Compare commits

...

13 Commits

Author SHA1 Message Date
mibi88 3c8f8b69ef Small improvements at show_text, ask_choice and show_old_messages. 2023-01-08 18:48:59 +01:00
mibi88 fb88a41da6 Small fix 2023-01-08 16:40:32 +01:00
mibi88 2702a61839 Added map animations 2023-01-08 12:20:03 +01:00
mibi88 12ed26362c Fixed my fix LOL 2023-01-07 21:53:49 +01:00
mibi88 e275effb3a Bug fix 2023-01-07 21:48:44 +01:00
mibi88 70b115a737 Updated french docs 2023-01-07 20:11:29 +01:00
mibi88 ec509b1967 Add portaits for ask_choice 2023-01-07 20:08:02 +01:00
mibi88 692db46f7a Add portraits + small improvements 2023-01-07 20:05:11 +01:00
mibi88 0a0f87f543 Finished docss 2023-01-07 12:45:10 +01:00
mibi88 e1ebed2497 Small fix. 2023-01-07 11:37:39 +01:00
mibi88 4e766bf06b Finished documenting world and player 2023-01-07 11:27:45 +01:00
mibi88 96d6177674 Writing the french docs. 2023-01-07 00:39:11 +01:00
mibi88 59b69f8cc2 Started the french doc. 2023-01-07 00:18:51 +01:00
4 changed files with 551 additions and 283 deletions

196
DOCS_fr.md Normal file
View File

