diff --git a/art/art.zip b/art/art.zip index 51b1ab9..6ac6a3d 100644 Binary files a/art/art.zip and b/art/art.zip differ diff --git a/assets.mdesk b/assets.mdesk index e6144e1..5061be1 100644 --- a/assets.mdesk +++ b/assets.mdesk @@ -6,6 +6,10 @@ { filepath: "maninblack.png", } +@image angel: +{ + filepath: "angel.png", +} @image unread_triangle: { filepath: "unread_triangle.png", @@ -22,6 +26,10 @@ { filepath: "simple_text_chirp.wav", } +@sound angel_grunt_0: +{ + filepath: "angel_grunt_0.wav", +} @sound grunt_0: { filepath: "grunt_0.wav", diff --git a/assets/angel.png b/assets/angel.png new file mode 100644 index 0000000..f779340 --- /dev/null +++ b/assets/angel.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:65cd1a7ef0edb2cc157a9d9642d56ec1ff5639ef7d9ad2ab5a4561de37e0823c +size 1249809 diff --git a/assets/angel_grunt_0.wav b/assets/angel_grunt_0.wav new file mode 100644 index 0000000..8b29b01 Binary files /dev/null and b/assets/angel_grunt_0.wav differ diff --git a/assets/drama.mdesk b/assets/drama.mdesk index 9996126..1639d2f 100644 --- a/assets/drama.mdesk +++ b/assets/drama.mdesk @@ -32,6 +32,10 @@ {enum: Daniel, dialog: "Exactly what I'll do to you if you don't keep your mouth shut", to: Raphael, action: ACT_put_shotgun_away} {enum: Raphael, dialog: "Y-y-y-yes sir.", to: Daniel} +{can_hear: [Devil, Angel]} +{enum: Devil, dialog: "You will fall!", to: Angel} +{enum: Angel, dialog: "Perhaps. And then I will rise as He has, from the corpse and ashes, the sun rises.", to: Devil} + /* {can_hear: [WellDweller, Farmer, ManInBlack]}, {enum: WellDweller, dialog: "What a fearful farm you live in, come down to the well, the grass is damper down here.", to: Farmer, mood: Scared, thoughts: "Nobody can take me from my well"}, diff --git a/character_info.h b/character_info.h index 83b7f31..edddbde 100644 --- a/character_info.h +++ b/character_info.h @@ -29,6 +29,11 @@ ActionInfo actions[] = { .description = "Do nothing", NO_ARGUMENT, }, + { + .name = "approach", + .description = "There has been an error, please report to the developer. No NPCs should be able to do this", + ARGUMENT("Expects the argument to be who you're approaching"), + }, { .name = "join", .description = "Joins somebody else's party, so you follow them everywhere", @@ -101,4 +106,9 @@ CharacterGen characters[] = { .enum_name = "Passerby", .prompt = CHARACTER_PROMPT_PREFIX("Random Passerby") "random person, just passing by", }, + { + .name = "Angel", + .enum_name = "Angel", + .prompt = CHARACTER_PROMPT_PREFIX("Angel") "mysterious, radiant, mystical creature the player first talks to. You guide the entire game: deciding on an objective for the player to fulfill until you believe they've learned their lesson, whatever that means to them.", + }, }; diff --git a/main.c b/main.c index 34706c4..9e2523b 100644 --- a/main.c +++ b/main.c @@ -365,6 +365,7 @@ float float_rand(float min, float max) float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */ return min + scale * (max - min); /* [min, max] */ } +// always randomizes pitch void play_audio(AudioSample *sample, float volume) { AudioPlayer *to_use = 0; @@ -2530,7 +2531,7 @@ GameState load_from_string(MD_Arena *arena, MD_Arena *error_arena, MD_String8 da .arena = temp.arena, .error_arena = error_arena, }; - GameState to_return = {0}; + GameState to_return = { 0 }; ser_GameState(&ser, &to_return); if(ser.cur_error.failed) { @@ -3158,6 +3159,7 @@ Armature player_armature = {0}; Armature farmer_armature = {0}; Armature shifted_farmer_armature = {0}; Armature man_in_black_armature = {0}; +Armature angel_armature = {0}; // armatureanimations are processed once every visual frame from this list Armature *armatures[] = { @@ -3165,6 +3167,7 @@ Armature *armatures[] = { &farmer_armature, &shifted_farmer_armature, &man_in_black_armature, + &angel_armature, }; Mesh mesh_player = {0}; @@ -3232,6 +3235,9 @@ void init(void) man_in_black_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Man In Black")); man_in_black_armature.image = image_man_in_black; + angel_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Angel")); + angel_armature.image = image_angel; + binary_file = MD_LoadEntireFile(frame_arena, MD_S8Lit("assets/exported_3d/Farmer.bin")); farmer_armature = load_armature(persistent_arena, binary_file, MD_S8Lit("Farmer.bin")); @@ -3731,10 +3737,11 @@ void flush_quad_batch() typedef enum { - LAYER_TILEMAP, + LAYER_INVALID, LAYER_WORLD, LAYER_UI, LAYER_UI_FG, + LAYER_UI_TEXTINPUT, LAYER_SCREENSPACE_EFFECTS, LAYER_LAST @@ -3965,7 +3972,7 @@ void line(Vec2 from, Vec2 to, float line_width, Color color) } #ifdef DEVTOOLS -bool show_devtools = true; +bool show_devtools = false; #ifdef PROFILING extern bool profiling; #else @@ -4204,6 +4211,7 @@ typedef struct TextParams Color *colors; // color per character, if not null must be array of same length as text bool do_clipping; LoadedFont *use_font; // if null, uses default font + Layer layer; } TextParams; // returns bounds. To measure text you can set dry run to true and get the bounds @@ -4297,7 +4305,12 @@ AABB draw_text(TextParams t) col = t.colors[i]; } - draw_quad((DrawParams) { to_draw, font.image, font_atlas_region, col, t.clip_to, .layer = LAYER_UI_FG, .do_clipping = t.do_clipping }); + Layer to_use = LAYER_UI_FG; + if(t.layer != LAYER_INVALID) + { + to_use = t.layer; + } + draw_quad((DrawParams) { to_draw, font.image, font_atlas_region, col, t.clip_to, .layer = to_use, .do_clipping = t.do_clipping }); } } } @@ -5570,6 +5583,8 @@ void frame(void) to_use = &farmer_armature; else if(it->npc_kind == NPC_Raphael) to_use = &man_in_black_armature; + else if(it->npc_kind == NPC_Angel) + to_use = &angel_armature; else assert(false); @@ -5671,15 +5686,15 @@ void frame(void) // @Place(text input drawing) #ifdef DESKTOP - draw_quad((DrawParams){quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, text_input_fade*0.3f), .layer = LAYER_UI_FG}); + draw_quad((DrawParams){quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, text_input_fade*0.3f), .layer = LAYER_UI_TEXTINPUT}); Vec2 edge_of_text = MulV2F(screen_size(), 0.5f); if(text_input_buffer_length > 0) { - AABB bounds = draw_centered_text((TextParams){false, MD_S8(text_input_buffer, text_input_buffer_length), MulV2F(screen_size(), 0.5f), blendalpha(WHITE, text_input_fade), 1.0f, .use_font = &font_for_text_input}); + AABB bounds = draw_centered_text((TextParams){false, MD_S8(text_input_buffer, text_input_buffer_length), MulV2F(screen_size(), 0.5f), blendalpha(WHITE, text_input_fade), 1.0f, .use_font = &font_for_text_input, .layer = LAYER_UI_TEXTINPUT}); edge_of_text = bounds.lower_right; } Vec2 cursor_center = V2(edge_of_text.x,screen_size().y/2.0f); - draw_quad((DrawParams){quad_centered(cursor_center, V2(3.0f, 80.0f)), IMG(image_white_square), blendalpha(WHITE, text_input_fade * (sinf((float)elapsed_time*8.0f)/2.0f + 0.5f)), .layer = LAYER_UI_FG}); + draw_quad((DrawParams){quad_centered(cursor_center, V2(3.0f, 80.0f)), IMG(image_white_square), blendalpha(WHITE, text_input_fade * (sinf((float)elapsed_time*8.0f)/2.0f + 0.5f)), .layer = LAYER_UI_TEXTINPUT}); #endif // Draw Tilemap draw tilemap tilemap drawing @@ -5877,10 +5892,8 @@ void frame(void) static bool player_in_combat = false; - - float speed_target = 1.0f; - gs.stopped_time = cur_unread_entity != 0; + gs.stopped_time = cur_unread_entity != 0 || (!gs.no_angel_screen); if(gs.stopped_time) speed_target = 0.0f; // pausing the game speed_factor = Lerp(speed_factor, unwarped_dt*10.0f, speed_target); @@ -6851,6 +6864,75 @@ ISANERROR("Don't know how to do this stuff on this platform.") draw_centered_text((TextParams){false, MD_S8Lit("The AI server is having technical difficulties..."), text_center, WHITE, 1.0f }); } + // angel screen + { + static float visible = 1.0f; + bool should_be_visible = !gs.no_angel_screen; + visible = Lerp(visible, unwarped_dt*2.0f, should_be_visible ? 1.0f : 0.0f); + + Entity *angel_entity = 0; + ENTITIES_ITER(gs.entities) + { + if(it->is_npc && it->npc_kind == NPC_Angel) + { + assert(!angel_entity); + angel_entity = it; + } + } + assert(angel_entity); + + if(should_be_visible) gs.player->talking_to = frome(angel_entity); + + draw_quad((DrawParams) {quad_at(V2(0,screen_size().y), screen_size()), IMG(image_white_square), blendalpha(BLACK, visible), .layer = LAYER_UI_FG}); + + static MD_String8List to_say = {0}; + static double cur_characters = 0; + if(to_say.node_count == 0) + { + to_say = split_by_word(persistent_arena, MD_S8Lit("You've been asleep for a long long time...")); + cur_characters = 0; + } + MD_String8 cur_word = {0}; + MD_String8Node *cur_word_node = 0; + double chars_said = cur_characters; + for(MD_String8Node *cur = to_say.first; cur; cur = cur->next) + { + if((int)chars_said < cur->string.size) + { + cur_word = cur->string; + cur_word_node = cur; + break; + } + chars_said -= (double)cur->string.size; + } + if(!cur_word.str) + { + cur_word = to_say.last->string; + cur_word_node = to_say.last; + } + + cur_characters += unwarped_dt*ANGEL_CHARACTERS_PER_SEC; + chars_said += unwarped_dt*ANGEL_CHARACTERS_PER_SEC; + if(chars_said > cur_word.size && cur_word_node->next) + { + play_audio(&sound_angel_grunt_0, 1.0f); + } + + assert(cur_word_node); + MD_String8Node *prev_next = cur_word_node->next; + cur_word_node->next = 0; + MD_String8 without_unsaid = MD_S8ListJoin(frame_arena, to_say, &(MD_StringJoin){.mid = MD_S8Lit(" ")}); + cur_word_node->next = prev_next; + + draw_centered_text((TextParams){false, without_unsaid, V2(screen_size().x*0.5f, screen_size().y*0.75f), blendalpha(WHITE, visible), 1.0f, .use_font = &font_for_text_input}); + draw_centered_text((TextParams){false, MD_S8Lit("(Press E to speak)"), V2(screen_size().x*0.5f, screen_size().y*0.25f), blendalpha(WHITE, visible*0.5f), 0.8f, .use_font = &font_for_text_input}); + + if(pressed.interact) + { + begin_text_input(); + } + } + // win screen { static float visible = 0.0f; diff --git a/tuning.h b/tuning.h index 34a75f0..12cc8a1 100644 --- a/tuning.h +++ b/tuning.h @@ -6,6 +6,7 @@ #define PLAYER_SPEED 0.15f // in meters per second #define PERCEPTION_HEARING_RAGE (TILE_SIZE*4.0f) #define CHARACTERS_PER_SEC 45.0f +#define ANGEL_CHARACTERS_PER_SEC 35.0f #define PROPAGATE_ACTIONS_RADIUS 10.0f #define SWORD_SWIPE_RADIUS (TILE_SIZE*3.0f) #define ARROW_SPEED 200.0f