1
0
Fork 0

Merge branch 'master' of gitea.planet-casio.com:Slyvtt/Collab_RPG

This commit is contained in:
mibi88 2023-08-23 19:49:39 +02:00
commit 1c5885ea32
38 changed files with 826 additions and 153 deletions

3
.gitignore vendored
View File

@ -13,4 +13,5 @@ __pycache__/
*.sublime-workspace
.vscode
*.json
level*.json
tilesetnpp.json

View File

@ -25,6 +25,7 @@ set(SOURCES
src/memory.c
src/game.c
src/dialogs.c
src/npc.c
# ...
)
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets

View File

@ -13,11 +13,13 @@ A ce stade, on a déjà implémenté :
- [x] Multiple cartes avec importation automatique des fichiers `world` issus de Tiled
- [x] Carte Multilayer (Background, Foreground + accessibilité / Dommages) avec transparence du calque Foreground
- [x] Personnage
- [x] Dialogues (sauts de lignes et mots plus grands que l'écran pas supportés)
- [ ] Fontes de caractères
- [ ] Interaction
- [x] Dialogues avec fichiers externes `json` et séquenceage possible de ceux-ci via un arbre d'histoire (sauts de lignes et mots plus grands que l'écran pas supportés)
- [x] Fontes de caractères
- [x] Interaction
- [ ] NPC
- [x] Changement de map durant le jeu
- [ ] Système d'événements
## Crédits

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
assets-cg/NPC_Icon_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 B

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,44 +1,18 @@
demo_player.png:
type: bopti-image
name: demo_player_img
*.png:
custom-type: custom-image
name_regex: (.*)\.png \1_img
profile: p8
scale: 2
demo_PNJ.png:
type: bopti-image
name: demo_PNJ_img
profile: p8
player_face.png:
type: bopti-image
name: player_face_img
profile: p8
SignAction.png:
type: bopti-image
name: SignAction_img
profile: p8
INFO_Icon.png:
type: bopti-image
name: INFO_Icon_img
profile: p8
NPC_Icon.png:
type: bopti-image
name: NPC_Icon_img
profile: p8
SGN_Icon.png:
type: bopti-image
name: SGN_Icon_img
profile: p8
demo_PNG.png:
scale: 1
font.png:
name: fontRPG
type: font
custom-type: font
charset: print
grid.size: 10x10
grid.padding: 2
grid.border: 0
proportional: true
height: 10
height: 10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 875 B

After

Width:  |  Height:  |  Size: 19 KiB

134
assets/DialogsLvl0.json Normal file
View File

@ -0,0 +1,134 @@
{ "dialogs":[
{ "ID":0,
"dialog":"Bienvenue a Toi, l'Ami, dans cette magnifique ville de Nabrouch. Comme tu peux le constater, les habitants ne sont pas tres nombreux et ont tendance a se terrer dans leur maison depuis la revolution. Il faut dire que les Anciens dirigeants, bien qu'exiles, exercent encore une certaine forme de pouvoir ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":1
},
{
"ID":1,
"dialog":"Depuis la mort de ton Pere, la region a bien change ... Enfin, surtout ses habitants. Tu devras te mefier de tout le monde.",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":2
},
{
"ID":2,
"dialog":"Tu devrais commencer par rejoindre la taverne que ton pere t'a laisse en heritage.",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":3,
"dialog":"Taverne de Pue Le Bouc",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":4,
"dialog":"Tiens !! Quelqu'un est mort ici. Tu le connais ?",
"isQuestion":1,
"choice":"Oui$Non",
"conclusion1":"C'est bien triste mon Ami.`$life-2``$power-5`",
"next1":-1,
"conclusion2":"Dommage quand meme pour Lui.",
"next2":-1,
"nextOther":-1
},
{
"ID":5,
"dialog":"Salut Hero !! Quel bon vent t'ammene ici a Nabrouch ?",
"isQuestion":1,
"choice":"De Passage$La Famille",
"conclusion1":"Entre donc te reposer dans la taverne, c'est la seule du coin.",
"next1":-1,
"conclusion2":"Fais bien attention alors.",
"next2":6,
"nextOther":-1
},
{
"ID":6,
"dialog":"On dit qu'il se passe des choses étranges par ici depuis quelques temps. Fais bien attention a Toi.",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":7,
"dialog":"Salut Hero, je suis le cremier. Veux tu me delester un peu ?",
"isQuestion":1,
"choice":"Oui$Non",
"conclusion1":"Voici donc pour toi`$life+5``$mana+5``$power+2`",
"next1":-1,
"conclusion2":"Bon bah casse toi ...",
"next2":-1,
"nextOther":-1
},
{
"ID":8,
"dialog":"Le Sanctuaire Maudit ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":9,
"dialog":"Etrange ce coffre abandonne et ouvert ... Fouiller dedans ?",
"isQuestion":1,
"choice":"Oui$Non",
"conclusion1":"Trop cool, du stuff `$life+5``$mana+5``$power+2`",
"next1":-1,
"conclusion2":"Je ferai mieux de partir loin ...",
"next2":-1,
"nextOther":-1
},
{
"ID":10,
"dialog":"Et sa tombe est en train d'etre creusee ?",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":11
},
{
"ID":11,
"dialog":"Beaucoup de morts pour une si petite bourgade ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
}
]
}

46
assets/DialogsLvl1.json Normal file
View File

@ -0,0 +1,46 @@
{ "dialogs":[
{ "ID":0,
"dialog":"Le tombeau du Chevalier Legendaire",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":3
},
{
"ID":1,
"dialog":"Salut, je suis le gardien du Tombeau. As-tu remarque quelque chose d'etrange en venant ici ?",
"isQuestion":1,
"choice":"Rien de special$Des pas dans les bois",
"conclusion1":"Ok, soit prudent tout de meme",
"next1":2,
"conclusion2":"Je vais finir mon tour de ronde et verifier",
"next2":2,
"nextOther":-1
},
{
"ID":2,
"dialog":"A bientot l'ami et prend garde aux brigands.",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":3,
"dialog":"Ce Hero de la Revolution a marque le pays de son Aura. Peut-etre aurais-je la meme destinee ... ",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
}
]
}

