Add skeleton enemies

main
parent 1bf8487ea6
commit 7d131a1931

@ -58,6 +58,10 @@
{
filepath: "drop_shadow.png",
}
@image skeleton:
{
filepath: "copyrighted/skeleton.png",
}
@image shift_icon:
{
filepath: "shift_icon.png",

@ -348,8 +348,8 @@
"rotation":0,
"visible":true,
"width":32,
"x":958.999999999997,
"y":913.333333333337
"x":1528.66666666667,
"y":748.333333333337
},
{
"class":"",
@ -359,8 +359,52 @@
"rotation":0,
"visible":true,
"width":32,
"x":1287.33333333333,
"y":748.666666666666
"x":1258,
"y":732.666666666666
},
{
"class":"",
"height":32,
"id":6,
"name":"SKELETON",
"rotation":0,
"visible":true,
"width":32,
"x":1637,
"y":921.833333333333
},
{
"class":"",
"height":32,
"id":7,
"name":"SKELETON",
"rotation":0,
"visible":true,
"width":32,
"x":1721.33333333333,
"y":1098.66666666667
},
{
"class":"",
"height":32,
"id":8,
"name":"SKELETON",
"rotation":0,
"visible":true,
"width":32,
"x":1652,
"y":1224
},
{
"class":"",
"height":32,
"id":9,
"name":"SKELETON",
"rotation":0,
"visible":true,
"width":32,
"x":1716,
"y":1222.66666666667
}],
"opacity":1,
"type":"objectgroup",
@ -369,7 +413,7 @@
"y":0
}],
"nextlayerid":8,
"nextobjectid":6,
"nextobjectid":10,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.9.2",

@ -5,7 +5,13 @@ mkdir build_web
call run_codegen.bat || goto :error
emcc -sEXPORTED_FUNCTIONS=_main,_end_text_input -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -O0 -s ALLOW_MEMORY_GROWTH --source-map-base . -gsource-map -DDEVTOOLS -Ithirdparty -Igen main.c -o build_web\index.html --preload-file assets --shell-file web_template.html || goto :error
@REM set FLAGS=-fsanitize=undefined -fsanitize=address
@REM GO FUCK YOURSELF
set FLAGS=-s TOTAL_STACK=5242880
@echo on
emcc -sEXPORTED_FUNCTIONS=_main,_end_text_input -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -O0 -s ALLOW_MEMORY_GROWTH %FLAGS% --source-map-base ../ -gsource-map -DDEVTOOLS -Ithirdparty -Igen main.c -o build_web\index.html --preload-file assets --shell-file web_template.html || goto :error
@echo off
goto :EOF

@ -5,8 +5,11 @@ mkdir build_web_release
call run_codegen.bat || goto :error
@REM GO FUCK YOURSELF
set FLAGS=-s TOTAL_STACK=5242880
echo Building release
emcc -sEXPORTED_FUNCTIONS=_main,_end_text_input -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -DNDEBUG -O2 -s ALLOW_MEMORY_GROWTH -Ithirdparty -Igen main.c -o build_web_release\index.html --preload-file assets --shell-file web_template.html || goto :error
emcc -sEXPORTED_FUNCTIONS=_main,_end_text_input -sEXPORTED_RUNTIME_METHODS=ccall,cwrap -DNDEBUG -O2 -s ALLOW_MEMORY_GROWTH %FLAGS% -Ithirdparty -Igen main.c -o build_web_release\index.html --preload-file assets --shell-file web_template.html || goto :error
goto :EOF

267
main.c

