SCII v.0.9b1
This commit is contained in:
parent
310f0dc8bd
commit
48b81d2c85
|
@ -0,0 +1,276 @@
|
|||
"""
|
||||
SCII - make ASCII RPG with multiple layered maps.
|
||||
Copyright (C) 2023 Mibi88
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see https://www.gnu.org/licenses/.
|
||||
"""
|
||||
|
||||
# e-mail : mbcontact50@gmail.com
|
||||
|
||||
#--- scii - make ASCII RPG with multiple layered maps ---
|
||||
|
||||
# Map drawing modes
|
||||
|
||||
STICKY = 0
|
||||
CENTERED = 1
|
||||
BLOCKS = 2
|
||||
STICKYBLOCKS = 3
|
||||
|
||||
class Scii:
|
||||
def __init__(self, world, player, on_npc_collision, scii_keys = None, get_input_text = None, no_collision = None, collision_checker = None,
|
||||
message_history_max = None, screen_width = 21, screen_height = 7):
|
||||
self.world = world
|
||||
self.player = player
|
||||
self.map_num = world["map_num"]
|
||||
self.screen_width = screen_width
|
||||
self.screen_height = screen_height-1
|
||||
self.screen_x_middle = self.screen_width//2
|
||||
self.screen_y_middle = self.screen_height//2
|
||||
self.screen_size = self.screen_width*self.screen_height
|
||||
self._vram = [' ' for i in range(self.screen_size)]
|
||||
self.on_char_handlers = {}
|
||||
if scii_keys: self.scii_keys = scii_keys
|
||||
else: self.scii_keys = {"left": '4', "right": '6', "up": '8', "down": '2', "quit": 'q', "old_messages": '0'}
|
||||
if get_input_text: self.get_input_text = get_input_text
|
||||
else: self.get_input_text = self._default_intext
|
||||
if collision_checker: self.collision_checker = collision_checker
|
||||
else: self.collision_checker = self._default_collision_check
|
||||
self.last_key = ""
|
||||
if not message_history_max: self.message_history_max = 20
|
||||
else: self.message_history_max = message_history_max
|
||||
self.old_messages = []
|
||||
self.on_npc_collision = on_npc_collision
|
||||
if no_collision: self.no_collision = no_collision
|
||||
else: self.no_collision = " ^"
|
||||
self.collision_npc = None
|
||||
def _default_collision_check(self, world, player, x, y):
|
||||
collision = 0
|
||||
for i in self.world["maps"][self.map_num]["layers"]:
|
||||
data = i["data"].split("\n")
|
||||
while("" in data): data.remove("")
|
||||
try:
|
||||
c = data[y][x]
|
||||
if c != i["transp_char"] and not (c in self.no_collision):
|
||||
return 1
|
||||
for npc in world["npc"]:
|
||||
if npc["map"] == self.map_num and npc["x"] == x and npc["y"] == y and npc["collision_check"]:
|
||||
self.collision_npc = npc
|
||||
return 2
|
||||
except:
|
||||
if x >= 0 and x < self.get_map_width() and y >= 0 and y < self.get_map_height(): return 0
|
||||
else: return 1
|
||||
return 0
|
||||
def _default_intext(self):
|
||||
return "> "
|
||||
def _input(self):
|
||||
i = input(self.get_input_text())
|
||||
if len(i) > 0:
|
||||
self.last_key = i[0]
|
||||
return self.last_key
|
||||
return self.last_key
|
||||
def _mainloop(self):
|
||||
key = ""
|
||||
while key != self.scii_keys["quit"]:
|
||||
self.draw_map(self.world["dmode"], self.player["isvisible"])
|
||||
key = self._input()
|
||||
nx = self.player["x"]
|
||||
ny = self.player["y"]
|
||||
if key == self.scii_keys["left"]: nx = self.player["x"]-1
|
||||
elif key == self.scii_keys["right"]: nx = self.player["x"]+1
|
||||
elif key == self.scii_keys["up"]: ny = self.player["y"]-1
|
||||
elif key == self.scii_keys["down"]: ny = self.player["y"]+1
|
||||
collision = self.collision_checker(self.world, self.player, nx, ny)
|
||||
if self.player["collision_check"] and not collision:
|
||||
self.player["x"] = nx
|
||||
self.player["y"] = ny
|
||||
elif collision == 2 and self.collision_npc != None:
|
||||
self.on_npc_collision(self, self.collision_npc)
|
||||
for jump in self.world["maps"][self.map_num]["jumps"]:
|
||||
if jump["isactive"] and self.player["x"] == jump["x"] and self.player["y"] == jump["y"]:
|
||||
self.player["x"] = jump["to_x"]
|
||||
self.player["y"] = jump["to_y"]
|
||||
self.map_num = jump["to_map"]
|
||||
self.world["map_num"] = self.map_num
|
||||
if key == self.scii_keys["old_messages"]: self.show_old_messages()
|
||||
def mainloop(self):
|
||||
try:
|
||||
self._mainloop()
|
||||
except Exception as e: print("Ow there was an error in SCII : {}".format(e))
|
||||
def _setc(self, x, y, c):
|
||||
if len(c) == 1 and x>=0 and x<self.screen_width and y>=0 and y<self.screen_height:
|
||||
self._vram[y*self.screen_width+x] = c
|
||||
def _dvram(self):
|
||||
for y in range(self.screen_height):
|
||||
for x in range(self.screen_width):
|
||||
print(self._vram[y*self.screen_width+x], end="")
|
||||
print()
|
||||
def _cvram(self):
|
||||
self._vram = [' ' for i in range(self.screen_size)]
|
||||
def get_map_width(self, map_data):
|
||||
max_len = 0
|
||||
for i in map_data["layers"]:
|
||||
for line in i["data"].split('\n'):
|
||||
if len(line)>max_len: max_len = len(line)
|
||||
return max_len
|
||||
def get_map_height(self, map_data):
|
||||
max_len = 0
|
||||
for i in map_data["layers"]:
|
||||
data = i["data"].split("\n")
|
||||
while("" in data): data.remove("")
|
||||
if len(data) > max_len:
|
||||
max_len = len(data)
|
||||
return max_len
|
||||
def draw_map(self, mode, show_player):
|
||||
map_data = self.world["maps"][self.map_num]
|
||||
osx = self.player["x"]
|
||||
osy = self.player["y"]
|
||||
sx = osx
|
||||
sy = osy
|
||||
if mode == STICKY:
|
||||
sx -= self.screen_x_middle
|
||||
sy -= self.screen_y_middle
|
||||
# Fix x
|
||||
if sx < 0:
|
||||
sx = 0
|
||||
elif sx + self.screen_width > self.get_map_width(map_data):
|
||||
sx = self.get_map_width(map_data) - self.screen_width
|
||||
px = osx - sx
|
||||
# Fix y
|
||||
if sy < 0:
|
||||
sy = 0
|
||||
elif sy + self.screen_height > self.get_map_height(map_data):
|
||||
sy = self.get_map_height(map_data) - self.screen_height
|
||||
py = osy - sy
|
||||
elif mode == CENTERED:
|
||||
px = self.screen_x_middle
|
||||
py = self.screen_y_middle
|
||||
sx -= self.screen_x_middle
|
||||
sy -= self.screen_y_middle
|
||||
elif mode == BLOCKS:
|
||||
sx = sx // self.screen_width * self.screen_width
|
||||
sy = sy // self.screen_height * self.screen_height
|
||||
px = osx-sx
|
||||
py = osy-sy
|
||||
elif mode == STICKYBLOCKS:
|
||||
sx = sx // self.screen_width * self.screen_width
|
||||
sy = sy // self.screen_height * self.screen_height
|
||||
if sx > self.get_map_width(map_data) - self.screen_width:
|
||||
sx = self.get_map_width(map_data) - self.screen_width
|
||||
if sy > self.get_map_height(map_data) - self.screen_height:
|
||||
sy = self.get_map_height(map_data) - self.screen_height
|
||||
px = osx-sx
|
||||
py = osy-sy
|
||||
self._cvram()
|
||||
layerc = 0
|
||||
for i in map_data["layers"]:
|
||||
data = i["data"].split("\n")
|
||||
while("" in data): data.remove("")
|
||||
map_width = self.get_map_width(map_data)
|
||||
map_height = self.get_map_height(map_data)
|
||||
for y in range(self.screen_height):
|
||||
for x in range(self.screen_width):
|
||||
try:
|
||||
if sx+x >= 0 and sx+x < map_width and sy+y >= 0 and sy+y < map_height:
|
||||
c = data[sy+y][sx+x]
|
||||
if c != i["transp_char"]:
|
||||
self._setc(x, y, c)
|
||||
except: pass
|
||||
for npc in self.world["npc"]:
|
||||
if npc["layer"] == layerc and npc["map"] == self.map_num and npc["isvisible"]:
|
||||
self._setc(px + (npc["x"] - osx), py + (npc["y"] - osy), npc["char"])
|
||||
if layerc == self.player["layer"]: self._setc(px, py, self.player["playerc"])
|
||||
layerc += 1
|
||||
self._dvram()
|
||||
def show_text(self, text):
|
||||
dwidth = self.screen_width - 2
|
||||
self._cvram()
|
||||
dtext = ""
|
||||
sz = 0
|
||||
y = 0
|
||||
for i in text.split(" "):
|
||||
if len(i) > dwidth:
|
||||
count = sz
|
||||
for c in i:
|
||||
dtext += c
|
||||
count += 1
|
||||
if count >= dwidth - 1:
|
||||
dtext += "-\n"
|
||||
count = 0
|
||||
y += 1
|
||||
dtext += ' '
|
||||
sz = count + 1
|
||||
elif sz + len(i) + 1 < dwidth:
|
||||
dtext += i + ' '
|
||||
sz += len(i) + 1
|
||||
y += i.count('\n')
|
||||
else:
|
||||
dtext += '\n' + i + ' '
|
||||
sz = len(i) + 1
|
||||
y += i.count('\n') + 1
|
||||
x = 0
|
||||
y = 0
|
||||
msg = ""
|
||||
for i in dtext:
|
||||
if i == '\n':
|
||||
y += 1
|
||||
x = 0
|
||||
if y >= self.screen_height:
|
||||
self._setc(self.screen_width - 1, self.screen_y_middle, '>')
|
||||
self._dvram()
|
||||
intxt = input("Continue > ")
|
||||
if len(intxt) > 0:
|
||||
if intxt[0] == self.scii_keys["quit"]: return
|
||||
y = 0
|
||||
x = 0
|
||||
self._add_message(msg)
|
||||
msg = ""
|
||||
self._cvram()
|
||||
else:
|
||||
self._setc(x, y, i)
|
||||
x += 1
|
||||
msg += i
|
||||
self._dvram()
|
||||
if msg != "": self._add_message(msg)
|
||||
input("End of the text > ")
|
||||
def _add_message(self, message):
|
||||
self.old_messages.append(message)
|
||||
while(len(self.old_messages) > self.message_history_max): del self.old_messages[0]
|
||||
def show_old_messages(self):
|
||||
if len(self.old_messages) < 1:
|
||||
self._cvram()
|
||||
x = 1
|
||||
for i in "No messages.":
|
||||
self._setc(x, self.screen_y_middle, i)
|
||||
x += 1
|
||||
self._dvram()
|
||||
input("Go back > ")
|
||||
c = len(self.old_messages)
|
||||
for i in [i for i in self.old_messages[::-1]]:
|
||||
self.show_text(i)
|
||||
c -= 1
|
||||
if c < 1: input("Go back > ")
|
||||
else: intxt = input("Next message > ")
|
||||
if len(intxt) > 0:
|
||||
if intxt[0] == 'q': return
|
||||
def ask_choice(self, text, choices):
|
||||
choice = 0
|
||||
while choice < 1 or choice > len(choices):
|
||||
newtext = text + "\n\n"
|
||||
c = 1
|
||||
for i in choices:
|
||||
newtext += "{} - {}\n".format(c, i)
|
||||
c += 1
|
||||
self.show_text(newtext)
|
||||
try:
|
||||
choice = int(input("Choice > "))
|
||||
except: choice = -1
|
||||
return choice
|
||||
#---
|
Loading…
Reference in New Issue