Skip to content

Commit cc57404

Browse files
committed
Adds potions to monster drops
Potions will proved an effect that lasts until the player moves to the next level. So far there's a frost potion which adds armor and makes one immune to tile effects (fire, gas) and a bloodlust potion which is essentially quad damage. This might make the player slightly OP. But this late. I don't think anyone will complain. A maximum of one potion will drop per level. Future potions might be: - Levitation: Avoid pits (white) - Speed: Rogue move speed (yellow) - Barkskin: Armor (brown) - Extra life: Avoid one death (green)
1 parent dfed896 commit cc57404

File tree

13 files changed

+149
-22
lines changed

13 files changed

+149
-22
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ root = true
22

33
[*]
44
insert_final_newline = true
5+
trim_trailing_whitespace = true
56

67
[*.{c,h}]
78
charset = utf-8

.vimrc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ packadd termdebug
77
let g:termdebug_wide = 1
88

99
" INDENTING:
10-
set tabstop=4
11-
set shiftwidth=4
1210
set noexpandtab " tabs are tabs, not spaces
11+
set copyindent
12+
set softtabstop=0
13+
set tabstop=8
14+
set shiftwidth=8
1315

1416
au FileType c,h setl tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab

src/item.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,20 @@
2727
#include "camera.h"
2828
#include "linkedlist.h"
2929

30+
/**
31+
* \brief A game item struct
32+
*/
3033
typedef struct Item_t {
31-
Sprite *sprite;
32-
LinkedList *subsprites;
33-
bool collected;
34-
bool openable;
35-
bool opened;
36-
char label[50];
37-
double price;
38-
double value;
39-
LinkedList *items;
40-
void (*effect)(struct Item_t *, Player *);
34+
Sprite *sprite; /**< The item sprite */
35+
LinkedList *subsprites; /**< A list of sub-sprites */
36+
bool collected; /**< If the item has been collected */
37+
bool openable; /**< Can the item be opened? */
38+
bool opened; /**< Has the item been opened? */
39+
char label[50]; /**< The Item label */
40+
double price; /**< The item price (for vendor) */
41+
double value; /**< Value, the item value. Eg. Gold */
42+
LinkedList *items; /**< Sub items */
43+
void (*effect)(struct Item_t *, Player *); /**< Item effect callback */
4144
} Item;
4245

4346
Item *

src/item_builder.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,52 @@ item_builder_build_key(unsigned int type)
196196
return item;
197197
}
198198