46
assets/DialogsLvl2.json Normal file
View File

@ -0,0 +1,46 @@
{ "dialogs":[
{ "ID":0,
"dialog":"Encore une tombe ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":1,
"dialog":"Un passage souterrain ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":2
},
{
"ID":2,
"dialog":"Je me demande bien ou il peut conduire. Une prochaine expedition a faire peut-etre ...",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
},
{
"ID":3,
"dialog":"C'est la maison du gardien du cimetiere",
"isQuestion":0,
"choice":"_",
"conclusion1":"_",
"next1":-1,
"conclusion2":"_",
"next2":-1,
"nextOther":-1
}
]
}

59
assets/DialogsLvl3.json Normal file
View File

@ -0,0 +1,59 @@
{
"dialogs": [
{
"ID": 0,
"dialog": "Maison du Fermier",
"isQuestion": 0,
"choice": "_",
"conclusion1": "_",
"next1": -1,
"conclusion2": "_",
"next2": -1,
"nextOther": -1
},
{
"ID": 1,
"dialog": "Maison du Marechal Ferrand",
"isQuestion": 0,
"choice": "_",
"conclusion1": "_",
"next1": -1,
"conclusion2": "_",
"next2": -1,
"nextOther": -1
},
{
"ID": 2,
"dialog": "Maison du Boucher",
"isQuestion": 0,
"choice": "_",
"conclusion1": "_",
"next1": -1,
"conclusion2": "_",
"next2": -1,
"nextOther": -1
},
{
"ID": 3,
"dialog": "Maison du Boulanger",
"isQuestion": 0,
"choice": "_",
"conclusion1": "_",
"next1": -1,
"conclusion2": "_",
"next2": -1,
"nextOther": -1
},
{
"ID": 4,
"dialog": "Maison du Maire",
"isQuestion": 0,
"choice": "_",
"conclusion1": "_",
"next1": -1,
"conclusion2": "_",
"next2": -1,
"nextOther": -1
}
]
}

View File

