change the way dialogs work

update converters.py thanks to Lephenixnoir
now dialogs are inside the map directly on Tiled
This commit is contained in:
bgiraudr 2021-08-26 01:17:48 +02:00
parent 0477f1210c
commit 39648a7353
22 changed files with 160 additions and 162 deletions

View File

@ -23,7 +23,7 @@ add_custom_command(
set(SOURCES
src/main.c
src/character.c
src/talkable.c
src/vec2.c
src/game.c
src/engine.c
@ -39,12 +39,6 @@ set(ASSETS_cg
assets-cg/maps/testCarte.json
assets-cg/maps/inside/interior_1.json
assets-cg/spritesheet.png
assets-cg/characters/Tituya.char
assets-cg/characters/Lephenixnoir.char
assets-cg/characters/KikooDX.char
assets-cg/characters/Massena.char
assets-cg/characters/Tituya2.char
assets-cg/characters/PancarteVille.char
)
fxconv_declare_assets(${ASSETS} ${ASSETS_fx} ${ASSETS_cg} WITH_METADATA)

View File

@ -1,4 +0,0 @@
41
10
KikooDX
Je te rassure, pas de Pokemon !

View File

@ -1,4 +0,0 @@
50
30
Lephenixnoir
Regarde ! Je n'ai pas de reflet !

View File

@ -1,4 +0,0 @@
2
9
Massena
C'est une belle ville non ?

View File

@ -1,4 +0,0 @@
10
20
Planete City
90+E FTW

View File

@ -1,4 +0,0 @@
37
32
Tituya
J'ai toujours aimé ce pont;Pas toi ?

View File

@ -1,4 +0,0 @@
52
2
Tituya
La belle montagne !

View File

@ -1,3 +0,0 @@
*.char:
custom-type: character
name_regex: (.*)\.char character_\1

View File

@ -5,9 +5,6 @@ def convert(input, output, params, target):
if params["custom-type"] == "map":
convert_map(input, output, params, target)
return 0
elif params["custom-type"] == "character":
convert_character(input, output, params, target)
return 0
else:
return 1
@ -16,7 +13,7 @@ def convert_map(input, output, params, target):
TILE_SOLID = 1
TILE_DOOR_IN = 2
TILE_DOOR_OUT = 3
TILE_CHARACTER = 4
TILE_TALKABLE = 4
TILE_BRIDGE = -1 #only for bridge detection to avoid solid behind
@ -52,8 +49,8 @@ def convert_map(input, output, params, target):
value = TILE_DOOR_IN
elif type == "door_out":
value = TILE_DOOR_OUT
elif type == "character":
value = TILE_CHARACTER
elif type == "talkable":
value = TILE_TALKABLE
elif type == "bridge":
value = TILE_BRIDGE
else:
@ -65,11 +62,40 @@ def convert_map(input, output, params, target):
#Extract from the json the width, height and layers of the map
w, h = data["width"], data["height"]
nblayer = len(data["layers"])
indexObjectlayer = None
o = fxconv.ObjectData()
o += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nblayer)
o += fxconv.ref(f"img_{nameTilesetFree}")
nbTilelayer = len(data["layers"])
for i in range(nbTilelayer):
try:
data["layers"][i]["data"]
#nbTileLayer is the number of "true" layers (without ObjectsLayer)
nbTilelayer = i+1
except KeyError:
indexObjectlayer = i
break
if indexObjectlayer != None:
nbDialog = len(data["layers"][indexObjectlayer]["objects"])
else:
nbDialog = 0
structMap = fxconv.Structure()
structMap += fxconv.u32(w) + fxconv.u32(h) + fxconv.u32(nbTilelayer) + fxconv.u32(nbDialog)
structMap += fxconv.ref(f"img_{nameTilesetFree}")
dialogs = fxconv.Structure()
if indexObjectlayer != None:
#generate all of the dialog
for i in data["layers"][indexObjectlayer]["objects"]:
dialogs += fxconv.u32(int(i["x"]/i["width"]))
#Tiled seem to start at the bottom y of the object
#So if tile is 16 px wide, you would start at line y = 1
dialogs += fxconv.u32(int(i["y"]/i["width"])-1)
for j in i["properties"]:
if(j["value"] == ""): j["value"] = " "
dialogs += fxconv.string(j["value"])
structMap += fxconv.ptr(dialogs)
#generation of the collision map (take the maximum of the layer except for bridges)
#bridges are always walkable
@ -78,7 +104,7 @@ def convert_map(input, output, params, target):
maxValue = 0
bridge = False
for x in range(w*h):
for i in range(nblayer):
for i in range(nbTilelayer):
value = tile_value.get(data["layers"][i]["data"][x])
if value == None: value = TILE_AIR
if value > maxValue: maxValue = value
@ -91,27 +117,16 @@ def convert_map(input, output, params, target):
info_map += fxconv.u16(maxValue)
maxValue = 0
bridge = False
o += fxconv.ref(info_map)
structMap += fxconv.ref(info_map)
#generate the array of tiles from the layer
for layer in data["layers"]:
for i in range(nbTilelayer):
layer_data = bytes()
layer = data["layers"][i]
for tile in layer["data"]:
layer_data += fxconv.u16(tile)
o += fxconv.ref(layer_data)
structMap += fxconv.ref(layer_data)
#generate !
fxconv.elf(o, output, "_" + params["name"], **target)
def convert_character(input, output, params, target):
with open(input,"r") as dialog:
file = dialog.read().splitlines()
o = fxconv.ObjectData()
o += fxconv.u32((int)(file[0])) + fxconv.u32((int)(file[1]))
o += fxconv.ref(bytes(file[2], 'utf-8') + bytes(1)) #bytes(1) is necessary to end a char
o += fxconv.ref(bytes(file[3], 'utf-8') + bytes(1))
fxconv.elf(o, output, "_" + params["name"], **target)
fxconv.elf(structMap, output, "_" + params["name"], **target)

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="12" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="10" nextobjectid="25">
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="12" height="10" tilewidth="16" tileheight="16" infinite="0" nextlayerid="11" nextobjectid="30">
<editorsettings>
<export target="interior_1.json" format="json"/>
</editorsettings>
@ -46,4 +46,12 @@
0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="10" name="dialog">
<object id="25" gid="267" x="112" y="112" width="16" height="16">
<properties>
<property name="name" value="Tituya"/>
<property name="text" value="Salutation !"/>
</properties>
</object>
</objectgroup>
</map>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="100" height="38" tilewidth="16" tileheight="16" infinite="0" nextlayerid="9" nextobjectid="25">
<map version="1.5" tiledversion="1.7.2" orientation="orthogonal" renderorder="right-down" width="100" height="38" tilewidth="16" tileheight="16" infinite="0" nextlayerid="11" nextobjectid="38">
<editorsettings>
<export target="testCarte.json" format="json"/>
</editorsettings>
@ -88,4 +88,36 @@
294,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,381,382,383,381,382,383,381,382,383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
</data>
</layer>
<objectgroup id="10" name="text">
<object id="33" gid="267" x="592" y="528" width="16" height="16">
<properties>
<property name="name" value="Tituya"/>
<property name="text" value="J'ai toujours aimé ce pont;Pas toi ?"/>
</properties>
</object>
<object id="34" gid="267" x="704" y="368" width="16" height="16">
<properties>
<property name="name" value="Pancarte"/>
<property name="text" value="Ne vous aventurez pas trop loin !"/>
</properties>
</object>
<object id="35" gid="267" x="720" y="368" width="16" height="16">
<properties>
<property name="name" value=""/>
<property name="text" value="Une belle pancarte &lt;3"/>
</properties>
</object>
<object id="36" gid="267" x="800" y="496" width="16" height="16">
<properties>
<property name="name" value="Lephenixnoir"/>
<property name="text" value="Regarde ! Je n'ai pas de reflet !"/>
</properties>
</object>
<object id="37" gid="267" x="656" y="176" width="16" height="16">
<properties>
<property name="name" value="KikooDX"/>
<property name="text" value="Je te rassure, pas de Pokémon !"/>
</properties>
</object>
</objectgroup>
</map>

View File

@ -19,13 +19,13 @@
<tile id="45" type="solid"/>
<tile id="46" type="solid"/>
<tile id="47" type="solid"/>
<tile id="48" type="character"/>
<tile id="49" type="solid"/>
<tile id="48" type="talkable"/>
<tile id="49" type="talkable"/>
<tile id="52" type="solid"/>
<tile id="53" type="solid"/>
<tile id="54" type="solid"/>
<tile id="56" type="character"/>
<tile id="57" type="character"/>
<tile id="56" type="talkable"/>
<tile id="57" type="talkable"/>
<tile id="78" type="solid"/>
<tile id="79" type="solid"/>
<tile id="80" type="solid"/>
@ -88,6 +88,12 @@
<tile id="263" type="solid"/>
<tile id="264" type="solid"/>
<tile id="265" type="solid"/>
<tile id="266" type="text">
<properties>
<property name="name" value=""/>
<property name="text" value=""/>
</properties>
</tile>
<tile id="268" type="solid"/>
<tile id="269" type="solid"/>
<tile id="270" type="solid"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -1,17 +0,0 @@
#pragma once
struct Character {
/*the position of the character*/
int x, y;
/*the name*/
char *name;
/*the text to say*/
char *dialog;
};
/*draw the dialog of a specified character*/
void draw_dialog(struct Character *character);
/*find the character using the player's position*/
struct Character* get_character_xy(struct Character *characters[], int x, int y);
/*get the characters for a specified map*/
struct Character** get_map_characters(int id);

View File

@ -6,8 +6,6 @@ struct Game {
struct Map *map;
/*the player*/
struct Player *player;
/*list of all the characters on the map*/
struct Character **characters;
/*the camera*/
struct Camera camera;
/*the background color*/

View File

@ -5,9 +5,11 @@
struct Map {
/*width, height and the number of layer of the map (max 2)*/
int w, h, nb_layers;
int w, h, nb_layers, dialog_count;
/*the tileset to use*/
bopti_image_t *tileset;
/*list of all the dialog*/
struct Talkable *dialogs;
/*state of each tile on the map (solid, air ...)*/
short *info_map;
/*list of all the tiles*/
@ -19,7 +21,7 @@ enum map_state {
TILE_SOLID = 1,
TILE_DOOR_IN = 2,
TILE_DOOR_OUT = 3,
TILE_CHARACTER = 4,
TILE_TALKABLE = 4,
};
/*check if a tile is walkable*/

15
include/talkable.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "map.h"
struct Talkable {
/*the position of the tile*/
int x, y;
/*the name*/
char *name;
/*the text to display*/
char *text;
};
/*draw the dialog of a specified talkable tile*/
void draw_dialog(struct Talkable *character);
/*find the talkable tile using the player's position*/
struct Talkable* get_dialog_xy(struct Map *map, int x, int y);

View File

@ -1,66 +0,0 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <string.h>
#include "character.h"
#include "engine.h"
#include "map.h"
#include "util.h"
struct Character character_default = {
.x = 0,
.y = 0,
.name = "default name",
.dialog = "default dialog"
};
/*draw the dialog of a specified character*/
void draw_dialog(struct Character *character) {
const char *delim = ";";
char *str = strdup(character->dialog);
char *curr_line = strtok(str, delim);
while(curr_line != NULL) {
drect(20,10,370,80,C_WHITE);
dprint(25,20, C_BLACK, "%s", character->name);
dprint(25,40, C_BLACK, "%s", curr_line);
dupdate();
curr_line = strtok(NULL, delim);
wait_for_input(KEY_SHIFT);
}
}
/*find the character using the player's position*/
struct Character* get_character_xy(struct Character *characters[], int x, int y) {
int i = 0;
while(strcmp(characters[i]->name,"default name") != 0) {
if(characters[i]->x == x && characters[i]->y == y) return characters[i];
i++;
}
return &character_default;
}
/*get the characters for a specified map*/
struct Character** get_map_characters(int id) {
if(id == 1) {
extern struct Character character_Tituya;
extern struct Character character_Lephenixnoir;
extern struct Character character_Tituya2;
extern struct Character character_KikooDX;
extern struct Character character_Massena;
extern struct Character character_PancarteVille;
static struct Character *characters[] = {
&character_Tituya,
&character_Lephenixnoir,
&character_Massena,
&character_Tituya2,
&character_KikooDX,
&character_PancarteVille,
&character_default,
};
return characters;
}
static struct Character *characters[] = {};
return characters;
}

View File

@ -6,7 +6,7 @@
#include "player.h"
#include "animation.h"
#include "define.h"
#include "character.h"
#include "talkable.h"
#include "camera.h"
#include "vec2.h"
@ -107,11 +107,11 @@ void engine_set_background(struct Game *game, int color) {
/*make an interaction with something*/
void engine_action(struct Game const *game, int action) {
if(action == ACTION_SHIFT) {
if(player_facing(game) == TILE_CHARACTER) {
if(player_facing(game) == TILE_TALKABLE) {
int direction = game->player->direction;
int dx = (direction == DIR_RIGHT) - (direction == DIR_LEFT);
int dy = (direction == DIR_DOWN) - (direction == DIR_UP);
draw_dialog(get_character_xy(game->characters, game->player->pos.x + dx, game->player->pos.y + dy));
draw_dialog(get_dialog_xy(game->map, game->player->pos.x + dx, game->player->pos.y + dy));
}
}
}

View File

@ -5,7 +5,6 @@
#include "engine.h"
#include "player.h"
#include "animation.h"
#include "character.h"
#include "camera.h"
#include "define.h"
@ -44,7 +43,6 @@ int main(void) {
.camera = camera_new(&player.pos_visual),
.background = C_WHITE
};
game.characters = get_map_characters(1);
/*Timer*/
static volatile int tick = 1;

View File

@ -8,7 +8,7 @@
int map_walkable(struct Map const *map, int x, int y) {
int tile = map->info_map[x + map->w * y];
if(x < 0 || x > map->w-1 || y < 0 || y > map->h-1) return 0;
return (tile != TILE_SOLID && tile != TILE_CHARACTER);
return (tile != TILE_SOLID && tile != TILE_TALKABLE);
}
/*get the tile under the player*/
@ -20,7 +20,6 @@ void generate_interior_map(struct Game *game) {
extern struct Map in_1;
game->map = &in_1;
set_player_xy(game->player, 3,3);
//game->camera.target = &VEC2F(DWIDTH/2, DHEIGHT/2);
game->camera.pos.x = in_1.w/2 * TILE_SIZE + game->player->x_mid;
game->camera.pos.y = in_1.h/2 * TILE_SIZE + game->player->y_mid;
}

41
src/talkable.c Normal file
View File

@ -0,0 +1,41 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <string.h>
#include "talkable.h"
#include "engine.h"
#include "map.h"
#include "util.h"
struct Talkable default_value = {
.x = 0,
.y = 0,
.name = "default name",
.text = "default dialog"
};
/*draw the dialog of a specified talkable tile*/
void draw_dialog(struct Talkable *talkable) {
const char *delim = ";";
char *str = strdup(talkable->text);
char *curr_line = strtok(str, delim);
while(curr_line != NULL) {
drect(20,10,370,80,C_WHITE);
dprint(25,20, C_BLACK, "%s", talkable->name);
dprint(25,40, C_BLACK, "%s", curr_line);
dupdate();
curr_line = strtok(NULL, delim);
wait_for_input(KEY_SHIFT);
}
}
/*find the talkable tile using the player's position*/
struct Talkable* get_dialog_xy(struct Map *map, int x, int y) {
int i = 0;
while(i < map->dialog_count) {
if(map->dialogs[i].x == x && map->dialogs[i].y == y) return &map->dialogs[i];
i++;
}
return &default_value;
}