diff --git a/assets.mdesk b/assets.mdesk index 466f5c5..67bc66e 100644 --- a/assets.mdesk +++ b/assets.mdesk @@ -18,6 +18,10 @@ { filepath: "grunt_3.wav", } +@image peace_orb: +{ + filepath: "peace_orb.png", +} @image peace_totem: { filepath: "peace_totem.png", diff --git a/assets/new_level.json b/assets/new_level.json index 290264b..3d62084 100644 --- a/assets/new_level.json +++ b/assets/new_level.json @@ -365,8 +365,8 @@ "rotation":0, "visible":true, "width":32, - "x":1601.66666666667, - "y":1647.33333333333 + "x":1530.91836734694, + "y":2684.06802721088 }, { "class":"", diff --git a/character_info.h b/character_info.h index ff717a4..345fe97 100644 --- a/character_info.h +++ b/character_info.h @@ -38,6 +38,7 @@ ActionInfo actions[] = { {.name = "joins_player", }, {.name = "leaves_player", }, {.name = "stops_fighting_player", }, + {.name = "gives_peace_token", }, // Actions used by jester and other characters only in // the prologue for the game @@ -215,14 +216,7 @@ CharacterGen characters[] = { #define NPC_NAME "Edeline" .name = NPC_NAME, .enum_name = "Edeline", - .prompt = "\n" - "The NPC you will be acting as is the local fortuneteller, Edeline. Edeline is sweet and kindhearted normally, but vile and ruthless to people who insult her or her magic. She specializes in a new 'Purple Magic' that Meld despises. Meld, the local blacksmith, thinks Edeline's magic is silly. An example of an interaction between the player and the NPC, Edeline:\n" - "\n" - PLAYERSAY("What's up? Who are you?") - NPCSAY("I am Edeline, master of the future") - PLAYERSAY("Oh really? What do you say about joinin my party?") - NPCDOSAY("ACT_joins_player", "Absolutely!") - "Edeline is the master of the future, the star reader. Both are self-given titles, but her ability to predict the future has garnered attention from many who live in Worchen. However, some have called her 'unreliable' at times and her predictions can at times be either cryptic or broadly interpreted. She is eager to join the player's party if asked", + .prompt = "She is the town fortuneteller, sweet and kindhearted normally, but vile and ruthless to people who insult her or her magic. She specializes in a new 'Purple Magic' that Meld despises. Meld, the local blacksmith, thinks Edeline's magic is silly." }, { .name = "Death", @@ -270,23 +264,7 @@ CharacterGen characters[] = { #define NPC_NAME "The King" .name = NPC_NAME, .enum_name = "TheKing", - .prompt = "\n" - "The NPC you will be acting as is known as The King. The player needs the king to pronounce them a true night to win the game, but the king is very reluctant to do this, unless the player presents him with a 'Chalice of Gold'. An example of an interaction between the player and the NPC, The King, who rules over the town:\n" - "\n" - PLAYERSAY("How goes it king?") - NPCSAY("Leading is difficult, but rewarding.") - PLAYERSAY("What should I do?") - NPCSAY("You are still lacking the position of knight, are you not? You will never win without being a true knight. Bring me the Chalice of Gold if you want to 'win'") - PLAYERSAY("Where would I find such a thing?") - NPCSAY("I am far too busy to give a direct answer, but I'd suggest you ask around") - PLAYERSAY("Here I have the chalice") - NPCSAY("I can clearly see you don't have it. Do not attempt to fool me if you value your head") - PLAYERSAY("Presents it") - NPCSAY("Did you just say 'presents it' out loud thinking I'd think that means you have the chalice?") - PLAYERDO_ARG("ACT_gives_item", "ITEM_Chalice") - NPCDOSAY("ACT_knights_player", "How beautiful... You are clearly worth the title of knight!") - "\n" - "If the player does indeed present the king with the chalice of gold, the king will be overwhelemd with respect and feel he has no choice but to knight the player, ending the game. The Chalice of Gold ALWAYS makes the player a knight, if the player gives it to the king.", + .prompt = "He is a calm, honorable ruler, who does the best he can to do good by his people, even if they can be a little crazy at times.", }, }; diff --git a/main.c b/main.c index 581dc5b..bc53dc7 100644 --- a/main.c +++ b/main.c @@ -1007,6 +1007,13 @@ void cause_action_side_effects(Entity *from, Entity *to, Action a) assert(false); } + if(a.kind == ACT_gives_peace_token) + { + assert(!from->has_given_peace_token); + from->has_given_peace_token = true; + to->peace_tokens += 1; + } + if(a.kind == ACT_give_item) { assert(a.argument.item_to_give != ITEM_none); @@ -2827,23 +2834,29 @@ PlacedWordList place_wrapped_words(MD_Arena *arena, MD_String8 text, float text_ float current_vertical_offset = 0.0f; // goes negative for(MD_String8Node *next_word = words.first; next_word; next_word = next_word->next) { - AABB word_bounds = draw_text((TextParams){false, true, next_word->string, V2(0.0, 0.0), .scale = text_scale}); - word_bounds.lower_right.x += space_size; - float next_x_position = cur.x + aabb_size(word_bounds).x; - if(next_x_position - at_position.x > maximum_width) + if(next_word.size == 0) { - current_vertical_offset -= font_line_advance*text_scale*1.1f; // the 1.1 is just arbitrary padding because it looks too crowded otherwise - cur = AddV2(at_position, V2(0.0f, current_vertical_offset)); - next_x_position = cur.x + aabb_size(word_bounds).x; } + else + { + AABB word_bounds = draw_text((TextParams){false, true, next_word->string, V2(0.0, 0.0), .scale = text_scale}); + word_bounds.lower_right.x += space_size; + float next_x_position = cur.x + aabb_size(word_bounds).x; + if(next_x_position - at_position.x > maximum_width) + { + current_vertical_offset -= font_line_advance*text_scale*1.1f; // the 1.1 is just arbitrary padding because it looks too crowded otherwise + cur = AddV2(at_position, V2(0.0f, current_vertical_offset)); + next_x_position = cur.x + aabb_size(word_bounds).x; + } - PlacedWord *new_placed = MD_PushArray(arena, PlacedWord, 1); - new_placed->text = next_word->string; - new_placed->lower_left_corner = cur; + PlacedWord *new_placed = MD_PushArray(arena, PlacedWord, 1); + new_placed->text = next_word->string; + new_placed->lower_left_corner = cur; - MD_DblPushBack(to_return.first, to_return.last, new_placed); + MD_DblPushBack(to_return.first, to_return.last, new_placed); - cur.x = next_x_position; + cur.x = next_x_position; + } } MD_ReleaseScratch(scratch); @@ -4866,6 +4879,28 @@ void frame(void) // ui #define HELPER_SIZE 250.0f + + // how many peace tokens + { + MD_ArenaTemp scratch = MD_GetScratch(0, 0); + const float to_screen_padding = 50.0f; + const float btwn_elems = 10.0f; + const float text_scale = 1.0f; + const float peace_token_icon_size = 50.0f; + + TextParams t = {false, true, MD_S8Fmt(scratch.arena, "%d", player->peace_tokens), V2(0, 0), WHITE, text_scale}; + AABB text_bounds = draw_text(t); + float total_elem_width = btwn_elems + peace_token_icon_size + aabb_size(text_bounds).x; + float elem_height = peace_token_icon_size; + AABB total_elem_box = aabb_at(V2(screen_size().x - to_screen_padding - total_elem_width, screen_size().y - to_screen_padding), V2(total_elem_width, elem_height)); + draw_quad((DrawParams){false, quad_at(total_elem_box.upper_left, V2(peace_token_icon_size, peace_token_icon_size)), IMG(image_peace_orb), WHITE, .layer = LAYER_UI}); + t.dry_run = false; + t.pos = AddV2(total_elem_box.upper_left, V2(peace_token_icon_size + btwn_elems + aabb_size(text_bounds).x/2.0f, -peace_token_icon_size/2.0f)); + draw_text(t); + MD_ReleaseScratch(scratch); + } + + // keyboard tutorial icons if (!mobile_controls) { float total_height = HELPER_SIZE * 2.0f; diff --git a/makeprompt.h b/makeprompt.h index 0c989cf..b19b36f 100644 --- a/makeprompt.h +++ b/makeprompt.h @@ -234,6 +234,7 @@ typedef struct Entity bool is_npc; bool being_hovered; bool perceptions_dirty; + bool has_given_peace_token; #ifdef DESKTOP int times_talked_to; // for better mocked response string @@ -323,6 +324,11 @@ void fill_available_actions(Entity *it, AvailableActions *a) { BUFF_APPEND(a, ACT_give_item); } + + if (!it->has_given_peace_token) + { + BUFF_APPEND(a, ACT_gives_peace_token); + } if (it->npc_kind == NPC_TheKing) { @@ -444,6 +450,18 @@ MD_String8 is_action_valid(MD_Arena *arena, Entity *from, Entity *to_might_be_nu } } + if(a.kind == ACT_gives_peace_token) + { + if(from->has_given_peace_token) + { + return MD_S8Lit("You can't give away a peace token when you've already given one away"); + } + if(!to_might_be_null || !to_might_be_null->is_character) + { + return MD_S8Lit("Must be targeting the player to give away your peace token"); + } + } + if(a.kind == ACT_leaves_player && from->standing != STANDING_JOINED) { return MD_S8Lit("You can't leave the player unless you joined them."); @@ -604,6 +622,18 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, Entity *e) } } MD_S8ListPushFmt(scratch.arena, &latest_state, "]"); + + // peace token + { + if(e->has_given_peace_token) + { + MD_S8ListPushFmt(scratch.arena, &latest_state, "\nRight now you don't have your piece token so you can't give it anymore"); + } + else + { + MD_S8ListPushFmt(scratch.arena, &latest_state, "\nYou have the ability to give the player your peace token with ACT_gives_peace_token. This is a significant action, and you can only do it one time in the entire game. Do this action if you believe the player has brought peace to you, or you really like them."); + } + } MD_String8 latest_state_string = MD_S8ListJoin(scratch.arena, latest_state, &(MD_StringJoin){MD_S8Lit(""),MD_S8Lit(""),MD_S8Lit("")}); MD_S8ListPush(scratch.arena, &list, MD_S8Chop(make_json_node(scratch.arena, MSG_SYSTEM, latest_state_string), 1)); // trailing comma not allowed in json diff --git a/tuning.h b/tuning.h index 6be6492..7dd2a9b 100644 --- a/tuning.h +++ b/tuning.h @@ -26,7 +26,7 @@ #endif // REFACTORING:: also have to update in javascript!!!!!!!! -#define MAX_SENTENCE_LENGTH 400 // LOOOK AT AGBOVE COMMENT GBEFORE CHANGING +#define MAX_SENTENCE_LENGTH 600 // LOOOK AT AGBOVE COMMENT GBEFORE CHANGING #define SENTENCE_CONST(txt) { .data = txt, .cur_index = sizeof(txt) } #define SENTENCE_CONST_CAST(txt) (Sentence)SENTENCE_CONST(txt)