@ -1,18 +1,29 @@
from random import randint
from PIL import Image
import fxconv
import json
import pathlib
import csv
import os
def convert(input, output, params, target):
if params["custom-type"] == "map":
#convert_map(input, output, params, target)
#return 0
print("ERROR : Asset ", params["name"], " has legacy type map")
return 1
elif params["custom-type"] == "world":
convert_world(input, output, params, target)
return 0
elif params["custom-type"] == "custom-image":
convert_custom_image(input, output, params, target)
return 0
elif params["custom-type"] == "font":
convert_font(input, output, params, target)
return 0
elif params["custom-type"] == "dialogs":
print("ERROR : Asset ", params["name"], " has legacy type dialog")
#convert_dialogs(input, output, params, target)
return 0
else:
return 1
@ -62,20 +73,8 @@ def convert_world(input, output, params, target):
print( "Map = ", map )
structWorld += fxconv.ptr( map )
#ext = get_extra_map_data( mapPath, output, params, target, xmin, ymin, xmax, ymax )
#print( "Data = ", ext )
#if (ext!=fxconv.u32(0)): structExtra += fxconv.ptr( ext )
structWorld += fxconv.u32(0)
#structExtra += fxconv.u32(0)
"""
#and all the extra data (PNJ, SGN, ...)
fxconv.elf_multi(
[("_" + params["varMapData"], structWorld),
("_" + params["varExtraData"], structExtra)],
output, **target)
"""
#generate !
fxconv.elf(structWorld, output, "_" + params["name"], **target)
@ -123,10 +122,10 @@ def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
#create the structure of the map
structMap = fxconv.Structure()
structMap += fxconv.u16(w) + fxconv.u16(h) + fxconv.u16(nbTilelayer)
structMap += fxconv.u16(tileset_size)
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer)
structMap += fxconv.u32(tileset_size)
structMap += fxconv.u16(xmin) + fxconv.u16(ymin) + fxconv.u16(xmax) + fxconv.u16(ymax)
structMap += fxconv.u32(xmin) + fxconv.u32(ymin) + fxconv.u32(xmax) + fxconv.u32(ymax)
structMap += fxconv.ref(f"img_{nameTilesetFree}")
@ -150,6 +149,8 @@ def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
structMap += fxconv.ptr(walk_data)
nbextra = 0
extradata = fxconv.Structure()
@ -163,6 +164,26 @@ def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
structMap += fxconv.ptr( extradata )
nameDialog = data["properties"][0]["value"]
dialogfile = "/".join(input.split("/")[:-nbRetour]) + "/" + nameDialog
print( "THE DIALOGS ARE CONTAINED IN THE FILE : ", dialogfile )
nbdiag = 0
diagdata = fxconv.Structure()
nbdiag, diagdata = convert_dialogs(dialogfile, output, params, target)
if (nbdiag==0):
structMap += fxconv.u32( 0 )
structMap += fxconv.u32( 0 )
else:
structMap += fxconv.u32( int(nbdiag) )
structMap += fxconv.ptr( diagdata )
#extraction of the data contained in the layer "Background" and "Foreground" of the map
@ -208,8 +229,7 @@ def get_tile_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
def get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
print( "WE ARE COMPUTING THE EXTRA DATA OF THE MAP : ", input )
data = json.load(open(input, "r"))
nblayer = ["id" in i for i in data["layers"]].count(True) - 1
print( "I found ", nblayer, " of extradata")
@ -230,24 +250,156 @@ def get_extra_map_data(input, output, params, target, xmin, ymin, xmax, ymax):
#create the structure of the map
structData = fxconv.Structure()
nbExtraData = 0
layer = data["layers"][layer_extradata]
for i in layer["objects"]:
nbExtraData = nbExtraData + 1
x = i["x"] + xmin
y = i["y"] + ymin
nme = i["name"]
#get the type of the item
tpe = i["type"]
for j in i["properties"]:
stg = j[ "value" ]
print( "OBJECT X= ", x, " Y= ", y, "STR= ", stg )
#we check if the type corresponds to a items of type Point in Tiled
if tpe in ( "SGN", "NPC", "INFO" ):
nbExtraData = nbExtraData + 1
x = i["x"] + xmin
y = i["y"] + ymin
nme = i["name"]
dialogID = None
needAction = None
path = 0
path_length = 0
xdata = None
ydata = None
#we now fill all the properties of this item
for j in i["properties"]:
#property "dialog"
if j["name"]=="dialogID": dialogID = j[ "value" ]
#property "isQuestion"
elif j["name"]=="needAction": needAction = j[ "value" ]
else:
#Extra properties for NPCs (path)
if tpe=="NPC":
if j["name"]=="hasPath":
pathID = None
path = j[ "value" ]
if path==1:
print( "PNJ has path - NOW LOOKING FOR RELEVANT DATA" )
# we start looking for path data with first the ID of the path Object
for u in i["properties"]:
if u["name"]=="path":
pathID = u[ "value" ]
print( "path ID is identified : ID= ", pathID )
for v in layer["objects"]:
if v[ "id" ] == pathID:
print( "path data found : " )
xdata = bytes()
ydata = bytes()
for w in v[ "polyline" ]:
path_length = path_length + 1
print( "X= ", w[ "x" ], " Y= ", w[ "y" ] )
xdata += fxconv.u16( int( w[ "x" ] ) )
ydata += fxconv.u16( int( w[ "y" ] ) )
else:
print( "PNJ has no Path" )
else:
print( "UNIDENTIFIED PROPERTY : ", j["name"])
print( "OBJECT X= ", x, " Y= ", y, "STR= ", dialogID )
print( " Type= ", tpe, " Name= ", nme )
structData += fxconv.u16( int(x) )
structData += fxconv.u16( int(y) )
structData += fxconv.string( nme )
structData += fxconv.string( tpe )
structData += fxconv.string( stg )
print( " Action?= ", needAction )
structData += fxconv.u32( int(x) )
structData += fxconv.u32( int(y) )
structData += fxconv.string( nme )
structData += fxconv.string( tpe )
structData += fxconv.u32( int(dialogID) )
structData += fxconv.u32( int(needAction) )
if path==0:
structData += fxconv.u32(0)
structData += fxconv.u32(0)
structData += fxconv.u32(0)
structData += fxconv.u32(0)
else:
o_xdata = fxconv.Structure()
o_xdata += xdata
o_ydata = fxconv.Structure()
o_ydata += ydata
structData += fxconv.u32(path)
structData += fxconv.u32(path_length)
structData += fxconv.ptr(o_xdata)
structData += fxconv.ptr(o_ydata)
#else we do nothing (yet)
else:
print( "Skip this object" )
return nbExtraData, structData
def convert_custom_image(input, output, params, target):
scale = int(params.get("scale", 1))
# Upscale image before converting
im = Image.open(input)
im = im.resize((im.width * scale, im.height * scale),
resample=Image.NEAREST)
o = fxconv.convert_image_cg(im, params)
fxconv.elf(o, output, "_" + params["name"], **target)
def convert_font(input, output, params, target):
o = fxconv.convert_topti(input, params)
fxconv.elf(o, output, "_" + params["name"], **target)
def convert_dialogs(input, output, params, target):
print( "WE ARE COMPUTING THE DIALOGS FROM : ", input )
data = json.load(open(input, "r"))
structDialogs = fxconv.Structure()
nbdialogs = 0
for d in data["dialogs"]:
print( int(d[ "ID" ]))
# print( d[ "dialog" ] )
print( int(d[ "isQuestion" ]) )
# print( d[ "choice" ].replace('$', chr(0)) )
# print( d[ "conclusion1" ] )
# print( int(d[ "next1" ] ) )
# print( d[ "conclusion2" ] )
# print( int(d[ "next2" ] ) )
# print( int(d[ "nextOther" ]) )
nbdialogs = nbdialogs + 1
structDialogs += fxconv.u32( int(d[ "ID" ] ) )
structDialogs += fxconv.string( d[ "dialog" ] )
structDialogs += fxconv.u32( int(d[ "isQuestion" ] ) )
structDialogs += fxconv.string( d[ "choice" ].replace('$', chr(0)) )
structDialogs += fxconv.string( d[ "conclusion1" ] )
structDialogs += fxconv.u32( int(d[ "next1" ] ) )
structDialogs += fxconv.string( d[ "conclusion2" ] )
structDialogs += fxconv.u32( int(d[ "next2" ] ) )
structDialogs += fxconv.u32( int(d[ "nextOther" ] ) )
return nbdialogs, structDialogs
#fxconv.elf(structDialogs, output, "_" + params["name"], **target)

View File

@ -1,11 +1,7 @@
# *.json:
# custom-type: map
# name_regex: (.*)\.json map_\1
WorldRPG.world:
custom-type: world
#name: xxx #unused but mandatory (Do not touch)
#varMapData: worldRPG
#varExtraData: extraRPG
name: worldRPG
#DialogsRPG.json:
# custom-type: dialogs
# name: dialogRPG