@ -0,0 +1,196 @@
# libSCII
Pour utiliser libSCII, il faut créer une nouvelle variable de la classe Scii :
## La classe `Scii`
```python
scii = Scii(world, player, npc_collision)
```
Voici les arguments qu'on peut donner à Scii :
```python
world, player, on_npc_collision, scii_keys = {"left": '4', "right": '6', "up": '8', "down": '2', "quit": 'q', "old_messages": '0'}, get_input_text = None, no_collision = " ^", collision_checker = None, message_history_max = 20, screen_width = 21, screen_height = 7, portrait_width = 7
```
* `world` va contenir les données du monde. Des explication plus précises sont plus bas.
* `player` va conten les données du joueur. Des explication plus précises sont plus bas.
* `on_npc_collision` doit être une fonction avec les arguments `self, npc` qui est exécutée lorsque le joueur va vers le pnj.
* `self` contient la classe `Scii` et permet d'y appeler des fonctions.
* `npc` contient les données du pnj, comme elles sont écrites dans `world` (voir plus bas).
* `scii_keys` contient les touches que le joueur utilise pour faire certaines action. Quand `scii_keys` est égal à `None`, les touches utilisés sont : `{"left": '4', "right": '6', "up": '8', "down": '2', "quit": 'q', "old_messages": '0'}`. `"old_messages"` permet de voir les anciennes conversations.
* `get_input_text` est une fonction qui doit retourner une chaine de caractères qui sera affichée dans l'input pour récupérer les touches.
* `no_collision` est une chaine de caractères qui contient les caractères que le joueur peut traverser. Par défaut, lorsque `no_collision` est égal à `None`, la chaine de caractères est `" ^"`.
* `collision_checker` est une fonction qui prend les paramètres `self, world, player, x, y` et qui retourne 0 si le joueur peut passer à (x, y), 1 si il ne peut pas passer à (x, y) et 2 si il y a un pnj à (x, y). `self` permet d'appeler des fonctions de la classe `Scii` ou à en récupérer des données et `world` et `player` contiennent les mêmes données que `world` et `player` qui sont des arguments de `Scii`.
* `message_history_max` contient le nombre de messages maximals qui seront conservés dans l'historique des conversations.
* `screen_width` est un `int` qui contient la largeur de l'écran en nombre de caractères.
* `screen_height` est un `int` qui contient la hauteur de l'écran en nombre de caractères.
* `portrait_width` la largeur des portraits qui peuvent s'afficher à côté du texte.
## `world`, le monde du jeu
`world` est un dictionnaire qui contiendra tout les éléments du monde du jeu.
### Un exemple de `world`
```python
map0 = """
########################################################
# ________ \|/ #
# | ) | _|_ #
# |_)____| \_/ ______ #
# ^ [==-==-] _ #
# <=> [-===-=] // #
# / \ [==-==-] <=// #
# | || #
########################################################
"""
animations = {
"replace_animations": {
'-': {
"frames": ['=', '-'],
"animation_frame": 0
},
'=': {
"frames": ['-', '='],
"animation_frame": 0
}
},
"coords_animations": {
"4, 4": {
"frames": ['^', ' '],
"animation_frame": 0
}
}
}
world = {
"dmode": STICKY,
"map_num": 0,
"maps": [
{
"layers": [
{
"data": map0,
"transp_char": None,
"animations": animations
}
],
"jumps": [
{
"x": 4,
"y": 4,
"to_x": 1,
"to_y": 1,
"to_map": 0,
"isactive": 1
}
]
}
],
"npc": [
{
"x": 35,
"y": 1,
"isvisible": 1,
"collision_check": 1,
"layer": 0,
"map": 0,
"char": '&',
"name": "massena"
},
{
"x": 35,
"y": 6,
"isvisible": 1,
"collision_check": 1,
"layer": 0,
"map": 0,
"char": '&',
"name": "lephenixnoir"
}
]
}
```
### Description
* `dmode` : La méthode d'affichage de la carte :
* `STICKY` : Le joueur est au milieu à part si il est trop proche du bord de la carte, il va donc se décentrer.
* `CENTERED` : Le joueur est toujours au centre (comme dans Asci).
* `BLOCKS` : La carte s'affiche par portions (un peu comme c'est parfois le cas dans Megaman sur la NES).
* `STICKYBLOCKS` : La carte s'affiche comme dans `BLOCKS`, mais elle remplit toujours l'écran.
* `map_num` : Le numéro de la carte sur laquelle on va démarrer le jeu.
* `maps` : Une liste de plusieurs cartes, chacune constituée de :
* `layers` : les différentes couches qui constituent les maps. Ces layers sont dessinés du premier au dernier.
* `data` : Une string qui contient le layer (`map0` dans l'exemple).
* `transp_char` : Le caractère qui ne sera pas affiché : permet de voir le layer d'en dessous. Si il est à `None`, aucun caractère ne sera enlevé.
* `animations` (**Optionnel**) : Dictionnaire qui permet d'ajouter des animations à la map constitué de :
* `replace_animations` : Dictionnaire pour les animations où un caractère est remplacé par un autre sur toute la map. Pour chaque caractère qui doit être animé, il faut y ajouter un autre dictionnaire où le nom est le caractère qui doit être animé. Ces dictionnaires sont constitués de :
* `frames` : Liste qui contient les différent caractères qui constituent l'animation.
* `animation_frame` : Quel caractère de l'animation va être affiché. C'est une position dans `frames`.
* `coords_animations` : Dictionnaire pour les animations où un caractère est remplacé par un autre uniquement à une position bien précise. Pour chaque position qui doit être animée, il faut y ajouter un autre dictionnaire où le nom est `"x, y"` où x doit être remplacé par l'abscisse et y par l'ordonnée du caractère qui doit être animé. Ces dictionnaires sont constitués de :
* `frames` : Liste qui contient les différent caractères qui constituent l'animation.
* `animation_frame` : Quel caractère de l'animation va être affiché. C'est une position dans `frames`.
* `jumps` : Liste des endroits où le joueur peut sauter d'une map à l'autre et/ou d'une position à l'autre. Cette liste est constituée de dictionnaires constituées de :
* `x` et `y` : La position de départ.
* `to_x` et `to_y` : La position de d'arrivée.
* `to_map` : La map de l'arrivée.
* `isactive` : Booléen : est ce que ce jump peut téléporter le joueur ?
* `npc` : Liste des pnj qui sont des dictionnaires constituée de :
* `x` et `y` : Leur position sur la map.
* `isvisible` : est ce qu'ils sont visibles.
* `collision_check` : Booléen : est ce qu'on peut entrer en collision avec eux.
* `layer` : Au dessus de quel layer ils s'affichent.
* `map` : Sur quelle map ils sont.
* `char` : Quel caractère est utilisé pour les afficher.
* `name` : Le nom du pnj, ce qui permet de l'identifier.
## `player`, le joueur
### Un exemple de `player`
```python
player = {
"x": 3,
"y": 4,
"isvisible": 1,
"collision_check": 1,
"layer": 0,
"playerc": '@'
}
```
### Description
* `x` et `y` : Sa position sur la map.
* `isvisible` : est ce qu'il est visible.
* `collision_check` : Booléen : est ce qu'il est stoppé par les objets durs et les pnj.
* `layer` : Au dessus de quel layer ils s'affiche.
La map sur laquelle il est est déjà définie dans `map_num` de `world`.
## Les fonctions de `Scii`
`self` est la classe `Scii`.
* `mainloop(self)` : Lance la boucle du jeu.
* Déjà utilisés dans mainloop :
* `get_map_width(self, map_data)` : Retourne la largeur de la map.
* `map_data` : dictionnaire de la map comme il est dans `world["maps"]`
* `get_map_height(self, map_data)` : Retourne la hauteur de la map.
* `map_data` : dictionnaire de la map comme il est dans `world["maps"]`
* `draw_map(self, mode, show_player)`
* `mode` : Mode de dessin de la map (`STICKY`, `CENTERED`, `BLOCKS` ou `STICKYBLOCKS`)
* `show_player` : Booléen : est ce que le joueur doit être affiché.
* `def show_text(self, text)` : Affiche du texte. L'historique du texte affiché est disponible en appuyant sur `scii_keys["old_messages"]` ou en appelant `show_old_messages(self)`.
* `text` : Texte à afficher.
* `portrait` (**Optionnel**) : Affiche un portrait à côté du texte.
* `show_old_messages(self)` : Affiche les anciennes conversations.
* `ask_choice(self, text, choices)` : Demande à l'utilisateur de faire un choix parmi les choix proposés dans `choices`. Retourne le choix fait. Le premier choix est le numéro 1, et les prochains sont à chaque fois de 1 plus grands : dans `["Oui", "Non", "Je ne sais pas"]` "Oui" est le choix numéro 1, "Non" est le choix numéro 2 et "Je ne sais pas" est le choix numéro 3.
* `text` : Texte à afficher avant de demander à l'utilisateur quel proposition il fait. Les choix seront affichés en dessous.
* `choices` : Liste de chaînes de caractères des choix que l'utilisateur.
* `portrait` (**Optionnel**) : Affiche un portrait à côté du texte.

View File

@ -1,276 +1,320 @@
"""
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
#---
"""
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 = {"left": '4', "right": '6', "up": '8', "down": '2', "quit": 'q', "old_messages": '0'}, get_input_text = None,
no_collision = " ^", collision_checker = None, message_history_max = 20, screen_width = 21, screen_height = 7, portrait_width = 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 = {}
self.scii_keys = scii_keys
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 = ""
self.message_history_max = message_history_max
self.old_messages = []
self.on_npc_collision = on_npc_collision
self.no_collision = no_collision
self.collision_npc = None
self.portrait_width = portrait_width
def _default_collision_check(self, world, player, x, y):
collision = 0
for i in 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(world["maps"][self.map_num]) and y >= 0 and y < self.get_map_height(world["maps"][self.map_num]): return 0
else: return 1
return 0
def _default_intext(self):
return "> "
def _input(self):
try: i = input(self.get_input_text())
except: i = input(self.get_input_text(self))
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)
if "animations" in i:
animations = 1
replace_animations = i["animations"]["replace_animations"]
coords_animations = i["animations"]["coords_animations"]
else:
animations = 0
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 animations:
if c in replace_animations:
c = replace_animations[c]["frames"][replace_animations[c]["animation_frame"]]
if "{}, {}".format(sx+x, sy+y) in coords_animations:
c = coords_animations["{}, {}".format(sx+x, sy+y)]["frames"][coords_animations["{}, {}".format(sx+x, sy+y)]["animation_frame"]]
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"] and show_player: self._setc(px, py, self.player["playerc"])
if animations:
for key in i["animations"]["replace_animations"]:
i["animations"]["replace_animations"][key]["animation_frame"] += 1
if i["animations"]["replace_animations"][key]["animation_frame"] >= len(i["animations"]["replace_animations"][key]["frames"]):
i["animations"]["replace_animations"][key]["animation_frame"] = 0
for key in i["animations"]["coords_animations"]:
i["animations"]["coords_animations"][key]["animation_frame"] += 1
if i["animations"]["coords_animations"][key]["animation_frame"] >= len(i["animations"]["coords_animations"][key]["frames"]):
i["animations"]["coords_animations"][key]["animation_frame"] = 0
layerc += 1
self._dvram()
def _show_text(self, text, portrait = None):
if portrait: dwidth = self.screen_width - (2 + self.portrait_width)
else: 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:
if portrait: self._draw_portrait(portrait)
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:
if portrait: self._setc(8 + x, y, i)
else: self._setc(x, y, i)
x += 1
msg += i
if portrait: self._draw_portrait(portrait)
self._dvram()
if msg != "": self._add_message(msg)
def show_text(self, text, portrait = None):
self._show_text(text, portrait)
input("End of the text > ")
def _draw_portrait(self, portrait):
for i in range(self.screen_height):
self._setc(1, i, '|')
self._setc(self.portrait_width, i, '|')
for i in range(self.portrait_width):
self._setc(1 + i, self.screen_height - 1, '-')
self._setc(1 + i, 0, '-')
self._setc(1, self.screen_height - 1, '+')
self._setc(self.portrait_width, self.screen_height - 1, '+')
self._setc(1, 0, '+')
self._setc(self.portrait_width, 0, '+')
portrait_data = portrait.split('\n')
while("" in portrait_data): portrait_data.remove("")
for y in range(1, self.screen_height - 1):
for x in range(2, self.portrait_width):
try: self._setc(x, y, portrait_data[y - 1][x - 2])
except: pass
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, portrait = None):
choice = 0
while choice < 1 or choice > len(choices):
newtext = text + "\n"
c = 1
for i in choices:
if c < len(choices): newtext += "{}:{}\n".format(c, i)
else: newtext += "{}:{}".format(c, i)
c += 1
self._show_text(newtext, portrait)
try:
choice = int(input("Choice > "))
except: choice = -1
self._add_message("You selected choice {}:{}".format(choice, choices[choice - 1]))
return choice
#---

