From bca71726db6d602073d599b745ab919878f55e7f Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Wed, 16 Feb 2022 17:42:05 +0100 Subject: [PATCH] items on the floor --- CMakeLists.txt | 4 +++ assets-cg/items/fxconv-metadata.txt | 5 ++++ assets-cg/items/life.aseprite | Bin 0 -> 662 bytes assets-cg/items/sword1.aseprite | Bin 0 -> 691 bytes src/anim.c | 4 +++ src/anim.h | 4 +++ src/aoe.c | 8 ++++++ src/aoe.h | 6 +++- src/game.c | 2 +- src/game.h | 2 -- src/item.c | 42 ++++++++++++++++++++++++++++ src/item.h | 28 +++++++++++++++++++ src/main.c | 25 +++++++++++++---- src/player.c | 4 ++- src/player.h | 6 ++-- src/render.c | 13 +++++---- src/skills.h | 2 +- 17 files changed, 135 insertions(+), 20 deletions(-) create mode 100644 assets-cg/items/fxconv-metadata.txt create mode 100644 assets-cg/items/life.aseprite create mode 100644 assets-cg/items/sword1.aseprite create mode 100644 src/item.c create mode 100644 src/item.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f0c2b7f..723fb64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCES src/enemies.c src/game.c src/geometry.c + src/item.c src/main.c src/map.c src/menu.c @@ -56,6 +57,9 @@ set(ASSETS assets-cg/hud_xp.ase assets-cg/skillicons.png assets-cg/font_hud.png + # Items + assets-cg/items/life.aseprite + assets-cg/items/sword1.aseprite # Player animations assets-cg/player/player_up.aseprite assets-cg/player/player_right.aseprite diff --git a/assets-cg/items/fxconv-metadata.txt b/assets-cg/items/fxconv-metadata.txt new file mode 100644 index 0000000..0c8bce0 --- /dev/null +++ b/assets-cg/items/fxconv-metadata.txt @@ -0,0 +1,5 @@ +*.aseprite: + custom-type: aseprite-anim + name_regex: (.*)\.aseprite frames_item_\1 + next: Item=Item + profile: p4 diff --git a/assets-cg/items/life.aseprite b/assets-cg/items/life.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..795f2255155485a6b6ed481f3ee3d72c51cd0da4 GIT binary patch literal 662 zcmcJNODIH99EZ<%4Oyru6XkJ|uu#S%nnsCIUJFqsY4R8|Wy**qd6YcEBsTJ1SddAS zY?OtKM+yr`3=5;kPO(I;?+&7@{ZHq+=l<`l-*?WvQ$a%bmo*}iA%#W=(a8KMdTLXI zGybFW3)6C;!;}dps?6}FH3j+> z9q@5?4!%BT!`b_C=-e^DoJkifZOVWZrOD8kYl3-sZfL0Mhc&KSXq#7H?a3WHx_*NS zCB*#t798vuhD}ZBecTbp z8fAQu#S~2(5yTEPypX~O9o0oqut0%)!bv8UOae(GDp5_6!SK6K5L!`I-)V1?nW@~w z{5kmVSGk6WVz<57!75aKwiUkJXQ_Wr$AYb{xA$ylNXehkMEG@PolbjTFcmZ$wq5RR xjM{c5z1G!-k-pROhRT8Q`ggNG+GB|?O3*u&y!$H&*7(gX_gH$Ah#S5;{s14ptLFd! literal 0 HcmV?d00001 diff --git a/assets-cg/items/sword1.aseprite b/assets-cg/items/sword1.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..dbf1821191c0859ac62e30fca3c577b1fc8d2536 GIT binary patch literal 691 zcmcJNOGs2v7{@;!IYJ9tg^Do85_J<^N3pyP3 zSeu;=drNcRdQ&o7c~J{@r=P?9-&ye4P6_mm8}NF6BP^;pr%9yM?b>O_HJ13^}_N}H+-1e1K&CvaHY%xms>x<-ho2cbI;IT zHV|o@yJEp6*a7;uBaSu7_#%rbnm8he9cp+Xg%LWIi`H16KtACl6H6w6q!DGel2imd zDHOye#djao+*j!-+{FHO@F%Zwjg*4sng&0s3+kw?`F2NT{XH#1o~p?hpYN)kAD%dH zJxPAKJJXk<(<;ZGmR*~52F$h}Ul*s0lIYiF@XOC%o42dA-$;C5e8{is^e=7Q>K+>j on8DS$Kkk1w=N7s?+Xl>FeC*ntic4=E2X4GeFzs<7qxl`SLt&M@0{{R3 literal 0 HcmV?d00001 diff --git a/src/anim.c b/src/anim.c index 0702c53..862e6de 100644 --- a/src/anim.c +++ b/src/anim.c @@ -75,6 +75,10 @@ ANIM1(hud_xp_Idle); ANIM1(hud_xp_Shine); ANIM1(hud_xp_Explode); +/* Items */ +ANIM1(item_life); +ANIM1(item_sword1); + /* Animation functions. */ fixed_t (anim_duration)(anim_t const *anim) diff --git a/src/anim.h b/src/anim.h index 5883d92..aca6d26 100644 --- a/src/anim.h +++ b/src/anim.h @@ -106,3 +106,7 @@ extern anim_t anims_player_Hit; extern anim_t anims_hud_xp_Idle; extern anim_t anims_hud_xp_Shine; extern anim_t anims_hud_xp_Explode; + +/* Items */ +extern anim_t anims_item_life; +extern anim_t anims_item_sword1; diff --git a/src/aoe.c b/src/aoe.c index 8763c78..bc392a4 100644 --- a/src/aoe.c +++ b/src/aoe.c @@ -235,6 +235,14 @@ void aoe_apply(game_t *game, entity_t *entity, entity_t *e) bool was_hit = false; aoe_t *aoe = getcomp(entity, aoe); aoe_record_t *rec = aoe_record(aoe, e); + fighter_t *e_f = getcomp(e, fighter); + + if(aoe->type == AOE_ITEM && e_f && e_f->player) { + item_pick_up(&aoe->data.item.data, e); + aoe->lifetime = 0; + /* Don't bother recording the hit since the item will disappear */ + was_hit = false; + } /* Don't hit entities that have been recently hit */ if(rec && aoe->repeat_delay == 0) return; diff --git a/src/aoe.h b/src/aoe.h index 6c81ca2..89b94ce 100644 --- a/src/aoe.h +++ b/src/aoe.h @@ -6,9 +6,11 @@ #include "geometry.h" #include "anim.h" - +#include "item.h" enum { + /* Item */ + AOE_ITEM, /* Bare-hand fist/close-contact attack */ AOE_HIT, /* Simple ranged attack */ @@ -51,6 +53,8 @@ typedef struct uint16_t type; /* Effect data (type-dependent) */ union { + /* Item: item info */ + struct { item_data_t data; } item; /* Generic attacks: source and ATK strength */ struct { int strength; int dir; } generic; /* AOE_PROJECTILE: speed and direction of movement */ diff --git a/src/game.c b/src/game.c index 7ed01ae..7be2586 100644 --- a/src/game.c +++ b/src/game.c @@ -189,7 +189,7 @@ void game_remove_dead_entities(game_t *g) if(f && f->HP == 0 && f->enemy != NULL && anim_finished) { /* Give XP points to player */ - bool lvup = player_add_xp(g->player_data, f->enemy->id->xp); + bool lvup = player_add_xp(g->player, f->enemy->id->xp); if(lvup) { g->hud_xp_anim.frame = anims_hud_xp_Explode.start[0]; diff --git a/src/game.h b/src/game.h index 6bd235f..a6de39b 100644 --- a/src/game.h +++ b/src/game.h @@ -39,8 +39,6 @@ typedef struct game { int entity_count; /* Player; this must be one of the entities loaded in the game */ entity_t *player; - /* Associated player data */ - player_t *player_data; /* Field of movement to reach the player (used by most enemy AIs) */ pfg_all2one_t paths_to_player; diff --git a/src/item.c b/src/item.c new file mode 100644 index 0000000..1489e53 --- /dev/null +++ b/src/item.c @@ -0,0 +1,42 @@ +#include "item.h" +#include "aoe.h" +#include "comp/fighter.h" +#include "comp/physical.h" +#include "comp/visible.h" +#include + +entity_t *item_make(item_data_t const *data, vec2 position) +{ + entity_t *e = aoe_make(AOE_ITEM, position, fix(9999.0)); + + visible_t *v = getcomp(e, visible); + v->sprite_plane = VERTICAL; + v->shadow_size = 3; + v->z = fix(0.35); + + physical_t *p = getcomp(e, physical); + p->hitbox = (rect){ -fix(4)/16, fix(3)/16, -fix(2)/16, fix(1)/16 }; + + aoe_t *aoe = getcomp(e, aoe); + aoe->origin = NULL; + aoe->repeat_delay = 0; + aoe->data.item.data = *data; + + if(data->type == ITEM_LIFE) { + visible_set_anim(e, &anims_item_life, 1); + } +// else if(data->type == ITEM_X) { +// visible_set_anim(e, &anims_item_x, 1); +// } + + return e; +} + +void item_pick_up(item_data_t const *data, entity_t *player) +{ + fighter_t *f = getcomp(player, fighter); + + if(data->type == ITEM_LIFE && f) { + f->HP = min(f->HP + data->life.HP, f->HP_max); + } +} diff --git a/src/item.h b/src/item.h new file mode 100644 index 0000000..89a15ec --- /dev/null +++ b/src/item.h @@ -0,0 +1,28 @@ +//--- +// items: Dropped objects that can be picked up from the ground +//--- + +#pragma once + +#include "comp/entity.h" +#include "geometry.h" + +enum { + ITEM_LIFE = 0, +}; + +typedef struct { + int type; + + union { + /* ITEM_LIFE: Amount of HP restored */ + struct { int HP; } life; + }; + +} item_data_t; + +/* Create an item. This is just an AOE with a particular type. */ +entity_t *item_make(item_data_t const *data, vec2 position); + +/* Give an item to a player entity. */ +void item_pick_up(item_data_t const *data, entity_t *player); diff --git a/src/main.c b/src/main.c index 77b9313..862e81d 100644 --- a/src/main.c +++ b/src/main.c @@ -10,6 +10,7 @@ #include "enemies.h" #include "game.h" #include "geometry.h" +#include "item.h" #include "level.h" #include "map.h" #include "menu.h" @@ -86,7 +87,7 @@ int main(void) // Spawn player //--- - player_t player_data = { + player_data_t player_data = { .entity = NULL, .mechanical_limits = { .max_speed = fix(4.5), @@ -105,7 +106,6 @@ int main(void) .xp_to_next_level = 0, .xp_current = 0, }; - game.player_data = &player_data; entity_t *player = entity_make(physical, visible, mechanical, fighter); player_data.entity = player; @@ -119,8 +119,7 @@ int main(void) player_f->combo_next = 0; player_f->combo_delay = fix(0); player_f->enemy = NULL; - // TODO: Set link to player data in entity - // player_f->player = &player_data; + player_f->player = &player_data; player_f->skills[1] = SKILL_DASH; player_f->skills[2] = AOE_SHOCK; player_f->skills[3] = AOE_JUDGEMENT; @@ -128,7 +127,7 @@ int main(void) for(int i = 0; i < 5; i++) player_f->actions_cooldown[i] = fix(0.0); /* Initialize stats. This will level up to level 1 */ - player_add_xp(&player_data, 0); + player_add_xp(player, 0); player_f->HP = player_f->HP_max; player_p->x = fix(game.level->player_spawn_x) + fix(0.5); @@ -145,6 +144,22 @@ int main(void) game_add_entity(&game, player); game.player = player; + + int x=0, y=0; + for(int i = 0; i < 100; i++) { + y = rand() % game.map->height; + x = rand() % game.map->width; + map_cell_t const *cell = map_cell(game.map, x, y); + __auto_type tiles = game.map->tileset->tiles; + + if(!tiles[cell->base].solid && + (!cell->decor || !tiles[cell->decor].solid)) + break; + } + item_data_t data = { .type = ITEM_LIFE, .life.HP = 50 }; + entity_t *item = item_make(&data, (vec2){ fix(x)+fix(0.5), fix(y)+fix(0.5) }); + game_add_entity(&game, item); + //--- // Main loop //--- diff --git a/src/player.c b/src/player.c index 2a39a29..737e0f9 100644 --- a/src/player.c +++ b/src/player.c @@ -6,8 +6,10 @@ static int xp_to_next_level(int level) return 3 * (level + 2) * (level + 2); } -bool player_add_xp(player_t *p, int points) +bool player_add_xp(entity_t *e, int points) { + player_data_t *p = getcomp(e, fighter)->player; + bool leveled_up = false; p->xp_current += max(points, 0); diff --git a/src/player.h b/src/player.h index 1ad7258..c32b908 100644 --- a/src/player.h +++ b/src/player.h @@ -9,7 +9,7 @@ #include "comp/fighter.h" #include -typedef struct { +typedef struct player_data { /* Associated entity */ entity_t *entity; /* Mechanical limits (dynamically recomputed) */ @@ -21,7 +21,7 @@ typedef struct { int xp_to_next_level; int xp_current; -} player_t; +} player_data_t; /* Add XP points to a player. Returns true if levels up */ -bool player_add_xp(player_t *p, int points); +bool player_add_xp(entity_t *p, int points); diff --git a/src/render.c b/src/render.c index 3de466f..e7757b4 100644 --- a/src/render.c +++ b/src/render.c @@ -434,16 +434,17 @@ void render_game(game_t const *g, bool show_hitboxes) extern bopti_image_t img_hud; dimage(0, HUD_Y - img_hud.height, &img_hud); + fighter_t *player_f = getcomp(g->player, fighter); + extern font_t font_hud; + player_data_t *player_data = player_f->player; dfont(&font_hud); dprint_opt(349, HUD_Y - 5, RGB24(0x15171a), C_NONE, DTEXT_CENTER, - DTEXT_TOP, "%d", g->player_data->xp_level); + DTEXT_TOP, "%d", player_data->xp_level); dprint_opt(349, HUD_Y - 6, RGB24(0xabb1ba), C_NONE, DTEXT_CENTER, - DTEXT_TOP, "%d", g->player_data->xp_level); + DTEXT_TOP, "%d", player_data->xp_level); dfont(&font_rogue); - fighter_t *player_f = getcomp(g->player, fighter); - /* Render life bar */ extern bopti_image_t img_hud_life; int fill_height = (img_hud_life.height * player_f->HP) / player_f->HP_max; @@ -458,8 +459,8 @@ void render_game(game_t const *g, bool show_hitboxes) } else { static int const XP_FULL=22; - int xp_current = g->player_data->xp_current; - int xp_total = max(g->player_data->xp_to_next_level, 1); + int xp_current = player_data->xp_current; + int xp_total = max(player_data->xp_to_next_level, 1); int fill_height = XP_FULL * xp_current / xp_total; anim_frame_subrender(343, HUD_Y-32, g->hud_xp_anim.frame, 0, XP_FULL - fill_height, -1, fill_height); diff --git a/src/skills.h b/src/skills.h index d62b78c..a1b73e1 100644 --- a/src/skills.h +++ b/src/skills.h @@ -10,7 +10,7 @@ enum { SKILL_DASH = 0x100, - /* Other skills: */ + /* Other skills in the AOE enumeration that are valid here: */ // AOE_PROJECTILE, // AOE_SHOCK, // AOE_JUDGEMENT,