Compare commits

...

6 commits

Author SHA1 Message Date
attilavs2
1a652762e3 assets-fx : Correction du tileset 1b 2024-08-02 23:31:04 +02:00
attilavs2
c003e16729 assets-fx : Correction du tileset 2b 2024-08-02 23:28:41 +02:00
mibi88
a27ad9a14f Ran clang-format 2024-08-02 18:29:56 +02:00
mibi88
fe824d7340 Inventory management. 2024-08-02 18:29:27 +02:00
mibi88
b26cf53e91 Inventory item selection. 2024-08-02 16:14:04 +02:00
mibi88
5dab7f9f18 Cleaner inventory rendering 2024-08-02 12:59:10 +02:00
11 changed files with 245 additions and 44 deletions

View file

@ -74,6 +74,8 @@ set(ASSETS_cg
assets-cg/font.png
assets-cg/inventory.png
assets-cg/items.png
assets-cg/selection.png
assets-cg/selected.png
)
set(ASSETS_cg_EGA64
@ -88,6 +90,8 @@ set(ASSETS_fx
assets-fx/SGN_Icon.png
assets-fx/player_face.png
assets-fx/font.png
assets-fx/selection.png
assets-fx/selected.png
# ...
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View file

@ -17,6 +17,14 @@ SGN_Icon.png:
type: bopti-image
name: SGN_Icon_img
selection.png:
type: bopti-image
name: selection_img
selected.png:
type: bopti-image
name: selected_img
font.png:
name: fontRPG
type: font

View file

@ -142,7 +142,7 @@ def convert_map(input: str, output: str, params: dict, target):
indoor = int(input_map.get_property("indoor"))
except Exception as e:
# Show a warning
print(f"WARNING: Indoor property not found.\n")
print(f"WARNING: Indoor property not found.")
if indoor:
# Get the indoor tileset

View file

@ -25,9 +25,15 @@
/* The size of the player */
#define P_WIDTH 16
#define P_HEIGHT 16
/*Max number of dynamic NPCs.*/
/* Max number of dynamic NPCs. */
#define NPC_STACK_SIZE 256
/* The position of the slots in the inventory */
#define SLOT_Y 87
#define SLOT_X_EQUIPPED 222
#define SLOT_X 272
#define SLOT_W 28
#define SLOT_H 27
#define SLOT_SPACING 32
#else
/* The tile size */
#define T_HEIGHT 8
@ -38,9 +44,15 @@
/* The player size */
#define P_WIDTH 8
#define P_HEIGHT 8
/*Max number of "dynamic" NPCs. We are starved for static ram on fx !*/
/* Max number of "dynamic" NPCs. We are starved for static ram on fx ! */
#define NPC_STACK_SIZE 32
/* The position of the slots in the inventory */
#define SLOT_Y 24
#define SLOT_X_EQUIPPED 72
#define SLOT_X 88
#define SLOT_W 8
#define SLOT_H 8
#define SLOT_SPACING 12
#endif
/* SPEED should NOT be 8 or bigger: it may cause bugs when handling

View file

@ -36,6 +36,11 @@ void game_init(Game *game) {
events_init_handler(&game->handler);
events_bind_variable(&game->handler, (int *)&game->player.life, "life");
events_bind_variable(&game->handler, &game->mana, "mana");
inventory_init(&game->inventory);
/* For debugging */
game->inventory.slots[5].i = I_GLOVE;
game->inventory.slots[1].i = I_ARMOR;
game->inventory.slots[8].i = I_TALISMAN;
// reload_npc(&game);
}
@ -122,8 +127,10 @@ void game_render_indicator(Game *game) {
/* Draw everything. */
void game_draw(Game *game) {
/*Only clear if we are inside, the screen is guaranteed to be filled
/* Only clear if we are inside, the screen is guaranteed to be filled
* otherwise */
/* (Mibi88) if we do so, we should only use opaque tiles in the background
layer (it's currently not the case), to artefacts when rendering dialogs. */
if(game->map_level->indoor)
dclear(C_WHITE);
map_render_by_layer(game, BACKGROUND);
@ -136,7 +143,7 @@ void game_draw(Game *game) {
dprint(8, 8, C_BLACK, "npc_count: %d", npc_count);
dprint(8, 16, C_BLACK, "Mana: %d", game->mana);
dprint(8, 24, C_BLACK, "X: %d Y: %d", game->player.x, game->player.y);
inventory_draw(game, &game->inventory);
inventory_draw(&game->inventory, &game->player);
}
/* Key management */
@ -159,6 +166,56 @@ void game_get_inputs(Game *game) {
clearevents();
sleep();
}
} else if(game->inventory.open) {
if(keydown(KEY_LEFT))
inventory_move_selection(&game->inventory, D_LEFT);
/* TODO: Make something cleaner */
while(keydown(KEY_LEFT)) {
clearevents();
sleep();
}
if(keydown(KEY_RIGHT))
inventory_move_selection(&game->inventory, D_RIGHT);
/* TODO: Make something cleaner */
while(keydown(KEY_RIGHT)) {
clearevents();
sleep();
}
if(keydown(KEY_UP))
inventory_move_selection(&game->inventory, D_UP);
/* TODO: Make something cleaner */
while(keydown(KEY_UP)) {
clearevents();
sleep();
}
if(keydown(KEY_DOWN))
inventory_move_selection(&game->inventory, D_DOWN);
/* TODO: Make something cleaner */
while(keydown(KEY_DOWN)) {
clearevents();
sleep();
}
if(keydown(KEY_OPTN))
inventory_move_from_selected(&game->inventory);
/* TODO: Make something cleaner */
while(keydown(KEY_OPTN)) {
clearevents();
sleep();
}
if(keydown(KEY_SQUARE)) {
inventory_use(&game->inventory, &game->player);
}
if(keydown(KEY_F1)) {
inventory_unequip(&game->inventory, IT_TALISMAN);
}
if(keydown(KEY_F2)) {
inventory_unequip(&game->inventory, IT_ARMOR);
}
if(keydown(KEY_F3)) {
inventory_unequip(&game->inventory, IT_WEAPON);
}
if(keydown(KEY_SHIFT))
game->inventory.selected = game->inventory.selection;
} else {
/* Player actions - Prototypes in player.h and implementation in
* player.c */

View file

@ -32,17 +32,30 @@ typedef enum {
I_AMOUNT
} Item;
typedef enum {
IT_NONE,
IT_TALISMAN,
IT_ARMOR,
IT_WEAPON,
IT_FOOD,
IT_AMOUNT
} ItemType;
typedef struct {
Item i;
Item i : 4;
unsigned char durability;
} Slot;
typedef struct {
/* Backpack slots. */
Slot slots[SLOT_NUM];
Slot talisman;
Slot armor;
Slot weapon;
/* Equipped items: first slot: talisman, second slot: armor, last slot:
weapon. */
Slot equipped[3];
/* 1 if the inventory is open. */
char open : 1;
char selected;
char selection;
} Inventory;
typedef struct {
@ -140,6 +153,7 @@ typedef struct {
uint8_t current_group;
uint8_t hostile_to_group;
/* uint16_t to keep the struct aligned */
uint16_t __padding;
} NPC;

View file

@ -1,51 +1,151 @@
#include "inventory.h"
#include <gint/display.h>
#include <string.h>
extern bopti_image_t inventory_img;
extern bopti_image_t items_img;
extern bopti_image_t selection_img;
extern bopti_image_t selected_img;
extern bopti_image_t player_male_inv_img;
extern bopti_image_t player_female_inv_img;
void inventory_draw(Game *game, Inventory *inventory) {
char item_types[I_AMOUNT] = {IT_NONE, IT_ARMOR, IT_WEAPON, IT_WEAPON,
IT_FOOD, IT_FOOD, IT_TALISMAN};
void inventory_init(Inventory *inventory) {
inventory->open = 0;
memset(inventory->slots, 0, sizeof(Slot) * SLOT_NUM);
memset(inventory->equipped, 0, sizeof(Slot) * 3);
inventory->selected = -1;
inventory->selection = 0;
}
void inventory_draw(Inventory *inventory, Player *player) {
size_t i;
/* TODO: Cleanup! */
inventory->slots[5].i = I_GLOVE;
inventory->armor.i = I_ARMOR;
inventory->talisman.i = I_TALISMAN;
inventory->weapon.i = I_SWORD;
if(inventory->open) {
dimage(0, 0, &inventory_img);
for(i = 0; i < SLOT_NUM; i++) {
#if GINT_RENDER_RGB
dsubimage(272 + (i % SLOT_COLUMNS) * 32,
87 + (i / SLOT_COLUMNS) * 32, &items_img,
inventory->slots[i].i * 28, 0, 28, 27, DIMAGE_NONE);
#else
dsubimage(88 + (i % SLOT_COLUMNS) * 12,
24 + (i / SLOT_COLUMNS) * 12, &items_img,
inventory->slots[i].i * 8, 0, 8, 8, DIMAGE_NONE);
#endif
dsubimage(SLOT_X + (i % SLOT_COLUMNS) * SLOT_SPACING,
SLOT_Y + (i / SLOT_COLUMNS) * SLOT_SPACING, &items_img,
inventory->slots[i].i * SLOT_W, 0, SLOT_W, SLOT_H,
DIMAGE_NONE);
if(i == inventory->selection) {
dimage(SLOT_X + (i % SLOT_COLUMNS) * SLOT_SPACING,
SLOT_Y + (i / SLOT_COLUMNS) * SLOT_SPACING,
&selection_img);
}
if(i == inventory->selected) {
dimage(SLOT_X + (i % SLOT_COLUMNS) * SLOT_SPACING,
SLOT_Y + (i / SLOT_COLUMNS) * SLOT_SPACING,
&selected_img);
}
}
for(i = 0; i < 3; i++) {
dsubimage(SLOT_X_EQUIPPED, SLOT_Y + i * SLOT_SPACING, &items_img,
inventory->equipped[i].i * SLOT_W, 0, SLOT_W, SLOT_H,
DIMAGE_NONE);
}
#if GINT_RENDER_RGB
dsubimage(222, 87, &items_img, inventory->talisman.i * 28, 0, 28, 27,
DIMAGE_NONE);
dsubimage(222, 87 + 32, &items_img, inventory->armor.i * 28, 0, 28, 27,
DIMAGE_NONE);
dsubimage(222, 87 + 64, &items_img, inventory->weapon.i * 28, 0, 28, 27,
DIMAGE_NONE);
#else
dsubimage(72, 24, &items_img, inventory->talisman.i * 8, 0, 8, 8,
DIMAGE_NONE);
dsubimage(72, 24 + 12, &items_img, inventory->armor.i * 8, 0, 8, 8,
DIMAGE_NONE);
dsubimage(72, 24 + 24, &items_img, inventory->weapon.i * 8, 0, 8, 8,
DIMAGE_NONE);
#endif
#if GINT_RENDER_RGB
/* Render the player between the two swords if we are on cg. */
dimage(183, 20,
game->player.is_male ? &player_male_inv_img
: &player_female_inv_img);
player->is_male ? &player_male_inv_img : &player_female_inv_img);
#endif
}
/* TODO: Stats. */
}
char inventory_add(Inventory *inventory, Item item) {
size_t i;
for(i = 0; i < SLOT_NUM; i++) {
if(!inventory->slots[i].i) {
inventory->slots[i].i = item;
inventory->slots[i].durability = 255;
return 0;
}
}
return 1;
}
void inventory_move_from_selected(Inventory *inventory) {
if(inventory->selected < 0)
return;
Slot current = inventory->slots[inventory->selection];
Slot new = inventory->slots[inventory->selected];
inventory->slots[inventory->selection] = new;
inventory->slots[inventory->selected] = current;
}
void inventory_use(Inventory *inventory, Player *player) {
Item item = inventory->slots[inventory->selection].i;
switch(item_types[item]) {
case IT_TALISMAN:
inventory->equipped[0] = inventory->slots[inventory->selection];
break;
case IT_ARMOR:
inventory->equipped[1] = inventory->slots[inventory->selection];
break;
case IT_WEAPON:
inventory->equipped[2] = inventory->slots[inventory->selection];
break;
case IT_FOOD:
/* TODO */
break;
default:
break;
}
inventory->slots[inventory->selection].i = I_NONE;
inventory->slots[inventory->selection].durability = 255;
}
void inventory_unequip(Inventory *inventory, ItemType type) {
if(inventory->slots[inventory->selection].i)
return;
switch(type) {
case IT_TALISMAN:
inventory->slots[inventory->selection] = inventory->equipped[0];
inventory->equipped[0].i = I_NONE;
inventory->equipped[0].durability = 255;
break;
case IT_ARMOR:
inventory->slots[inventory->selection] = inventory->equipped[1];
inventory->equipped[1].i = I_NONE;
inventory->equipped[1].durability = 255;
break;
case IT_WEAPON:
inventory->slots[inventory->selection] = inventory->equipped[2];
inventory->equipped[2].i = I_NONE;
inventory->equipped[2].durability = 255;
break;
default:
break;
}
}
void inventory_move_selection(Inventory *inventory, Direction direction) {
switch(direction) {
case D_UP:
inventory->selection -= SLOT_COLUMNS;
if(inventory->selection < 0)
inventory->selection = 0;
break;
case D_DOWN:
inventory->selection += SLOT_COLUMNS;
if(inventory->selection >= SLOT_NUM) {
inventory->selection = SLOT_NUM - 1;
}
break;
case D_LEFT:
if(inventory->selection > 0) {
inventory->selection--;
}
break;
case D_RIGHT:
if(inventory->selection < SLOT_NUM - 1) {
inventory->selection++;
}
break;
default:
break;
}
}

View file

@ -4,6 +4,12 @@
/* The structs related to the inventory are defined in game.h */
#include "game.h"
void inventory_draw(Game *game, Inventory *inventory);
void inventory_init(Inventory *inventory);
void inventory_draw(Inventory *inventory, Player *player);
char inventory_add(Inventory *inventory, Item item);
void inventory_move_from_selected(Inventory *inventory);
void inventory_use(Inventory *inventory, Player *player);
void inventory_unequip(Inventory *inventory, ItemType type);
void inventory_move_selection(Inventory *inventory, Direction direction);
#endif