View File

@ -12,16 +12,43 @@ map0 = """
########################################################
"""
portrait = """
___
/\\/\\\\
\\. ./
/ \\
"""
animations = {
"replace_animations": {
'-': {
"frames": ['=', '-'],
"animation_frame": 0
},
'=': {
"frames": ['-', '='],
"animation_frame": 0
}
},
"coords_animations": {
"4, 4": {
"frames": ['^', ' '],
"animation_frame": 0
}
}
}
def npc_collision(self, npc):
global portrait
if npc["name"] == "lephenixnoir":
self.show_text("""C'est moi, Lephe',
Je suis aussi dans le jeu !""")
Je suis aussi dans le jeu !""", portrait)
if npc["name"] == "massena":
txt = self.ask_choice("""T'as besoin d'aide pour des pixel arts ?""", ["Oui", "Non"])
txt = self.ask_choice("T'as besoin d'aide pour des pixel arts ?", ["Oui", "Non"])
if txt == 1:
self.show_text("""Merci !""")
self.show_text("Merci !")
else:
self.show_text("""Dommage""")
self.show_text("Dommage")
world = {
"dmode": STICKY,
@ -31,7 +58,8 @@ world = {
"layers": [
{
"data": map0,
"transp_char": None
"transp_char": None,
"animations": animations
}
],
"jumps": [

View File

@ -1,4 +1,4 @@
# ToDo
- [ ] Animated maps
- [ ] Bigger tiles than one char
* [x] Animated maps
- [ ] Bigger tiles than one char