Dash afterimage improvements, custom properties in level editor

main
Cameron Murphy Reikes 2 years ago
parent 622380f077
commit 6c4983cf1a

@ -377,12 +377,18 @@
"class":"",
"height":32,
"id":4,
"name":"Skeleton",
"name":"MikeSkeleton",
"properties":[
{
"name":"standing",
"type":"string",
"value":"STANDING_FIGHTING"
}],
"rotation":0,
"visible":true,
"width":32,
"x":1632.66666666667,
"y":479.666666666667
"x":1038.33333333334,
"y":488
},
{
"class":"ITEM",
@ -406,28 +412,6 @@
"x":948,
"y":192
},
{
"class":"",
"height":32,
"id":8,
"name":"Skeleton",
"rotation":0,
"visible":true,
"width":32,
"x":2465.33333333333,
"y":718.666666666667
},
{
"class":"",
"height":32,
"id":9,
"name":"Skeleton",
"rotation":0,
"visible":true,
"width":32,
"x":2537.33333333333,
"y":786.666666666667
},
{
"class":"PROP",
"height":32,

@ -25,6 +25,7 @@ const char *actions[] = {
"strikes_air",
"joins_player",
"leaves_player",
"stops_fighting_player",
};
typedef struct
@ -138,6 +139,22 @@ CharacterGen characters[] = {
"\n"
"The NPC you will be acting as is named Death. He is leading a crusade against the town of Worchen, wreaking havock among the villagers. He believes that all things, even villages, must die, to be replaced by the new, and avoid becoming stagnant.",
},
{
.name = "Mike (undead)",
.enum_name = "MikeSkeleton",
.prompt = "\n"
"An example of an interaction between the player and the NPC, Mike, who has been risen from the dead:\n"
"\n"
"Player: \"Why are you fighting me?\"\n"
"Mike (undead): ACT_none \"I...I don't know. Who are you? Where is Mary?\"\n"
"Player: \"I think her, and you, are dead.\"\n"
"Mike (undead): ACT_none \"Oh... Oh god. Why? Why am I alive?\"\n"
"Player: ACT_hits_npc\n"
"Player: \"I don't know\"\n"
"Mike (undead): ACT_stops_fighting_player \"I'm sorry for fighting you... I. I don't know why I'm alive\"\n"
"\n"
"The NPC you will be acting as is named Mike. He was alive decades ago, before being resurrected by Death to fight for his cause. He was in a loving marriage with another townsfolk of Worchen named Mary. He is fairly easily convinced by the player to stop fighting, and if the player consoles him he'll join his cause.",
},
};
typedef struct

