Fix talking_to not filled in, enum_name -> name, add todo

main
Cameron Murphy Reikes 2 years ago
parent 1a38114f59
commit 32fd2227dd

@ -5,9 +5,9 @@
// @TODO allow AI to prefix out of character statemetns with [ooc], this is a well khnown thing on role playing forums so gpt would pick up on it.
const char *global_prompt = "You are a colorful and interesting personality in an RPG video game, who remembers important memories from the conversation history and stays in character.\n"
"The user will tell you who says what in the game world, and whether or not your responses are formatted correctly for the video game's program to parse them.\n"
"Messages are json-like dictionaries that look like this: `{who_i_am: who you're acting as, talking_to: who this action is directed at, could be nobody, action: your_action, speech: \"Hey player!\", thoughts: \"Your thoughts\"}`. The required fields are `action`, `thoughts`, and `who_i_am`\n"
"Messages are json-like dictionaries that look like this: `{who_i_am: who you're acting as, talking_to: who this action is directed at, could be nobody, action: your_action, speech: \"Hey player!\", thoughts: \"Your thoughts\"}`. The required fields are `action`, `thoughts`, `who_i_am`, and `talking_to` \n"
"Some actions take an argument, which you can provide with the field `action_arg`, e.g for the action `give_item` you would provide an item in your inventory, like {action: give_item, action_arg: Chalice}. The item must come from your inventory which is listed below\n"
"If was_heard_in_passing is true, then the action wasn't said directly to you, it was heard physically close to you. So, you usually respond with action: none and omit the speech field, as something you hear around the corner or whatever you don't normally respond to unless you feel the need to interrupt or something like that.\n"
"`talking_to` provides the name of who the action is directed towards. Use 'nobody' if you just want to speak to the air, but if you're speaking to somebody fill out the field with `talking_to: \"Character's Name\"`. If talking_to isn't your name, then it's much more likely you don't respond to their speech and action by leaving speech as a string of size 0, like `speech: \"\"`\n"
"Do NOT give away an item until the player gives you something you think is of equal value\n"
;

@ -254,7 +254,7 @@ void do_parsing_tests()
speech = MD_S8Lit("Better have a good reason for bothering me.");
MD_String8 thoughts = MD_S8Lit("Man I'm tired today Whatever.");
MD_String8 to_parse = FmtWithLint(scratch.arena, "{action: none, speech: \"%.*s\", thoughts: \"%.*s\", who_i_am: TheBlacksmith, talking_to: nobody}", MD_S8VArg(speech), MD_S8VArg(thoughts));
MD_String8 to_parse = FmtWithLint(scratch.arena, "{action: none, speech: \"%.*s\", thoughts: \"%.*s\", who_i_am: \"Meld\", talking_to: nobody}", MD_S8VArg(speech), MD_S8VArg(thoughts));
error = parse_chatgpt_response(scratch.arena, &e, to_parse, &a);
assert(error.size == 0);
assert(a.kind == ACT_none);
@ -272,7 +272,7 @@ void do_parsing_tests()
error = parse_chatgpt_response(scratch.arena, &e, MD_S8Lit("ACT_give_item(Chalice \""), &a);
assert(error.size > 0);
to_parse = MD_S8Lit("{action: give_item, action_arg: Chalice, speech: \"Here you go\", thoughts: \"Man I'm gonna miss that chalice\", who_i_am: TheBlacksmith, talking_to: nobody}");
to_parse = MD_S8Lit("{action: give_item, action_arg: Chalice, speech: \"Here you go\", thoughts: \"Man I'm gonna miss that chalice\", who_i_am: \"Meld\", talking_to: nobody}");
error = parse_chatgpt_response(scratch.arena, &e, to_parse, &a);
assert(error.size == 0);
assert(a.kind == ACT_give_item);
@ -1026,7 +1026,7 @@ MD_String8 is_action_valid(MD_Arena *arena, Entity *from, Action a)
}
if(!found)
{
return FmtWithLint(arena, "Character you're talking to, %s, isn't close enough to be talked to", characters[a.talking_to_kind].enum_name);
return FmtWithLint(arena, "Character you're talking to, '%s', isn't close enough to be talked to", characters[a.talking_to_kind].name);
}
}
@ -1060,6 +1060,11 @@ MD_String8 is_action_valid(MD_Arena *arena, Entity *from, Action a)
return MD_S8Lit("You can't leave the player unless you joined them.");
}
if(a.kind == ACT_joins_player && from->standing == STANDING_JOINED)
{
return MD_S8Lit("You can't join the player, you've already joined them!");
}
return (MD_String8){0};
}
@ -1559,7 +1564,7 @@ void reset_level()
if(!found)
{
PushWithLint(scratch.arena, &drama_errors, "Couldn't find NPC of kind %s in the current map", characters[want].enum_name);
PushWithLint(scratch.arena, &drama_errors, "Couldn't find NPC '%s' in the current map", characters[want].name);
}
}
}