View File

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="8" nextobjectid="9">
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="8" nextobjectid="12">
<editorsettings>
<export target="level0.json" format="json"/>
</editorsettings>
<properties>
<property name="dialogFile" type="file" value="DialogsLvl0.json"/>
</properties>
<tileset firstgid="1" source="tilesetnpp.tsx"/>
<tileset firstgid="409" source="Walkable.tsx"/>
<layer id="1" name="Background" width="48" height="24">
@ -92,37 +95,64 @@
<objectgroup id="4" name="ExtraData">
<object id="1" name="INFO3" type="INFO" x="232" y="79.75">
<properties>
<property name="dialog" value="Etrange ce coffre ouvert ..."/>
<property name="dialogID" type="int" value="9"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="8" name="INFO2" type="INFO" x="119.75" y="47.25">
<properties>
<property name="dialog" value="Et sa tombe est en train d'etre creusee ...^"/>
<property name="dialogID" type="int" value="10"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="7" name="INFO2" type="INFO" x="52" y="44">
<object id="7" name="INFO1" type="INFO" x="52" y="44">
<properties>
<property name="dialog" value="Quelqu'un est mort ici ..."/>
<property name="dialogID" type="int" value="4"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="2" name="PNJ1" type="NPC" x="252" y="164">
<object id="2" name="PNJ2" type="NPC" x="164" y="132">
<properties>
<property name="dialog" value="Salut, je suis un PNJ"/>
<property name="dialogID" type="int" value="5"/>
<property name="hasPath" type="int" value="0"/>
<property name="needAction" type="int" value="1"/>
<property name="path" type="object" value="0"/>
</properties>
<point/>
</object>
<object id="10" name="PNJ1" type="NPC" x="252" y="164">
<properties>
<property name="dialogID" type="int" value="7"/>
<property name="hasPath" type="int" value="1"/>
<property name="needAction" type="int" value="1"/>
<property name="path" type="object" value="9"/>
</properties>
<point/>
</object>
<object id="4" name="SGN1" type="SGN" x="96" y="136">
<properties>
<property name="dialog" value="Indication sur le panneau. Bienvenue dans la maison du Tondu ..."/>
<property name="dialogID" type="int" value="3"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="5" name="SGN2" type="SGN" x="288" y="128">
<properties>
<property name="dialog" value="Indication sur le panneau. Entree dans le Sanctuaire Maudit ..."/>
<property name="dialogID" type="int" value="8"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="9" name="Chemin Crémier" type="TRJ" x="251.967" y="164.12">
<polyline points="0,0 -72.25,-18.5 -171.75,-19 -172.5,-99.25 -206.25,-122.75 -140.75,-114.75 -175.25,-97.5 -174.5,-33 -148.25,-20.5 -73.25,-20.25 39,-30.25 81.25,-45 79.25,-24.5"/>
</object>
<object id="11" name="DébutHistoire" type="INFO" x="18.6666" y="42.6667">
<properties>
<property name="dialogID" type="int" value="0"/>
<property name="needAction" type="int" value="0"/>
</properties>
<point/>
</object>

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="5" nextobjectid="2">
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="5" nextobjectid="4">
<properties>
<property name="dialogFile" type="file" value="DialogsLvl1.json"/>
</properties>
<tileset firstgid="1" source="tilesetnpp.tsx"/>
<tileset firstgid="409" source="Walkable.tsx"/>
<layer id="1" name="Background" width="48" height="24">
@ -89,9 +92,26 @@
<objectgroup id="4" name="ExtraData">
<object id="1" name="INFO1" type="INFO" x="303.75" y="143.25">
<properties>
<property name="dialog" value="Le tombeau du Chevalier Legendaire"/>
<property name="dialogID" type="int" value="0"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="2" name="Gardien" type="NPC" x="303.636" y="117.273">
<properties>
<property name="dialogID" type="int" value="1"/>
<property name="hasPath" type="int" value="1"/>
<property name="needAction" type="int" value="1"/>
<property name="path" type="object" value="3"/>
</properties>
<point/>
</object>
<object id="3" name="Chemin Gardien" x="303.818" y="117.455">
<properties>
<property name="dialogID" type="int" value="0"/>
<property name="needAction" type="int" value="1"/>
</properties>
<polyline points="0,0 -31.2727,-11.0909 -87.2727,-16.1818 -100.909,-6.72727 -100.182,28.9091 -72.3636,32.7273 -11.4546,37.8181 42.5455,42.5454 75.4546,22.9091 77.4545,1.45453 32.3636,-0.727273"/>
</object>
</objectgroup>
</map>

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="5" nextobjectid="5">
<properties>
<property name="dialogFile" type="file" value="DialogsLvl2.json"/>
</properties>
<tileset firstgid="1" source="tilesetnpp.tsx"/>
<tileset firstgid="409" source="Walkable.tsx"/>
<layer id="1" name="Background" width="48" height="24">
@ -89,19 +92,22 @@
<objectgroup id="4" name="ExtraData">
<object id="1" name="INFO1" type="INFO" x="128" y="87.5">
<properties>
<property name="dialog" value="Encore une tombe ..."/>
<property name="dialogID" type="int" value="0"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="2" name="INFO2" type="INFO" x="262.75" y="49">
<properties>
<property name="dialog" value="Un passage souterrain ..."/>
<property name="dialogID" type="int" value="1"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="3" name="SGN1" type="SGN" x="296" y="143.75">
<properties>
<property name="dialog" value="C'est la maison du gardien du cimetiere"/>
<property name="dialogID" type="int" value="3"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="right-down" width="48" height="24" tilewidth="8" tileheight="8" infinite="0" nextlayerid="5" nextobjectid="6">
<properties>
<property name="dialogFile" type="file" value="DialogsLvl3.json"/>
</properties>
<tileset firstgid="1" source="tilesetnpp.tsx"/>
<tileset firstgid="409" source="Walkable.tsx"/>
<layer id="1" name="Background" width="48" height="24">
@ -13,21 +16,21 @@
325,313,290,265,313,265,241,290,313,314,290,241,313,290,325,2,330,331,332,333,333,333,333,333,334,335,336,132,2,2,2,2,2,2,2,86,87,88,186,187,188,189,90,91,92,132,2,2,
349,2,2,2,2,2,2,2,2,2,2,2,2,2,349,2,162,163,164,162,163,164,165,162,163,164,165,132,2,297,298,299,300,2,2,110,111,112,210,211,212,213,114,115,116,133,2,2,
387,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,86,87,88,186,187,188,189,86,87,88,92,132,2,2,2,2,2,385,2,2,2,2,2,265,266,2,2,2,2,2,2,2,
2,2,258,259,260,261,261,262,263,264,2,21,22,23,24,2,110,111,112,210,211,212,213,110,111,112,116,133,386,241,241,313,241,313,266,265,266,266,265,289,290,2,160,161,385,2,2,387,
2,2,282,283,284,285,285,286,287,288,2,45,46,47,48,2,2,2,2,2,265,266,2,2,2,2,2,313,290,265,313,265,313,266,290,289,290,265,266,313,314,2,2,2,2,2,2,2,
2,2,306,307,308,309,309,310,311,312,131,69,70,71,72,2,266,265,266,266,265,386,160,161,2,386,2,265,265,266,241,2,258,259,260,261,261,262,263,264,2,2,2,2,2,2,2,2,
2,2,258,259,260,261,261,262,263,264,2,21,22,23,24,2,110,111,112,210,211,212,213,110,111,112,116,133,2,241,241,313,241,313,266,265,266,266,265,289,290,2,160,161,385,2,2,387,
2,2,282,283,284,285,285,286,287,288,2,45,46,47,48,2,2,2,2,2,265,266,2,2,2,2,2,2,2,265,313,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,306,307,308,309,309,310,311,312,131,69,70,71,72,2,2,2,2,2,265,386,160,161,2,386,2,2,2,266,241,2,258,259,260,261,261,262,263,264,2,2,2,2,2,2,2,2,
386,2,330,331,332,333,333,334,335,336,132,2,2,2,2,266,290,289,290,265,266,290,266,265,266,266,265,289,289,290,386,2,282,283,284,285,285,286,287,288,2,2,2,2,2,2,2,2,
2,2,162,163,165,162,163,163,165,165,132,2,313,290,265,313,265,2,2,2,2,2,290,289,290,265,266,313,313,314,241,2,306,307,308,309,309,310,311,312,131,2,2,2,2,2,2,2,
2,2,86,87,88,186,187,188,189,92,132,2,265,266,266,2,258,259,260,261,261,261,261,261,261,262,263,264,2,265,266,2,330,331,332,333,333,334,335,336,132,2,2,2,2,2,2,2,
2,2,110,111,112,210,211,212,213,116,133,2,289,290,2,2,282,283,284,285,285,285,285,285,285,286,287,288,2,289,290,2,162,163,164,162,163,164,165,165,132,2,2,297,298,299,300,2,
2,2,2,2,2,2,265,266,2,2,2,386,313,314,2,2,306,307,308,309,309,309,309,309,309,310,311,312,131,241,265,2,86,87,88,186,187,188,189,92,132,2,2,2,2,2,2,2,
2,2,2,386,2,2,289,290,160,161,2,2,265,266,2,2,330,331,332,333,333,333,333,333,333,334,335,336,132,266,266,2,110,111,112,210,211,212,213,116,133,2,2,2,2,2,386,2,
2,2,2,2,2,2,313,314,289,265,266,290,289,290,2,2,162,163,164,165,162,163,164,162,163,163,165,165,132,265,266,241,2,2,2,2,265,266,2,2,2,2,2,2,2,2,386,2,
265,266,266,265,386,313,265,266,265,266,313,314,313,314,266,2,86,87,88,90,90,87,88,186,187,188,189,92,132,289,289,290,266,265,266,266,289,290,2,160,161,2,21,22,23,24,2,2,
289,290,265,266,290,2,2,2,2,2,2,2,266,265,266,2,110,111,112,114,114,111,112,210,211,212,213,116,133,241,313,314,290,289,290,265,313,314,2,386,2,2,45,46,47,48,2,2,
2,2,162,163,165,162,163,163,165,165,132,2,2,290,265,313,2,2,2,2,2,2,2,2,2,2,2,2,2,314,241,2,306,307,308,309,309,310,311,312,131,2,2,2,2,2,2,2,
2,2,86,87,88,186,187,188,189,92,132,2,2,266,266,2,258,259,260,261,261,261,261,261,261,262,263,264,2,265,266,2,330,331,332,333,333,334,335,336,132,2,2,2,2,2,2,2,
2,2,110,111,112,210,211,212,213,116,133,2,2,290,2,2,282,283,284,285,285,285,285,285,285,286,287,288,2,289,290,2,162,163,164,162,163,164,165,165,132,2,2,297,298,299,300,2,
2,2,2,2,2,2,265,266,2,2,2,386,2,314,2,2,306,307,308,309,309,309,309,309,309,310,311,312,131,241,265,2,86,87,88,186,187,188,189,92,132,2,2,2,2,2,2,2,
2,2,2,386,2,2,289,290,160,161,2,2,2,266,2,2,330,331,332,333,333,333,333,333,333,334,335,336,132,266,266,2,110,111,112,210,211,212,213,116,133,2,2,2,2,2,386,2,
2,2,2,2,2,2,313,314,2,2,2,2,2,290,2,2,162,163,164,165,162,163,164,162,163,163,165,165,132,265,266,241,2,2,2,2,265,266,2,2,2,2,2,2,2,2,386,2,
265,266,266,265,386,313,265,266,265,266,313,314,313,314,2,2,86,87,88,90,90,87,88,186,187,188,189,92,132,289,289,290,266,265,266,266,289,290,2,160,161,2,21,22,23,24,2,2,
289,290,265,266,290,2,2,2,2,2,2,2,2,265,266,2,110,111,112,114,114,111,112,210,211,212,213,116,133,2,2,2,2,2,2,2,2,2,2,386,2,2,45,46,47,48,2,2,
2,2,2,2,2,2,2,2,2,386,2,2,2,265,266,2,2,2,2,2,2,2,2,2,265,266,2,2,2,2,345,346,347,348,2,339,340,2,2,2,2,2,69,70,71,72,2,2,
2,297,298,299,300,2,2,339,340,2,2,2,2,289,290,266,265,266,266,265,386,265,266,266,289,290,2,160,161,2,369,370,371,372,2,363,364,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,386,2,2,363,364,2,2,2,2,313,314,290,289,290,265,266,290,289,290,265,313,314,2,2,385,2,393,394,395,396,2,2,2,2,2,2,2,387,2,2,2,386,2,2
2,2,2,2,386,2,2,363,364,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,385,2,393,394,395,396,2,2,2,2,2,2,2,387,2,2,2,386,2,2
</data>
</layer>
<layer id="2" name="Foreground" width="48" height="24">
@ -89,31 +92,36 @@
<objectgroup id="4" name="ExtraData">
<object id="1" name="SGN5" type="SGN" x="224" y="183.25">
<properties>
<property name="dialog" value="Maison du Maire"/>
<property name="dialogID" type="int" value="4"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="5" name="SGN4" type="SGN" x="320.5" y="159.25">
<properties>
<property name="dialog" value="Maison du Boulanger"/>
<property name="dialogID" type="int" value="3"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="3" name="SGN3" type="SGN" x="184.25" y="95.75">
<properties>
<property name="dialog" value="Maison du Boucher"/>
<property name="dialogID" type="int" value="2"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="4" name="SGN2" type="SGN" x="343.75" y="80">
<properties>
<property name="dialog" value="Maison du Marechal Ferrand"/>
<property name="dialogID" type="int" value="1"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>
<object id="2" name="SGN1" type="SGN" x="71.75" y="143.25">
<properties>
<property name="dialog" value="Maison du Fermier"/>
<property name="dialogID" type="int" value="0"/>
<property name="needAction" type="int" value="1"/>
</properties>
<point/>
</object>