@ -23,10 +23,10 @@
#include <math.h>
#define PROFILING_IMPL
#ifdef DEVTOOLS
#ifdef DESKTOP
#define PROFILING
#define PROFILING_IMPL
#endif
#endif
#include "profiling.h"
@ -98,6 +98,7 @@ typedef struct AnimatedSprite
double time_per_frame;
int num_frames;
Vec2 start;
Vec2 offset;
float horizontal_diff_btwn_frames;
Vec2 region_size;
bool no_wrap; // does not wrap when playing
@ -152,6 +153,7 @@ typedef enum NpcKind
{
OLD_MAN,
DEATH,
SKELETON,
} NpcKind;
typedef struct Entity
@ -163,6 +165,8 @@ typedef struct Entity
Vec2 vel; // only used sometimes, like in old man and bullet
float damage; // at 1.0, dead! zero initialized
bool facing_left;
// multiple entities have a sword swing
BUFF(struct Entity*, 8) done_damage_to_this_swing; // only do damage once, but hitbox stays around
bool is_bullet;
@ -180,12 +184,13 @@ typedef struct Entity
// only for death npc
bool going_to_target;
Vec2 target_goto;
// only for skeleton npc
double swing_timer;
// character
bool is_character;
CharacterState state;
struct Entity *talking_to; // Maybe should be generational index, but I dunno. No death yet
BUFF(struct Entity*, 8) done_damage_to_this_swing; // only do damage once, but hitbox stays around
bool is_rolling; // can only roll in idle or walk states
double time_not_rolling; // for cooldown for roll, so you can't just hold it and be invincible
double roll_progress;
@ -498,6 +503,54 @@ char *tprint(const char *format, ...)
return to_return;
}
AABB entity_sword_aabb(Entity *e, float width, float height)
{
if(e->facing_left)
{
return (AABB){
.upper_left = AddV2(e->pos, V2(-width, height)),
.lower_right = AddV2(e->pos, V2(0.0, -height)),
};
}
else
{
return (AABB){
.upper_left = AddV2(e->pos, V2(0.0, height)),
.lower_right = AddV2(e->pos, V2(width, -height)),
};
}
}
typedef BUFF(Entity*, 16) SwordToDamage;
SwordToDamage entity_sword_to_do_damage(Entity *from, Overlapping o)
{
SwordToDamage to_return = {0};
BUFF_ITER(Overlap, &o)
{
if(!it->is_tile && it->e != from)
{
bool done_damage = false;
Entity *looking_for = it->e;
BUFF_ITER(Entity*, &from->done_damage_to_this_swing)
{
if(*it == looking_for) done_damage = true;
}
if(!done_damage)
{
if(!BUFF_HAS_SPACE(&from->done_damage_to_this_swing))
{
BUFF_REMOVE_FRONT(&from->done_damage_to_this_swing);
Log("Too many things to do damage to...\n");
assert(false);
}
BUFF_APPEND(&to_return, looking_for);
BUFF_APPEND(&from->done_damage_to_this_swing, looking_for);
}
}
}
return to_return;
}
Vec2 entity_aabb_size(Entity *e)
{
if(e->is_character == ENTITY_PLAYER)
@ -514,6 +567,10 @@ Vec2 entity_aabb_size(Entity *e)
{
return V2(TILE_SIZE*1.10f, TILE_SIZE*1.10f);
}
else if(e->npc_kind == SKELETON)
{
return V2(TILE_SIZE*1.0f, TILE_SIZE*1.0f);
}
else
{
assert(false);
@ -705,6 +762,37 @@ AnimatedSprite death_idle =
.horizontal_diff_btwn_frames = 100.0f,
.region_size = {100.0f, 100.0f},
};
AnimatedSprite skeleton_idle =
{
.img = &image_skeleton,
.time_per_frame = 0.15,
.num_frames = 6,
.start = {0.0f, 0.0f},
.horizontal_diff_btwn_frames = 80.0,
.offset = {0.0f, 20.0f},
.region_size = {80.0f, 80.0f},
};
AnimatedSprite skeleton_swing_sword =
{
.img = &image_skeleton,
.time_per_frame = 0.10,
.num_frames = 6,
.start = {0.0f, 240.0f},
.horizontal_diff_btwn_frames = 80.0,
.offset = {0.0f, 20.0f},
.region_size = {80.0f, 80.0f},
};
AnimatedSprite skeleton_run =
{
.img = &image_skeleton,
.time_per_frame = 0.07,
.num_frames = 8,
.start = {0.0f, 160.0f},
.horizontal_diff_btwn_frames = 80.0,
.offset = {0.0f, 20.0f},
.region_size = {80.0f, 80.0f},
};
sg_image image_font = {0};
float font_line_advance = 0.0f;
@ -1129,7 +1217,7 @@ Vec2 into_clip_space(Vec2 screen_space_point)
// The image region is in pixel space of the image
void draw_quad(DrawParams d)
{
PROFILE_SCOPE("quad")
PROFILE_SCOPE("Draw quad")
{
quad_fs_params_t params = {0};
params.tint[0] = d.tint.R;
@ -1258,6 +1346,7 @@ double anim_sprite_duration(AnimatedSprite *s)
void draw_animated_sprite(AnimatedSprite *s, double elapsed_time, bool flipped, Vec2 pos, Color tint)
{
pos = AddV2(pos, s->offset);
sg_image spritesheet_img = *s->img;
int index = (int)floor(elapsed_time/s->time_per_frame) % s->num_frames;
if(s->no_wrap)
@ -1687,48 +1776,51 @@ void draw_dialog_panel(Entity *talking_to)
float new_line_height = dialog_panel.lower_right.Y;
int i = 0;
//BUFF_ITER(Sentence, &talking_to->player_dialog)
BUFF_ITER_EX(Sentence, &talking_to->player_dialog, talking_to->player_dialog.cur_index-1, it >= &talking_to->player_dialog.data[0], it--)
if(talking_to->player_dialog.cur_index > 0)
{
bool player_talking = i % 2 != 0; // iterating backwards
Color *colors = calloc(sizeof(*colors), it->cur_index);
bool in_astrix = false;
for(int char_i = 0; char_i < it->cur_index; char_i++)
BUFF_ITER_EX(Sentence, &talking_to->player_dialog, talking_to->player_dialog.cur_index-1, it >= &talking_to->player_dialog.data[0], it--)
{
bool set_in_astrix_false = false;
if(it->data[char_i] == '*')
bool player_talking = i % 2 != 0; // iterating backwards
Color *colors = calloc(sizeof(*colors), it->cur_index);
bool in_astrix = false;
for(int char_i = 0; char_i < it->cur_index; char_i++)
{
if(in_astrix)
bool set_in_astrix_false = false;
if(it->data[char_i] == '*')
{
set_in_astrix_false = true;
if(in_astrix)
{
set_in_astrix_false = true;
}
else
{
in_astrix = true;
}
}
else
if(player_talking)
{
in_astrix = true;
}
}
if(player_talking)
{
colors[char_i] = BLACK;
}
else
{
if(in_astrix)
{
colors[char_i] = colhex(0xffdf24);
colors[char_i] = BLACK;
}
else
{
colors[char_i] = colhex(0x345e22);
if(in_astrix)
{
colors[char_i] = colhex(0xffdf24);
}
else
{
colors[char_i] = colhex(0x345e22);
}
}
if(set_in_astrix_false) in_astrix = false;
}
if(set_in_astrix_false) in_astrix = false;
}
float measured_line_height = draw_wrapped_text(true, V2(dialog_panel.upper_left.X, new_line_height), dialog_panel.lower_right.X - dialog_panel.upper_left.X, it->data, colors, 0.5f, true, dialog_panel);
new_line_height += (new_line_height - measured_line_height);
draw_wrapped_text(false, V2(dialog_panel.upper_left.X, new_line_height), dialog_panel.lower_right.X - dialog_panel.upper_left.X, it->data, colors, 0.5f, true, dialog_panel);
float measured_line_height = draw_wrapped_text(true, V2(dialog_panel.upper_left.X, new_line_height), dialog_panel.lower_right.X - dialog_panel.upper_left.X, it->data, colors, 0.5f, true, dialog_panel);
new_line_height += (new_line_height - measured_line_height);
draw_wrapped_text(false, V2(dialog_panel.upper_left.X, new_line_height), dialog_panel.lower_right.X - dialog_panel.upper_left.X, it->data, colors, 0.5f, true, dialog_panel);
free(colors);
i++;
free(colors);
i++;
}
}
dbgrect(dialog_panel);
@ -1953,6 +2045,8 @@ void frame(void)
}
}
#endif
if(fabsf(it->vel.x) > 0.01f)
it->facing_left = it->vel.x < 0.0f;
if(it->is_npc)
{
@ -1970,7 +2064,7 @@ void frame(void)
{
it->pos = LerpV2(it->pos, dt*5.0f, it->target_goto);
}
if(it->aggressive)
if(it->npc_kind == OLD_MAN && it->aggressive)
{
draw_dialog_panel(it);
Entity *targeting = player;
@ -2004,7 +2098,67 @@ void frame(void)
Color col = LerpV4(WHITE, it->damage, RED);
if(it->npc_kind == OLD_MAN)
{
draw_animated_sprite(&old_man_idle, elapsed_time, false, it->pos, col);
bool face_left = false;
if(it->aggressive)
{
face_left = SubV2(player->pos, it->pos).x < 0.0f;
}
draw_animated_sprite(&old_man_idle, elapsed_time, face_left, it->pos, col);
}
else if(it->npc_kind == SKELETON)
{
if(fabsf(it->vel.x) > 0.01f)
it->facing_left = it->vel.x < 0.0f;
Color col = WHITE;
it->pos = move_and_slide(it, it->pos, MulV2F(it->vel, pixels_per_meter * dt));
AABB weapon_aabb = entity_sword_aabb(it, 30.0f, 18.0f);
dbgrect(weapon_aabb);
Vec2 target_vel = {0};
it->pos = AddV2(it->pos, MulV2F(it->vel, dt));
Overlapping overlapping_weapon = get_overlapping(cur_level, weapon_aabb);
if(it->swing_timer > 0.0)
{
// swinging sword
draw_animated_sprite(&skeleton_swing_sword, it->swing_timer, it->facing_left, it->pos, col);
it->swing_timer += dt;
if(it->swing_timer >= anim_sprite_duration(&skeleton_swing_sword))
{
it->swing_timer = 0.0;
}
if(it->swing_timer >= 0.4f)
{
SwordToDamage to_damage = entity_sword_to_do_damage(it, overlapping_weapon);
Entity *from = it;
BUFF_ITER(Entity *, &to_damage)
{
request_do_damage(*it, from->pos, 0.2f);
}
}
}
else
{
// in huntin' range
if(LenV2(SubV2(player->pos, it->pos)) < 250.0f)
{
Entity *skele = it;
BUFF_ITER(Overlap, &overlapping_weapon)
{
if(it->e && it->e->is_character)
{
skele->swing_timer += dt;
BUFF_CLEAR(&skele->done_damage_to_this_swing);
}
}
draw_animated_sprite(&skeleton_run, elapsed_time, it->facing_left, it->pos, col);
target_vel = MulV2F(NormV2(SubV2(player->pos, it->pos)), 4.0f);
}
else
{
draw_animated_sprite(&skeleton_idle, elapsed_time, it->facing_left, it->pos, col);
}
}
it->vel = LerpV2(it->vel, dt*8.0f, target_vel);
}
else if(it->npc_kind == DEATH)
{
@ -2069,6 +2223,7 @@ void frame(void)
if(entity_talkable) entity_talkable = entity_talkable && !it->is_tile;
if(entity_talkable) entity_talkable = entity_talkable && it->e->is_npc;
if(entity_talkable) entity_talkable = entity_talkable && !it->e->aggressive;
if(entity_talkable) entity_talkable = entity_talkable && !(it->e->npc_kind == SKELETON);
#ifdef WEB
if(entity_talkable) entity_talkable = entity_talkable && it->e->gen_request_id == 0;
#endif
@ -2189,8 +2344,6 @@ draw_dialog_panel(talking_to);
}
else
{
if(fabsf(player->vel.x) > 0.01f)
player->facing_left = player->vel.x < 0.0f;
}
}
else if(player->state == CHARACTER_IDLE)
@ -2207,44 +2360,12 @@ draw_dialog_panel(talking_to);
}
else if(player->state == CHARACTER_ATTACK)
{
AABB weapon_aabb = {0};
if(player->facing_left)
{
weapon_aabb = (AABB){
.upper_left = AddV2(player->pos, V2(-40.0, 25.0)),
.lower_right = AddV2(player->pos, V2(0.0, -25.0)),
};
}
else
{
weapon_aabb = (AABB){
.upper_left = AddV2(player->pos, V2(0.0, 25.0)),
.lower_right = AddV2(player->pos, V2(40.0, -25.0)),
};
}
AABB weapon_aabb = entity_sword_aabb(player, 40.0f, 25.0f);
dbgrect(weapon_aabb);
Overlapping overlapping_weapon = get_overlapping(cur_level, weapon_aabb);
BUFF_ITER(Overlap, &overlapping_weapon)
SwordToDamage to_damage = entity_sword_to_do_damage(player, get_overlapping(cur_level, weapon_aabb));
BUFF_ITER(Entity*, &to_damage)
{
if(!it->is_tile && it->e != player)
{
bool done_damage = false;
Entity *looking_for = it->e;
BUFF_ITER(Entity*, &player->done_damage_to_this_swing)
{
if(*it == looking_for) done_damage = true;
}
if(!done_damage)
{
if(!BUFF_HAS_SPACE(&player->done_damage_to_this_swing))
{
BUFF_REMOVE_FRONT(&player->done_damage_to_this_swing);
Log("Too many things to do damage to...\n");
}
BUFF_APPEND(&player->done_damage_to_this_swing, looking_for);
request_do_damage(it->e, player->pos, 0.2f);
}
}
request_do_damage(*it, player->pos, 0.2f);
}
player->swing_progress += dt;

@ -101,5 +101,5 @@ void init_profiling_mythread(uint32_t id) { (void)id; }
void end_profiling() {}
void end_profiling_mythread() {}
#define PROFILE_SCOPE(name) DeferLoop((void)0, (void)0) // so loop stuff in it doesn't break
#define PROFILE_SCOPE(name) for(int _i_ = 0; _i_ == 0; _i_ += 1)
#endif

@ -13,6 +13,7 @@ copy "EPIC RPG World Pack - Ancient Ruins V 1.7\EPIC RPG World Pack - Ancient Ru
copy "EPIC RPG World Pack - Ancient Ruins V 1.7\EPIC RPG World Pack - Ancient Ruins V 1.7\TiledMap Editor\Terrain - Ancient Ruins.tsx" "assets\copyrighted\ruins_ancient.tsx" || goto :error
copy "EPIC RPG World Pack - Ancient Ruins V 1.7\EPIC RPG World Pack - Ancient Ruins V 1.7\Tilesets\Tileset-Terrain.png" "assets\copyrighted\ruins_ancient.png" || goto :error
copy "Undead - Pixel Art Characters\Undead - Pixel Art Characters\Sprites\Wraith_Red.png" "assets\copyrighted\wraith.png" || goto :error
copy "Undead - Pixel Art Characters\Undead - Pixel Art Characters\Sprites\Skeleton_Blue.png" "assets\copyrighted\skeleton.png" || goto :error
rmdir /S /q gen
mkdir gen

Loading…
Cancel
Save