@ -442,9 +442,7 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, Entity *e, CanTalkTo can_tal
}
MD_String8 speech = MD_S8(it->speech, it->speech_length);
PushWithLint(scratch.arena, &cur_list, "was_heard_in_passing: %s, ", it->context.heard_physically ? "true" : "false");
PushWithLint(scratch.arena, &cur_list, "talking_to: %s, ", it->context.was_talking_to_somebody ? characters[it->context.talking_to_kind].enum_name : "nobody");
PushWithLint(scratch.arena, &cur_list, "talking_to: \"%s\", ", it->context.was_talking_to_somebody ? characters[it->context.talking_to_kind].name : "nobody");
// add speech
{
@ -568,7 +566,7 @@ MD_String8 generate_chatgpt_prompt(MD_Arena *arena, Entity *e, CanTalkTo can_tal
PushWithLint(scratch.arena, &latest_state, "The characters close enough for you to talk to with `talking_to`: [");
BUFF_ITER(NpcKind, &can_talk_to)
{
PushWithLint(scratch.arena, &latest_state, "%s, ", characters[*it].enum_name);
PushWithLint(scratch.arena, &latest_state, "\"%s\", ", characters[*it].name);
}
PushWithLint(scratch.arena, &latest_state, "]\n");
@ -664,7 +662,7 @@ MD_String8 parse_chatgpt_response(MD_Arena *arena, Entity *e, MD_String8 sentenc
}
assert(!e->is_character); // player can't perform AI actions?
MD_String8 my_name = MD_S8CString(characters[e->npc_kind].enum_name);
MD_String8 my_name = MD_S8CString(characters[e->npc_kind].name);
if(error_message.size == 0 && !MD_S8Match(who_i_am_str, my_name, 0))
{
error_message = FmtWithLint(arena, "You are acting as %.*s, not what you said in who_i_am, `%.*s`", MD_S8VArg(my_name), MD_S8VArg(who_i_am_str));
@ -681,9 +679,10 @@ MD_String8 parse_chatgpt_response(MD_Arena *arena, Entity *e, MD_String8 sentenc
bool found = false;
for(int i = 0; i < ARRLEN(characters); i++)
{
if(MD_S8Match(talking_to_str, MD_S8CString(characters[i].enum_name), 0))
if(MD_S8Match(talking_to_str, MD_S8CString(characters[i].name), 0))
{
found = true;
out->talking_to_somebody = true;
out->talking_to_kind = i;
}
}
@ -722,6 +721,7 @@ MD_String8 parse_chatgpt_response(MD_Arena *arena, Entity *e, MD_String8 sentenc
if(!found_action)
{
MD_String8 list_of_actions = MD_S8ListJoin(scratch.arena, action_strings, &(MD_StringJoin){.mid = MD_S8Lit(", ")});
error_message = FmtWithLint(arena, "Couldn't find action you can perform for provided string `%.*s`. Your available actions: [%.*s]", MD_S8VArg(action_str), MD_S8VArg(list_of_actions));
}
}

@ -1,6 +1,7 @@
DONE - rewrite to have metadesk format for speech and actions
DONE - action and item explanations in system message, along with available actions and items
DONE - remove party eavesdropping, but make clear to AI when things are heard physically or told directly. Allow AI to choose people in vicinity to target with conversation and action. I.e a `talking_to` field. Also add a required character: field in chatgpt response, and make sure it matches the character it's supposed to act as.
- Improve error messages on joins_party when already in party, factor parsing string -> enum into one shared function in parse chatgpt
- The using of items and backpack inventory view.
- delete peace tokens, replace with key items and scroll item that says word.
- display actions, like giving an item, in memory history

Loading…
Cancel
Save