3
clean
View File

@ -1,5 +1,6 @@
cd assets
rm -f *.json
rm -f level*.json
rm -f tilesetnpp.json
rm -r __pycache__
cd ..
rm -r build-cg

View File

@ -8,7 +8,7 @@
#define USB_FEATURE 0
#define DEBUGMODE 1
#define DEBUGMODE 0
#ifdef FXCG50
#define T_HEIGHT 16

View File

@ -6,10 +6,15 @@
#include <string.h>
#include "config.h"
#include "game.h"
#define BOX_HEIGHT (F_HEIGHT/PXSIZE+8)
#define CHOICE_BOX_HEIGHT 10
#define CHOICE_BOX_PADDING_TOP 3
extern font_t fontRPG;
#define FONT_USED fontRPG
@ -19,6 +24,14 @@ extern font_t fontRPG;
uint32_t *lightVRAMcurrent, *darkVRAMcurrent;
#endif //GRAYMODEOK
/* the color of the text to go to the next dialog phase */
/* it improves readability to have somathing lighter */
#if GRAYMODEOK || (defined(FXCG50) && !defined(COLOR1BIT))
#define NEXT_COLOR C_DARK
#else
#define NEXT_COLOR C_BLACK
#endif
void blit()
{
@ -125,15 +138,15 @@ int showtext_opt(Game *game, bopti_image_t *face, char *text,
if(update_screen) blit();
while(game->frame_duration < line_duration) sleep();
game->frame_duration = 0;
/* Ask the user to press EXE to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, C_BLACK, "[EXE] to continue ...");
/* Ask the user to press SHIFT to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite...");
}
/* Make a little animation :). */
if(update_screen) blit();
if(l>=max_lines_amount-1){
/* If we drew one entire screen. */
/* Wait that the EXE key is pressed if we should. */
if(wait_continue) while(getkey().key != KEY_EXE) sleep();
/* Wait that the SHIFT key is pressed if we should. */
if(wait_continue) while(getkey_opt(GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT) sleep();
/* Clear the text area. */
drect(BOX_HEIGHT*PXSIZE, 0, DWIDTH, (BOX_HEIGHT-1)*PXSIZE-2,
C_WHITE);
@ -153,11 +166,11 @@ int showtext_opt(Game *game, bopti_image_t *face, char *text,
if(update_screen) blit();
while(game->frame_duration < line_duration) sleep();
game->frame_duration = 0;
/* Ask the user to press EXE to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, C_BLACK, "[EXE] to continue ...");
/* Update the screen and wait for EXE being pressed, if needed. */
/* Ask the user to press SHIFT to continue. */
dtext(BOX_HEIGHT*PXSIZE, y, NEXT_COLOR, "[SHIFT] : suite...");
/* Update the screen and wait for SHIFT being pressed, if needed. */
if(update_screen) blit();
if(wait_continue) while(getkey().key != KEY_EXE) sleep();
if(wait_continue) while(getkey_opt( GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key != KEY_SHIFT) sleep();
}
if(call_before_end) return_int = call_before_end(game, i);
if(end_anim){
@ -187,8 +200,6 @@ void showtext_dialog(Game *game, bopti_image_t *face, char *text,
true, 0, true);
}
#define CHOICE_BOX_HEIGHT 10
#define CHOICE_BOX_PADDING_TOP 3
/* Some variables and pointers used to get some arguments passed in
* showtext_dialog_ask in _choice_call_before_end. */
@ -253,7 +264,7 @@ int _choice_call_before_end(Game *game, unsigned int org_i) {
C_BLACK, ">");
}
blit();
key = getkey().key;
key = getkey_opt( GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA, NULL).key;
/* If the player pressed the left arrow key and has not already selected
* the first possible choice. */
if(key == KEY_LEFT && selected > 0){
@ -280,9 +291,9 @@ int _choice_call_before_end(Game *game, unsigned int org_i) {
/* Move the selection arrow and update the selected item. */
selected++;
}
/* If the user has not validated his choice by pressing EXE, we loop one
/* If the user has not validated his choice by pressing SHIFT, we loop one
* more time. */
}while(key != KEY_EXE);
}while(key != KEY_SHIFT);
/* Make a little animation because we looove little animations ;) */
for(i=DWIDTH/8+1;i>0;i--){
/* I'm drawing the same box as on the start animation */
@ -319,3 +330,47 @@ int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start,
return showtext_opt(game, face, text, _choice_call_before_end, start, end,
_choice_screen_call, 100, true, 0, true);
}
void initiate_dialog_sequence(Game *game, bopti_image_t *face, uint32_t dialogNumber )
{
Dialog *currentDiag = &game->map_level->dialogs[ dialogNumber ];
/* we collect the information */
char *text = currentDiag->dialog;
char *choices = currentDiag->choices ;
char *conclusion1 = currentDiag->conclusion1;
int next1 = currentDiag->next1;
char *conclusion2 = currentDiag->conclusion2;
int next2 = currentDiag->next2;
int nextOther = currentDiag->nextOther;
int isQuestion = currentDiag->isQuestion;
/* we treat the action - i.e. we show a dialog */
if (isQuestion == 1) /* we have to manage a question */
{
int answer = showtext_dialog_ask( game, face, text, true, true, choices, 2, 0 );
/* TO DO we need to split the strings conclusion1 and conclusion2 */
/* to extract the "gift" part */
if (answer==0)
{
showtext_dialog( game, face, conclusion1, true, true );
if (next1!=-1) initiate_dialog_sequence( game, face, next1 );
}
else
{
showtext_dialog( game, face, conclusion2, true, true );
if (next2!=-1) initiate_dialog_sequence( game, face, next2 );
}
}
else
{
showtext_dialog( game, face, text, true, true );
if (nextOther!=-1) initiate_dialog_sequence( game, face, nextOther );
}
}

View File

@ -89,4 +89,6 @@ int showtext_dialog_ask(Game *game, bopti_image_t *face, char *text, bool start,
bool end, char *choices, int choices_amount,
int default_choice);
void initiate_dialog_sequence(Game *game, bopti_image_t *face, uint32_t dialogNumber );
#endif

View File

@ -8,10 +8,13 @@
#include <gint/cpu.h>
#include <gint/display.h>
#include "npc.h"
#include "stdlib.h"
extern bopti_image_t SignAction_img;
extern Dialog *dialogRPG;
#define MAX_INTERACTION_DISTANCE 12
@ -58,6 +61,7 @@ void render_indicator(Game *game)
void draw(Game *game) {
/* Draw everything. */
render_map_by_layer(game, BACKGROUND);
npc_draw( game );
player_draw(game);
render_map_by_layer(game, FOREGROUND);
render_indicator( game );

View File

@ -42,33 +42,63 @@ typedef struct {
} Player;
typedef struct {
uint32_t ID;
/* data to be shown in the dialog*/
char *dialog;
/* is it a question or a simple dialog ? */
uint32_t isQuestion;
/* if it is a question, then the choices for answering */
char *choices;
/* the conclusion of the dialog for answer 1 and 2 respectively */
/* Note : it may contain a set of event with a dedicated syntax */
char *conclusion1;
int32_t next1;
char *conclusion2;
int32_t next2;
int32_t nextOther;
} Dialog;
typedef struct {
/* position of the item */
uint16_t x;
uint16_t y;
uint32_t x;
uint32_t y;
/* its name */
char *name;
/* its class (NPC, SGN, INFO, ... )*/
char *type;
/* data to be shown in the dialog*/
char *dialog;
/* the ID of the first element of the dialog */
/* (to be aligned with "dialogs.json" IDs)*/
uint32_t dialogID;
/* 0 if imperative dialog (story mode) */
/* or 1 if the player need to press [SHIFT] to initiate the sequence*/
uint32_t needAction;
/* data for NPC's trajectories */
uint32_t hasPath;
uint32_t path_length;
uint16_t *xpath;
uint16_t *ypath;
/* ... this can be extended as per needs ... */
} ExtraData;
typedef struct {
/* width, height and the number of layer of the map */
uint16_t w;
uint16_t h;
uint16_t nblayers;
uint16_t tileset_size;
uint32_t w;
uint32_t h;
uint32_t nblayers;
uint32_t tileset_size;
/* world coordinates of the upper left and bootom right */
/* corners of the current map to be multiplied in game by PXSIZE */
uint16_t xmin;
uint16_t ymin;
uint16_t xmax;
uint16_t ymax;
uint32_t xmin;
uint32_t ymin;
uint32_t xmax;
uint32_t ymax;
/* the tileset to use */
bopti_image_t *tileset;
@ -84,6 +114,10 @@ typedef struct {
uint32_t nbextradata;
ExtraData *extradata;
/* structure that contains all the dialogs for that part of the map */
uint32_t nbdialogsdata;
Dialog *dialogs;
/* list of all the tiles to draw the background and the foreground layers */
uint16_t *layers[];
} Map;

View File

@ -32,7 +32,7 @@ extern Map *worldRPG[];
/* Game data (defined in "game.h")*/
Game game = {
NULL,
{12*PXSIZE, 36*PXSIZE, 0, 0, 10*PXSIZE, 48*PXSIZE, 100, SPEED, false, 0, false},
{12*PXSIZE, 36*PXSIZE, 0, 0, 12*PXSIZE, 36*PXSIZE, 100, SPEED, false, 0, false},
false, false, false, 0
/* debug variables*/
@ -108,11 +108,13 @@ int main(void) {
dgray(DGRAY_ON);
#endif
/*
showtext_dialog(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, true);
int in = showtext_dialog_ask(&game, &player_face_img, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, dignissim sit amet.", true, false, "Lorem\0Ipsum\0Dolor", 3, 0);
if(in==2) showtext_dialog(&game, &player_face_img, "You choosed Dolor", false, true);
else if(in==1) showtext_dialog(&game, &player_face_img, "You choosed Ipsum", false, true);
else showtext_dialog(&game, &player_face_img, "You choosed Lorem", false, true);
*/
do{
/* clear screen */
@ -151,10 +153,12 @@ int main(void) {
{
dfont( NULL );
for (int i=0; i<game.map_level->nbextradata; i++ )
dprint( 10, 90+i*15, C_RED, "X= %d - Y= %d - T: %s",
dprint( 10, 90+i*15, C_RED, "X= %d - Y= %d - T: %d - ID: %d - S: %c",
game.map_level->extradata[i].x,
game.map_level->extradata[i].y,
game.map_level->extradata[i].dialog );
game.map_level->extradata[i].dialogID,
game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].ID,
game.map_level->dialogs[ game.map_level->extradata[i].dialogID ].conclusion1[0] );
}
#endif

View File

@ -5,7 +5,7 @@
#include <gint/display.h>
extern Map *worldRPG[];
extern ExtraData *extraRPG[];
//extern ExtraData *extraRPG[];
void render_map(Game *game) {

72
src/npc.c Normal file
View File

@ -0,0 +1,72 @@
#include "npc.h"
#include "dialogs.h"
#include "game.h"
#include "map.h"
#include "config.h"
#include <gint/display.h>
#include <gint/keyboard.h> /*debug*/
#include <stdint.h>
extern bopti_image_t demo_PNJ_img;
/* the color of the text to go to the next dialog phase */
/* it improves readability to have somathing lighter */
#if defined(FXCG50)
#define PATH_COLOR C_RED
#else
#define PATH_COLOR C_BLACK
#endif
void npc_draw(Game *game) {
Player *player = &game->player;
for (uint32_t u=0; u<game->map_level->nbextradata; u++) //uint pour enlever un warning
{
ExtraData *Data = &game->map_level->extradata[u];
if (strcmp(Data->type, "NPC")==0) /* the current data is a NPC */
{
/* TODO : This is for debugging purpose, JUste to render the path */
/* to be followed by the NPC when this will be implemented */
#if DEBUGMODE
if (Data->hasPath==1) /* this NPC has a trajectory */
{
int NbPoints = Data->path_length+1;
for(int v=0; v<NbPoints; v++)
{
int16_t deltaX1=((int16_t) (Data->x + Data->xpath[v % NbPoints]) * PXSIZE)-(int16_t) player->wx;
int16_t deltaY1=((int16_t) (Data->y + Data->ypath[v % NbPoints]) * PXSIZE)-(int16_t) player->wy;
int16_t deltaX2=((int16_t) (Data->x + Data->xpath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wx;
int16_t deltaY2=((int16_t) (Data->y + Data->ypath[(v+1) % NbPoints]) * PXSIZE)-(int16_t) player->wy;
dline( player->px + deltaX1, player->py + deltaY1,
player->px + deltaX2, player->py + deltaY2,
PATH_COLOR);
}
}
#endif // DEBUGMODE
int16_t deltaX=((int16_t) (Data->x * PXSIZE))-(int16_t) player->wx;
int16_t deltaY=((int16_t) (Data->y * PXSIZE))-(int16_t) player->wy;
dimage( player->px-P_WIDTH/2+deltaX,
player->py-P_HEIGHT/2+deltaY,
&demo_PNJ_img);
}
}
}

18
src/npc.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef NPC_H
#define NPC_H
#include <stdbool.h>
#include "game.h"
#include "memory.h"
/* Draws the player player. This function should be called after drawing the
* map! */
void npc_draw(Game *game);
#endif

View File

@ -1,5 +1,6 @@
#include "player.h"
#include "dialogs.h"
#include "game.h"
#include "map.h"
#include "config.h"
#include <gint/display.h>
@ -26,10 +27,6 @@ const char damage_taken_walkable[WALKABLE_TILE_MAX] = {
};
extern bopti_image_t demo_player_img;
extern bopti_image_t NPC_Icon_img;
extern bopti_image_t SGN_Icon_img;
extern bopti_image_t INFO_Icon_img;
void player_draw(Game *game) {
Player *player = &game->player;
@ -82,6 +79,12 @@ void player_move(Game *game, Direction direction) {
}
extern bopti_image_t demo_player_img;
extern bopti_image_t NPC_Icon_img;
extern bopti_image_t SGN_Icon_img;
extern bopti_image_t INFO_Icon_img;
void player_action(Game *game) {
if( game->player.isDoingAction ) return; /* alreday doing something */
@ -90,21 +93,26 @@ void player_action(Game *game) {
/* we indicate that the player is occupied */
game->player.isDoingAction = true;
/* we collect the information */
char *text = game->map_level->extradata[game->player.whichAction].dialog;
ExtraData *currentData = &game->map_level->extradata[game->player.whichAction];
/* we use the correct image as per the class of the item */
bopti_image_t *face;
if (strcmp("INFO", game->map_level->extradata[game->player.whichAction].type)==0)
/* we use the correct image as per the class of the item */
if (strcmp("INFO", currentData->type)==0)
face = &INFO_Icon_img;
else if (strcmp("NPC", game->map_level->extradata[game->player.whichAction].type)==0)
else if (strcmp("NPC", currentData->type)==0)
face = &NPC_Icon_img;
else if (strcmp("SGN", game->map_level->extradata[game->player.whichAction].type)==0)
else if (strcmp("SGN", currentData->type)==0)
face = &SGN_Icon_img;
else face = &demo_player_img;
/* we treat the action - i.e. we show a dialog */
showtext_dialog( game, face, text, true, true );
uint32_t dialogStart = currentData->dialogID;
initiate_dialog_sequence( game, face, dialogStart );
/* when done we release the occupied status of the player */
game->player.isDoingAction = false;
}