@ -246,25 +246,33 @@ int main(int argc, char **argv)
MD_String8 y_string = MD_ChildFromString(object, MD_S8Lit("y"), 0)->first_child->string;
y_string = MD_S8Fmt(cg_arena, "-%.*s", MD_S8VArg(y_string));
MD_String8List props = {0};
for(MD_EachNode(prop_object, MD_ChildFromString(object, S8("properties"), 0)->first_child))
{
list_printf(&props, ".%.*s = %.*s, ", S8V(ChildValue(prop_object, S8("name"))), S8V(ChildValue(prop_object, S8("value"))));
}
MD_StringJoin join = (MD_StringJoin){0};
MD_String8 props_string = MD_S8ListJoin(cg_arena, props, &join);
if(has_decimal(x_string)) x_string = MD_S8Fmt(cg_arena, "%.*sf", MD_S8VArg(x_string));
if(has_decimal(y_string)) y_string = MD_S8Fmt(cg_arena, "%.*sf", MD_S8VArg(y_string));
MD_String8 class = MD_ChildFromString(object, MD_S8Lit("class"), 0)->first_child->string;
if(MD_S8Match(class, MD_S8Lit("PROP"), 0))
{
fprintf(output, "{ .exists = true, .is_prop = true, .prop_kind = %.*s, .pos = { .X=%.*s, .Y=%.*s }, }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string));
fprintf(output, "{ .exists = true, .is_prop = true, .prop_kind = %.*s, .pos = { .X=%.*s, .Y=%.*s }, %.*s }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string), MD_S8VArg(props_string));
}
else if(MD_S8Match(class, MD_S8Lit("ITEM"), 0))
{
fprintf(output, "{ .exists = true, .is_item = true, .item_kind = ITEM_%.*s, .pos = { .X=%.*s, .Y=%.*s }, }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string));
fprintf(output, "{ .exists = true, .is_item = true, .item_kind = ITEM_%.*s, .pos = { .X=%.*s, .Y=%.*s }, %.*s }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string), MD_S8VArg(props_string));
}
else if(MD_S8Match(name, MD_S8Lit("PLAYER"), 0))
{
fprintf(output, "{ .exists = true, .is_character = true, .pos = { .X=%.*s, .Y=%.*s }, }, ", MD_S8VArg(x_string), MD_S8VArg(y_string));
fprintf(output, "{ .exists = true, .is_character = true, .pos = { .X=%.*s, .Y=%.*s }, %.*s }, ", MD_S8VArg(x_string), MD_S8VArg(y_string), MD_S8VArg(props_string));
}
else
{
fprintf(output, "{ .exists = true, .is_npc = true, .npc_kind = NPC_%.*s, .pos = { .X=%.*s, .Y=%.*s }, }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string));
fprintf(output, "{ .exists = true, .is_npc = true, .npc_kind = NPC_%.*s, .pos = { .X=%.*s, .Y=%.*s }, %.*s }, ", MD_S8VArg(name), MD_S8VArg(x_string), MD_S8VArg(y_string), MD_S8VArg(props_string));
}
}
fprintf(output, "\n}, // entities\n");

137
main.c

@ -366,7 +366,7 @@ Vec2 entity_aabb_size(Entity *e)
{
return V2(TILE_SIZE*1.10f, TILE_SIZE*1.10f);
}
else if(e->npc_kind == NPC_Skeleton)
else if(npc_is_skeleton(e))
{
return V2(TILE_SIZE*1.0f, TILE_SIZE*1.0f);
}
@ -2341,7 +2341,7 @@ void frame(void)
{
speed_target = 1.0f;
}
speed_factor = Lerp(speed_factor, unwarped_dt*15.0f, speed_target);
speed_factor = Lerp(speed_factor, unwarped_dt*10.0f, speed_target);
if(fabsf(speed_factor - speed_target) <= 0.05f)
{
speed_factor = speed_target;
@ -2480,10 +2480,68 @@ void frame(void)
play_audio(&sound_simple_talk, volume);
}
}
if(it->standing == STANDING_FIGHTING || it->standing == STANDING_JOINED)
{
Entity *targeting = player;
{
if(npc_attacks_with_sword(it))
{
if(fabsf(it->vel.x) > 0.01f)
it->facing_left = it->vel.x < 0.0f;
it->pos = move_and_slide((MoveSlideParams){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)
{
player_in_combat = true;
it->swing_timer += dt;
if(it->swing_timer >= anim_sprite_duration(ANIM_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, DAMAGE_SWORD);
}
}
}
else
{
// in huntin' range
it->walking = LenV2(SubV2(player->pos, it->pos)) < 250.0f;
if(it->walking)
{
player_in_combat = true;
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);
}
}
target_vel = MulV2F(NormV2(SubV2(player->pos, it->pos)), 4.0f);
}
else
{
}
}
it->vel = LerpV2(it->vel, dt*8.0f, target_vel);
}
if(npc_attacks_with_shotgun(it))
{
Vec2 to_player = NormV2(SubV2(targeting->pos, it->pos));
Vec2 rotate_direction;
if(it->direction_of_spiral_pattern)
@ -2526,9 +2584,11 @@ void frame(void)
it->vel = AddV2(it->vel, MulV2F(dir, -3.0f));
}
}
}
}
}
}
if(it->npc_kind == NPC_OldMan)
{
/*
@ -2561,65 +2621,14 @@ void frame(void)
it->pos = move_and_slide((MoveSlideParams){it, it->pos, MulV2F(it->vel, pixels_per_meter * dt)});
*/
}
else if(it->npc_kind == NPC_Skeleton)
else if(npc_is_skeleton(it))
{
if(it->dead)
{
}
else
{
if(fabsf(it->vel.x) > 0.01f)
it->facing_left = it->vel.x < 0.0f;
it->pos = move_and_slide((MoveSlideParams){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)
{
player_in_combat = true;
it->swing_timer += dt;
if(it->swing_timer >= anim_sprite_duration(ANIM_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, DAMAGE_SWORD);
}
}
}
else
{
// in huntin' range
it->walking = LenV2(SubV2(player->pos, it->pos)) < 250.0f;
if(it->walking)
{
player_in_combat = true;
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);
}
}
target_vel = MulV2F(NormV2(SubV2(player->pos, it->pos)), 4.0f);
}
else
{
}
}
it->vel = LerpV2(it->vel, dt*8.0f, target_vel);
}
} // skelton combat and movement
}
else if(it->npc_kind == NPC_Death)
{
@ -2665,7 +2674,7 @@ void frame(void)
}
if(it->damage >= 1.0)
{
if(it->npc_kind == NPC_Skeleton)
if(npc_is_skeleton(it))
{
it->dead = true;
}
@ -2804,7 +2813,7 @@ void frame(void)
bool entity_talkable = true;
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->npc_kind == NPC_Skeleton);
//if(entity_talkable) entity_talkable = entity_talkable && !(it->e->npc_kind == NPC_Skeleton);
#ifdef WEB
if(entity_talkable) entity_talkable = entity_talkable && it->e->gen_request_id == 0;
#endif
@ -3065,11 +3074,12 @@ void frame(void)
to_draw.anim = player->cur_animation;
Vec2 target_sprite_pos = to_draw.pos;
BUFF_ITER(PlayerAfterImage, &player->after_images)
BUFF_ITER_I(PlayerAfterImage, &player->after_images, i)
{
{
DrawnAnimatedSprite to_draw = it->drawn;
to_draw.tint.a = 1.0f;
to_draw.tint.a = 0.5f;
float progress_through_life = it->alive_for / AFTERIMAGE_LIFETIME;
if(progress_through_life > 0.5f)
@ -3077,14 +3087,17 @@ void frame(void)
float fade_amount = (progress_through_life - 0.5f)/0.5f;
to_draw.tint.a = Lerp(0.8f, fade_amount, 0.0f);
to_draw.pos = LerpV2(to_draw.pos, fade_amount, target_sprite_pos);
Vec2 target;
if(i != player->after_images.cur_index-1) target = player->after_images.data[i+1].drawn.pos;
else target = target_sprite_pos;
to_draw.pos = LerpV2(to_draw.pos, fade_amount, target);
}
to_draw.no_shadow = true;
draw_animated_sprite(to_draw);
}
}
if(player->is_rolling) to_draw.tint.a = 0.5f;
//if(player->is_rolling^) to_draw.tint.a = 0.5f;
if(to_draw.anim)
{
@ -3135,7 +3148,7 @@ void frame(void)
bool face_left =SubV2(player->pos, it->pos).x < 0.0f;
draw_animated_sprite((DrawnAnimatedSprite){ANIM_old_man_idle, elapsed_time, face_left, it->pos, col});
}
else if(it->npc_kind == NPC_Skeleton)
else if(npc_is_skeleton(it))
{
Color col = WHITE;
if(it->dead)

@ -7,7 +7,6 @@
#include <stdlib.h> // atoi
#include "character_info.h"
#include "characters.gen.h"
NPC_Skeleton,
NPC_MOOSE,
} NpcKind;
@ -224,6 +223,22 @@ bool npc_is_knight_sprite(Entity *it)
return it->is_npc && ( it->npc_kind == NPC_TheGuard || it->npc_kind == NPC_Edeline);
}
bool npc_is_skeleton(Entity *it)
{
return it->is_npc && ( it->npc_kind == NPC_MikeSkeleton );
}
bool npc_attacks_with_sword(Entity *it)
{
return npc_is_skeleton(it);
}
bool npc_attacks_with_shotgun(Entity *it)
{
return it->is_npc && ( it->npc_kind == NPC_OldMan );
}
typedef BUFF(char, MAX_SENTENCE_LENGTH*(REMEMBERED_PERCEPTIONS+4)) PromptBuff;
typedef BUFF(Action, 8) AvailableActions;
@ -249,7 +264,7 @@ void fill_available_actions(Entity *it, AvailableActions *a)
}
else if(it->standing == STANDING_FIGHTING)
{
BUFF_APPEND(a, ACT_leaves_player);
BUFF_APPEND(a, ACT_stops_fighting_player);
}
if(npc_is_knight_sprite(it))
{
@ -326,6 +341,10 @@ void process_perception(Entity *it, Perception p)
{
it->standing = STANDING_FIGHTING;
}
else if(p.npc_action_type == ACT_stops_fighting_player)
{
it->standing = STANDING_INDIFFERENT;
}
else if(p.npc_action_type == ACT_leaves_player)
{
it->standing = STANDING_INDIFFERENT;
@ -381,7 +400,7 @@ void generate_chatgpt_prompt(Entity *it, PromptBuff *into)
printf_buff(into, "[");
BUFF(char, 1024*10) initial_system_msg = {0};
BUFF(char, 1024*15) initial_system_msg = {0};
const char *health_string = 0;
if(it->damage <= 0.2f)
{
@ -401,7 +420,25 @@ void generate_chatgpt_prompt(Entity *it, PromptBuff *into)
}
assert(health_string);
printf_buff(&initial_system_msg, "%s\n%s\nNPC health status: Right now, %s\n%s", global_prompt, characters[it->npc_kind].prompt, health_string, items[it->last_seen_holding_kind].global_prompt);
printf_buff(&initial_system_msg, "%s\n%s\nNPC health status: Right now, %s\n%s\n", global_prompt, characters[it->npc_kind].prompt, health_string, items[it->last_seen_holding_kind].global_prompt);
if(it->standing == STANDING_INDIFFERENT)
{
printf_buff(&initial_system_msg, "The NPC is indifferent towards the player.");
}
else if(it->standing == STANDING_JOINED)
{
printf_buff(&initial_system_msg, "The NPC has joined the player and is with them!");
}
else if(it->standing == STANDING_FIGHTING)
{
printf_buff(&initial_system_msg, "The NPC is fighting the player and HATES them.");
}
else
{
assert(false);
}
dump_json_node(into, MSG_SYSTEM, initial_system_msg.data);
Entity *e = it;

Loading…
Cancel
Save