199+
static void
200+
pickup_bloodlust(Item *item, Player *player)
201+
{
202+
gui_log("You drink a bloodlust potion. Rage pulses through your veins.");
203+
player->effects.effect = POTION_BLOODLUST;
204+
player->effects.damage_multiplier = 4;
205+
sprite_set_color_mod(player->sprite, 255, 25, 45);
206+
}
207+
208+
static void
209+
pickup_frost(Item *item, Player *player)
210+
{
211+
gui_log("You drink a frost potion. Your skin is ice.");
212+
player->effects.effect = POTION_FROST;
213+
player->effects.damage_reduction = 2 * player->stats.lvl;
214+
sprite_set_color_mod(player->sprite, 94, 156, 255);
215+
}
216+
217+
Item *
218+
item_builder_build_potion(PotionEffect effect)
219+
{
220+
Item *item;
221+
222+
assert(effect != POTION_NONE);
223+
224+
switch (effect) {
225+
case POTION_BLOODLUST:
226+
item = create_item("Items/Potion.png",
227+
NULL,
228+
CLIP16(48, 32),
229+
pickup_bloodlust);
230+
break;
231+
case POTION_FROST:
232+
item = create_item("Items/Potion.png",
233+
NULL,
234+
CLIP16(96, 0),
235+
pickup_frost);
236+
break;
237+
case POTION_NONE:
238+
default:
239+
break;
240+
}
241+
242+
return item;
243+
}
244+
199245
static Item *
200246
create_treasure(int current_level)
201247
{

src/item_builder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ item_builder_build_treasure(Treasure type, double goldAmt);
5959
Item *
6060
item_builder_build_key(unsigned int type);
6161

62+
Item *
63+
item_builder_build_potion(PotionEffect type);
64+
6265
void
6366
item_builder_close(void);
6467

src/monster.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ has_collided(Monster *monster, RoomMatrix *matrix, Vector2d direction)
321321
CombatResult result = stats_fight(&monster->stats,
322322
&space->player->stats);
323323

324+
result.dmg -= space->player->effects.damage_reduction;
325+
324326
player_hit(space->player, result.dmg);
325327

326328
if (result.dmg > 0) {
@@ -530,7 +532,7 @@ monster_coward_walk(Monster *m, RoomMatrix *rm)
530532
static void
531533
on_monster_move(Monster *m, const Position *origPos, Map *map, RoomMatrix *rm)
532534
{
533-
Position currentTilePos = position_to_matrix_coords(&m->sprite->pos);
535+
Position currentTilePos = position_to_matrix_coords(&m->sprite->pos);
534536
Player *player = rm->spaces[rm->playerRoomPos.x][rm->playerRoomPos.y].player;
535537
if (player) {
536538
Uint32 range = 3 + player_has_artifact(player, IMPROVED_HEARING) * 2;
@@ -780,14 +782,14 @@ monster_update_stats_for_level(Monster *m, unsigned int level)
780782
void
781783
monster_drop_loot(Monster *monster, Map *map, Player *player)
782784
{
783-
static unsigned int treasure_drop_chance = 1;
784-
unsigned int item_drop_chance = 1;
785+
static Uint32 treasure_drop_chance = 1;
786+
static Uint32 item_drop_chance = 1;
787+
static Uint32 potion_drop_chance = 30;
785788

786789
if (monster->sprite->state == SPRITE_STATE_FALLING)
787790
return;
788791

789792
Item *item;
790-
Item *items[3];
791793
unsigned int item_count = 0;
792794
bool player_full_health = player->stats.hp >= player->stats.maxhp;
793795

@@ -831,6 +833,17 @@ monster_drop_loot(Monster *monster, Map *map, Player *player)
831833
if (player->stats.hp < player->stats.maxhp / 2)
832834
item_drop_chance = 0;
833835

836+
/* TODO: This hardcoded size is a bit risky. Capacity is good but
837+
* perhaps a dynamic array would be safer just in case? */
838+
Item *items[4];
839+
if (player_has_potion_effect(player, POTION_NONE) && get_random(potion_drop_chance) == 0) {
840+
if (get_random(1) == 0)
841+
item = item_builder_build_potion(POTION_BLOODLUST);
842+
else
843+
item = item_builder_build_potion(POTION_FROST);
844+
item->sprite->pos = monsterTilePos;
845+
items[item_count++] = item;
846+
}
834847
if (get_random(treasure_drop_chance) == 0) {
835848
item = item_builder_build_item(TREASURE, map->level);
836849
item->sprite->pos = monsterTilePos;

src/object.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "object.h"
20+
#include "gui.h"
2021
#include "util.h"
2122
#include "mixer.h"
2223
#include "random.h"
@@ -85,6 +86,10 @@ object_damage(Object *o, Player *p)
8586
{
8687
if (!o->damage)
8788
return;
89+
if (player_has_potion_effect(p, POTION_FROST)) {
90+
gui_log("Your frost skin protects you from damage");
91+
return;
92+
}
8893
p->stats.hp -= o->damage;
8994
player_hit(p, o->damage);
9095
}

src/player.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ on_monster_collision(Player *player,
137137
CombatResult result = stats_fight(&player->stats,
138138
&monster->stats);
139139

140+
if (player->effects.damage_multiplier > 0) {
141+
result.dmg *= player->effects.damage_multiplier;
142+
}
143+
140144
mixer_play_effect(SWING0 + get_random(2));
141145
monster_hit(monster, result.dmg, result.critical);
142146
animation_run(player->swordAnimation);
@@ -233,7 +237,7 @@ player_has_collided(Player *p, RoomSpace *space)
233237
return !p->phase_count && space->monster && space->monster->sprite->state != SPRITE_STATE_FALLING;
234238
}
235239

236-
static bool
240+
static bool
237241
has_collided(Player *player, RoomMatrix *matrix, Vector2d direction)
238242
{
239243
Position roomCoord = position_to_room_coords(&player->sprite->pos);
@@ -514,7 +518,7 @@ build_sword_animation(Player *p, SDL_Renderer *renderer)
514518
p->swordAnimation->sprite->rotationPoint = (SDL_Point) { 16, 16 };
515519
}
516520

517-
Player*
521+
Player*
518522
player_create(class_t class, Camera *cam)
519523
{
520524
Player *player = malloc(sizeof(Player));
@@ -547,6 +551,7 @@ player_create(class_t class, Camera *cam)
547551

548552
memset(&player->skills,
549553
0, PLAYER_SKILL_COUNT * sizeof(Skill*));
554+
memset(&player->effects, 0, sizeof(PlayerEffects));
550555

551556
for (size_t i = 0; i < LAST_ARTIFACT_EFFECT; ++i)
552557
player->equipment.artifacts[i].level = 0;
@@ -602,6 +607,12 @@ player_reset_on_levelchange(Player *player)
602607
player->sprite->pos = (Position) {
603608
TILE_DIMENSION, TILE_DIMENSION };
604609
player->equipment.keys = 0;
610+
611+
/* Reset all active potions */
612+
memset(&player->effects, 0, sizeof(PlayerEffects));
613+
614+
/* Reset the player sprite */
615+
sprite_set_color_mod(player->sprite, 255, 255, 255);
605616
}
606617

607618
ExperienceData
@@ -823,6 +834,12 @@ player_add_artifact(Player *p, Artifact *a)
823834
p->equipment.hasArtifacts = true;
824835
}
825836

837+
bool
838+
player_has_potion_effect(Player *p, PotionEffect effect)
839+
{
840+
return effect == p->effects.effect;
841+
}
842+
826843
void
827844
player_set_falling(Player *player)
828845
{

src/player.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ typedef struct Animation Animation;
3636
typedef enum PlayerClass { ENGINEER, MAGE, PALADIN, ROGUE, WARRIOR } class_t;
3737
typedef enum PlayerState { ALIVE, DEAD } state_t;
3838

39+
typedef enum {
40+
POTION_NONE,
41+
POTION_FROST,
42+
POTION_BLOODLUST
43+
} PotionEffect;
44+
3945
typedef struct PlayerStatData {
4046
unsigned int total_steps;
4147
unsigned int steps;
@@ -67,6 +73,12 @@ typedef struct PlayerStateData {
6773
bool shopOwnerKiller;
6874
} PlayerStateData;
6975

76+
typedef struct PlayerEffects {
77+
PotionEffect effect;
78+
uint8_t damage_multiplier;
79+
uint8_t damage_reduction;
80+
} PlayerEffects;
81+
7082
typedef struct Player {
7183
Sprite *sprite;
7284
Stats stats;
@@ -84,6 +96,7 @@ typedef struct Player {
8496
Animation *swordAnimation;
8597
PlayerEquipment equipment;
8698
PlayerStateData stateData;
99+
PlayerEffects effects;
87100
} Player;
88101

89102
Player*
@@ -137,5 +150,8 @@ player_has_artifact(Player *, MagicalEffect);
137150
void
138151
player_add_artifact(Player*, Artifact*);
139152

153+
bool
154+
player_has_potion_effect(Player*, PotionEffect);
155+
140156
void
141157
player_set_falling(Player*);

src/sprite.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ sprite_create(void)
5353
return sprite_create_default();
5454
}
5555

56-
void
56+
void
5757
sprite_load_texture(Sprite *sprite,
5858
const char *path,
5959
int index,
@@ -116,6 +116,15 @@ sprite_set_alpha(Sprite *s, Uint8 alpha)
116116
texture_set_alpha(s->textures[1], alpha);
117117
}
118118

119+
void
120+
sprite_set_color_mod(Sprite *s, Uint8 r, Uint8 g, Uint8 b)
121+
{
122+
if (s->textures[0])
123+
texture_set_color_mod(s->textures[0], r, g, b);
124+
if (s->textures[1])
125+
texture_set_color_mod(s->textures[1], r, g, b);
126+
}
127+
119128
void
120129
sprite_update(Sprite *s, UpdateData *data)
121130
{

0 commit comments

Comments
 (0)