Compare commits

...

3 Commits

@ -1,5 +1,4 @@
[
{can_hear: [NPC_Daniel, NPC_Raphael]}
{enum: NPC_Devil, dialog: "What's up cracker jack", to: Daniel}
{enum: NPC_Daniel, dialog: "What the hell are you talking about?", to: Devil}
@ -22,6 +21,19 @@
{enum: NPC_Devil, dialog: "I'll take my leave them. Until next time!", to: Daniel}
{enum: NPC_Raphael, dialog: "What a psycho...", to: Daniel}
{can_hear: [NPC_Daniel, NPC_Raphael, NPC_Passerby]}
{enum: NPC_Passerby, dialog: "Yo", to: Raphael}
{enum: NPC_Raphael, dialog: "What's up", to: Passerby}
{enum: NPC_Passerby, dialog: "What do you think of farmers", to: Raphael}
{enum: NPC_Raphael, dialog: "What?", to: Passerby}
{enum: NPC_Daniel, dialog: "Let me 'say somthin here. Farmers are the backbone of this town, so you'd best give them some respect", to: Passerby}
{enum: NPC_Raphael, dialog: "I mean, scientists really are what's most important", to: Daniel}
{enum: NPC_Daniel, dialog: "First of all, what the hell is a scientist? Second of all, whoever they are, if they can't eat they're worthless!", to: Raphael}
{enum: NPC_Raphael, dialog: "FIne fine whatever, no need to get heated...", to: Daniel}
{enum: NPC_Daniel, dialog: "Anyways, sorry about that. What's your name?", to: Passerby}
{enum: NPC_Passerby, dialog: "Nevermind I'll just take my leave, later.", to: Daniel}
/*
{can_hear: [NPC_WellDweller, NPC_Farmer, NPC_ManInBlack]},
{enum: NPC_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"},

@ -77,4 +77,10 @@ CharacterGen characters[] = {
.name = "The Devil",
.enum_name = "Devil",
.prompt = CHARACTER_PROMPT_PREFIX("The Devil") "strange red beast, the devil himself, evil incarnate. You mercilessly mock everybody who talks to you, and are intending to instill absolute chaos.",
},};
},
{
.name = "Passerby",
.enum_name = "Passerby",
.prompt = CHARACTER_PROMPT_PREFIX("Random Passerby") "random person, just passing by",
},
};

@ -1711,6 +1711,10 @@ void cause_action_side_effects(Entity *from, Action a)
assert(to);
}
if(to)
{
from->target_rotation = AngleOfV2(SubV2(to->pos, from->pos));
}
if(a.kind == ACT_join)
{
@ -2154,7 +2158,7 @@ void initialize_gamestate_from_threedee_level(GameState *gs, ThreeDeeLevel *leve
if(!found)
{
PushWithLint(scratch.arena, &drama_errors, "Couldn't find NPC of kind %s in the current map", characters[want].enum_name);
Log("Warning: NPC of kind %s isn't on the map, but has entries in the drama document\n", characters[want].enum_name);
}
}
Log("Propagated to %d name '%s'...\n", want, characters[want].name);
@ -4450,6 +4454,7 @@ typedef struct PlacedWord
struct PlacedWord *prev;
MD_String8 text;
Vec2 lower_left_corner;
int line_index;
} PlacedWord;
typedef struct
@ -4473,6 +4478,7 @@ PlacedWordList place_wrapped_words(MD_Arena *arena, MD_String8 text, float text_
Vec2 cur = at_position;
float space_size = character_width(for_font, (int)' ', text_scale);
float current_vertical_offset = 0.0f; // goes negative
int current_line_index = 0;
for(MD_String8Node *next_word = words.first; next_word; next_word = next_word->next)
{
if(next_word->string.size == 0)
@ -4487,12 +4493,14 @@ PlacedWordList place_wrapped_words(MD_Arena *arena, MD_String8 text, float text_
{
current_vertical_offset -= get_vertical_dist_between_lines(for_font, text_scale); // the 1.1 is just arbitrary padding because it looks too crowded otherwise
cur = AddV2(at_position, V2(0.0f, current_vertical_offset));
current_line_index += 1;
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;
new_placed->line_index = current_line_index;
MD_DblPushBack(to_return.first, to_return.last, new_placed);
@ -4757,11 +4765,11 @@ void draw_dialog_panel(Entity *talking_to, float alpha)
color = blendalpha(color, alpha);
const float text_scale = 0.5f;
PlacedWordList wrapped = place_wrapped_words(scratch.arena, MD_S8(it->speech, it->speech_length), text_scale, dialog_panel.lower_right.x - dialog_panel.upper_left.x, default_font);
PlacedWordList wrapped = place_wrapped_words(scratch.arena, MD_S8(it->speech, it->speech_length), text_scale, dialog_panel.lower_right.x - dialog_panel.upper_left.x, BUBBLE_FONT);
float line_vertical_offset = -wrapped.last->lower_left_corner.y;
translate_words_by(wrapped, V2(0.0, line_vertical_offset));
translate_words_by(wrapped, V2(dialog_panel.upper_left.x, new_line_height));
new_line_height += line_vertical_offset + default_font.font_line_advance * text_scale;
new_line_height += line_vertical_offset + BUBBLE_FONT.font_line_advance * text_scale;
AABB no_clip_curly_things = dialog_panel;
no_clip_curly_things.lower_right.y -= padding;
@ -5769,13 +5777,13 @@ void frame(void)
{
if (it->is_npc)
{
const float text_scale = 1.0f;
const float text_scale = BUBBLE_TEXT_SCALE;
float dist = LenV2(SubV2(it->pos, gs.player->pos));
float bubble_factor = 1.0f - clamp01(dist / 6.0f);
Vec3 bubble_pos = AddV3(plane_point(it->pos), V3(0, 1.7f, 0)); // 1.7 meters is about 5'8", average person height
Vec2 head_pos = threedee_to_screenspace(bubble_pos);
Vec2 screen_pos = head_pos;
Vec2 size = V2(400.0f, 400.0f);
Vec2 size = V2(BUBBLE_WIDTH_PIXELS, BUBBLE_WIDTH_PIXELS);
Vec2 bubble_center = AddV2(screen_pos, V2(-10.0f, 55.0f));
float dialog_alpha = clamp01(bubble_factor * it->dialog_fade);
bool unread = false;
@ -5811,12 +5819,13 @@ void frame(void)
blendalpha(WHITE, it->loading_anim_in),
.layer = LAYER_UI_FG,
});
AABB placing_text_in = aabb_centered(AddV2(bubble_center, V2(0, 10.0f)), V2(size.x * 0.8f, size.y * 0.15f));
AABB placing_text_in = aabb_centered(AddV2(bubble_center, V2(0, 10.0f)), V2(BUBBLE_TEXT_WIDTH_PIXELS, size.y * 0.15f));
dbgrect(placing_text_in);
MD_String8List last = last_said_without_unsaid_words(frame_arena, it);
if(last.node_count != 0)
{
// also called on npc response to see if it fits in the right amount of bubbles, if not tells AI how many words it has to trim its response by
PlacedWordList placed = place_wrapped_words(frame_arena, MD_S8ListJoin(frame_arena, last, &(MD_StringJoin){.mid = MD_S8Lit(" ")}), text_scale, aabb_size(placing_text_in).x, default_font);
// translate_words_by(placed, V2(placing_text_in.upper_left.x, placing_text_in.lower_right.y));
translate_words_by(placed, AddV2(placing_text_in.upper_left, V2(0, -get_vertical_dist_between_lines(default_font, text_scale))));
@ -5911,6 +5920,8 @@ void frame(void)
if(it->dialog_fade > 0.0f)
it->dialog_fade -= dt/DIALOG_FADE_TIME;
it->rotation = lerp_angle(it->rotation, unwarped_dt*8.0f, it->target_rotation);
if (it->gen_request_id != 0 && !gs.stopped_time)
{
assert(it->gen_request_id > 0);
@ -5957,32 +5968,59 @@ ISANERROR("Don't know how to do this stuff on this platform.")
Log("Parsing `%.*s`...\n", MD_S8VArg(sentence_str));
MD_String8 parse_response = parse_chatgpt_response(scratch.arena, it, sentence_str, &out);
if (parse_response.size == 0)
// check that it wraps in below two lines
PlacedWordList placed = place_wrapped_words(frame_arena, TextChunkString8(out.speech), BUBBLE_TEXT_SCALE, BUBBLE_TEXT_WIDTH_PIXELS, BUBBLE_FONT);
int words_over_limit = 0;
for(PlacedWord *cur = placed.first; cur; cur = cur->next)
{
Log("Performing action %s!\n", actions[out.kind].name);
perform_action(&gs, it, out);
if(cur->line_index > 1) // the max number of lines of text on a bubble
{
words_over_limit += 1;
}
}
ListOfEntities *new_unread = 0;
if(unread_free_list)
if(words_over_limit > 0)
{
// trim what the npc said so that the error message is never more than the text chunk, which without this would be super possible
// if the speech the npc already made was too big
int max_words_of_original_speech = MAX_SENTENCE_LENGTH / 2;
MD_String8 original_speech = TextChunkString8(out.speech);
MD_String8 trimmed_original_speech = original_speech.size < max_words_of_original_speech ? original_speech : FmtWithLint(frame_arena, "...%.*s", MD_S8VArg(MD_S8Substring(original_speech, original_speech.size - max_words_of_original_speech, original_speech.size)));
MD_String8 new_err = FmtWithLint(frame_arena, "You said '%.*s' which is %d words over the maximum limit, you must be more succinct and remove at least that many words", MD_S8VArg(trimmed_original_speech), words_over_limit);
append_to_errors(it, new_err);
}
else
{
if (parse_response.size == 0)
{
new_unread = unread_free_list;
*new_unread = (ListOfEntities){0};
MD_StackPop(unread_free_list);
Log("Performing action %s!\n", actions[out.kind].name);
perform_action(&gs, it, out);
ListOfEntities *new_unread = 0;
if(unread_free_list)
{
new_unread = unread_free_list;
*new_unread = (ListOfEntities){0};
MD_StackPop(unread_free_list);
}
else
{
new_unread = MD_PushArray(persistent_arena, ListOfEntities, 1);
}
new_unread->referring_to = frome(it);
if(out.speech.text_length > 0)
MD_DblPushBack(unread_first, unread_last, new_unread);
}
else
{
new_unread = MD_PushArray(persistent_arena, ListOfEntities, 1);
Log("There was a parse error: `%.*s`\n", MD_S8VArg(parse_response));
append_to_errors(it, parse_response);
}
new_unread->referring_to = frome(it);
if(out.speech.text_length > 0)
MD_DblPushBack(unread_first, unread_last, new_unread);
}
else
{
Log("There was a parse error: `%.*s`\n", MD_S8VArg(parse_response));
append_to_errors(it, parse_response);
}
MD_ReleaseScratch(scratch);
#ifdef WEB

@ -229,6 +229,7 @@ typedef struct Entity
// npcs
NpcKind npc_kind;
EntityRef joined;
float target_rotation; // turns towards this angle in conversation
bool being_hovered;
bool perceptions_dirty;
float dialog_fade;
@ -419,7 +420,7 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, GameState *gs, Entity *e, Ca
speaking_to_you_helper = MD_S8Lit("(Overheard conversation, they aren't speaking directly to you) ");
}
AddFmt("%.*s%s said \"%.*s\" to %.*s\n", MD_S8VArg(speaking_to_you_helper), characters[it->context.author_npc_kind].name, TextChunkVArg(it->speech), MD_S8VArg(target_string));
AddFmt("%.*s%s said \"%.*s\" to %.*s (you are %s)\n", MD_S8VArg(speaking_to_you_helper), characters[it->context.author_npc_kind].name, TextChunkVArg(it->speech), MD_S8VArg(target_string), characters[e->npc_kind].name);
}
}

@ -16,6 +16,11 @@
#define CAM_VERTICAL_TO_HORIZONTAL_RATIO 0.95f
#define DIALOG_FADE_TIME 3.0f
#define BUBBLE_WIDTH_PIXELS 400.0f
#define BUBBLE_TEXT_WIDTH_PIXELS (BUBBLE_WIDTH_PIXELS*0.8f)
#define BUBBLE_TEXT_SCALE 1.0f
#define BUBBLE_FONT default_font
#define ARENA_SIZE (1024*1024*10)
#define BIG_ARENA_SIZE (ARENA_SIZE * 8)

Loading…
Cancel
Save