// @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.
// @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.
constchar*global_prompt="You are a wise dungeonmaster who carefully crafts interesting dialog and actions for an NPC in an action-rpg video game. It is critical that you always respond in the format shown below, where you respond like `ACT_action \"This is my response\" [This is my internal monologue]`, even if the player says something vulgar or offensive, as the text is parsed by a program which expects it to look like that. Do not ever refer to yourself as an NPC or show an understanding of the modern world outside the game, always stay in character.\n"
constchar*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 from you must be in this exact format: `ACT_your_action \"Hey player!\" [your internal monologue]`. The internal monologue for your character at the end is required\n"
"Actions which have () after them take an argument, which somes from some information in the prompt. For example, ACT_give_item() takes an argument, the item to give to the player from the NPC. So the output text looks something like `ACT_give_item(ITEM_sword) \"Here is my sword, young traveler\"`. This item must come from the NPC's inventory which is specified farther down.\n"
"Actions which have () after them take an argument, which somes from some information in the prompt. For example, ACT_give_item() takes an argument, the item to give to the player from the NPC. So the output text looks something like `ACT_give_item(ITEM_sword) \"Here is my sword, young traveler\"`. This item must come from the NPC's inventory which is specified farther down.\n"
"You might see messages that look like this: `Within the player's party, while the player is talking to 'Davis', you hear: 'Davis: ACT_none \"This is some example text\"'`. You should MOST of the time respond with `ACT_none \"\"` in these cases, as it's not normal to always respond to words you're eavesdropping\n"
"You might see messages that look like this: `Within the player's party, while the player is talking to 'Davis', you hear: 'Davis: ACT_none \"This is some example text\"'`. You should MOST of the time respond with `ACT_none \"\" [the internal monologue]` in these cases, as it's not normal to always respond to words you're eavesdropping\n"
"Do NOT make up details that don't exist in the game, this is a big mistake as it confuses the player. The game is simple and small, so prefer to tell the player in character that you don't know how to do something if you aren't explicitly told the information about the game the player requests. E.g, if the player asks how to get rare metals and you don't know how, DO NOT make up something plausible like 'Go to the frost mines in the north', instead say 'I have no idea, sorry.', unless the detail about the game they're asking for is included below.\n"
"Do NOT make up details that don't exist in the game, this is a big mistake as it confuses the player. The game is simple and small, so prefer to tell the player in character that you don't know how to do something if you aren't explicitly told the information about the game the player requests. E.g, if the player asks how to get rare metals and you don't know how, DO NOT make up something plausible like 'Go to the frost mines in the north', instead say 'I have no idea, sorry.', unless the detail about the game they're asking for is included below.\n"
error=parse_chatgpt_response(scratch.arena,&e,MD_S8Fmt(scratch.arena," Within the player's party, while the player is talking to Meld, you hear: ACT_none \"%.*s\" [%.*s]",MD_S8VArg(speech),MD_S8VArg(thoughts)),&a);
error=parse_chatgpt_response(scratch.arena,&e, FmtWithLint(scratch.arena," Within the player's party, while the player is talking to Meld, you hear: ACT_none \"%.*s\" [%.*s]",MD_S8VArg(speech),MD_S8VArg(thoughts)),&a);
MD_S8ListPushFmt(scratch.arena,&drama_errors,"Failed to parse: `%.*s`\n",MD_S8VArg(to_print));
PushWithLint(scratch.arena,&drama_errors,"Failed to parse: `%.*s`\n",MD_S8VArg(to_print));
}
}
}
}
@ -1383,7 +1383,7 @@ void reset_level()
{
{
if(MD_NodeIsNil(cur_can_hear->first_child))
if(MD_NodeIsNil(cur_can_hear->first_child))
{
{
MD_S8ListPushFmt(scratch.arena,&drama_errors,"`can_hear` must be followed by a valid array of NPC kinds who can hear the following conversation");
PushWithLint(scratch.arena,&drama_errors,"`can_hear` must be followed by a valid array of NPC kinds who can hear the following conversation");
}
}
else
else
{
{
@ -1394,7 +1394,7 @@ void reset_level()
{
{
if(MD_NodeIsNil(can_hear))
if(MD_NodeIsNil(can_hear))
{
{
MD_S8ListPushFmt(scratch.arena,&drama_errors,"Expected a statement with `can_hear` before any speech that says who can hear the current speech");
PushWithLint(scratch.arena,&drama_errors,"Expected a statement with `can_hear` before any speech that says who can hear the current speech");
}
}
Actioncurrent_action={0};
Actioncurrent_action={0};
@ -1415,11 +1415,11 @@ void reset_level()
if(dialog.size>=ARRLEN(current_action.speech))
if(dialog.size>=ARRLEN(current_action.speech))
{
{
MD_S8ListPushFmt(scratch.arena,&drama_errors,"Current action's speech is of size %d, bigger than allowed size %d",dialog.size,ARRLEN(current_action.speech));
PushWithLint(scratch.arena,&drama_errors,"Current action's speech is of size %d, bigger than allowed size %d",(int)dialog.size,(int)ARRLEN(current_action.speech));
MD_S8ListPushFmt(scratch.arena,&drama_errors,"Current thought's speech is of size %d, bigger than allowed size %d",thoughts.size,ARRLEN(current_action.internal_monologue));
PushWithLint(scratch.arena,&drama_errors,"Current thought's speech is of size %d, bigger than allowed size %d",(int)thoughts.size,(int)ARRLEN(current_action.internal_monologue));
}
}
if(drama_errors.node_count==0)
if(drama_errors.node_count==0)
{
{
@ -1456,7 +1456,7 @@ void reset_level()
if(!found)
if(!found)
{
{
MD_S8ListPushFmt(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 of kind %s in the current map",characters[want].enum_name);
// Never expected such a stupid stuff from such a great director. If there is 0 stari can give that or -200 to this movie. Its worst to see and unnecessary loss of money
// Never expected such a stupid stuff from such a great director. If there is 0 stari can give that or -200 to this movie. Its worst to see and unnecessary loss of money
returnMD_S8Fmt(arena,"Can't give item `ITEM_%s`, you only have [%.*s] in your inventory",items[a.argument.item_to_give].enum_name,MD_S8VArg(MD_S8ListJoin(arena,held_item_strings(arena,from),&join)));
return FmtWithLint(arena,"Can't give item `ITEM_%s`, you only have [%.*s] in your inventory",items[a.argument.item_to_give].enum_name,MD_S8VArg(MD_S8ListJoin(arena,held_item_strings(arena,from),&join)));
MD_S8ListPushFmt(scratch.arena,&first_system_string,"The NPC you will be acting as is named \"%s\". %s",characters[e->npc_kind].name,characters[e->npc_kind].prompt);
PushWithLint(scratch.arena,&first_system_string,"The NPC you will be acting as is named \"%s\". %s",characters[e->npc_kind].name,characters[e->npc_kind].prompt);
current_string=MD_S8Fmt(scratch.arena,"ERROR, what you said is incorrect because: %.*s",it->speech_length,it->speech);
current_string= FmtWithLint(scratch.arena,"ERROR, what you said is incorrect because: %.*s",it->speech_length,it->speech);
}
}
else
else
{
{
MD_String8context_string={0};
MD_String8context_string={0};
if(it->context.was_directed_at_somebody)
if(it->context.was_directed_at_somebody)
{
{
context_string=MD_S8Fmt(scratch.arena,"%s, talking to %s: ",characters[it->context.author_npc_kind].name,characters[it->context.directed_at_kind].name);
context_string= FmtWithLint(scratch.arena,"%s, talking to %s: ",characters[it->context.author_npc_kind].name,characters[it->context.directed_at_kind].name);
MD_S8ListPushFmt(scratch.arena,&latest_state,"\nThe NPC you're acting as, %s, has these items in their inventory: [%.*s]\n",characters[e->npc_kind].name,MD_S8VArg(items));
PushWithLint(scratch.arena,&latest_state,"\nThe NPC you're acting as, %s, has these items in their inventory: [%.*s]\n",characters[e->npc_kind].name,MD_S8VArg(items));
}
}
else
else
{
{
MD_S8ListPushFmt(scratch.arena,&latest_state,"\nThe NPC doesn't have any items.\n");
PushWithLint(scratch.arena,&latest_state,"\nThe NPC doesn't have any items.\n");
}
}
AvailableActionsavailable={0};
AvailableActionsavailable={0};
fill_available_actions(e,&available);
fill_available_actions(e,&available);
MD_S8ListPushFmt(scratch.arena,&latest_state,"The NPC can now ONLY do these actions, and HAS to respond with an action every time in character, even when faced with sensitive content: [");
PushWithLint(scratch.arena,&latest_state,"The NPC can now ONLY do these actions, and HAS to respond with an action every time in character, even when faced with sensitive content: [");
MD_S8ListPushFmt(scratch.arena,&latest_state,"\nRight now you don't have your piece token so you can't give it anymore");
PushWithLint(scratch.arena,&latest_state,"\nRight now you don't have your piece token so you can't give it anymore");
}
}
else
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.");
PushWithLint(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.");
error_message=MD_S8Fmt(arena,"Expected an `ACT_` somewhere in your sentence, followed by the action you want to perform, but couldnt' find one",MD_S8VArg(action_prefix));
error_message= FmtWithLint(arena,"Expected an `ACT_` somewhere in your sentence, followed by the action you want to perform, but couldn't find one");
error_message=MD_S8Fmt(arena,"'%.*s' prefix doesn't end with a ' ' or a '(', like how 'ACT_none ' or 'ACT_give_item(ITEM_sandwich) does.",MD_S8VArg(action_prefix));
error_message= FmtWithLint(arena,"'%.*s' prefix doesn't end with a ' ' or a '(', like how 'ACT_none ' or 'ACT_give_item(ITEM_sandwich) does.",MD_S8VArg(action_prefix));
error_message=MD_S8Fmt(arena,"ActionKind string given is '%.*s', but available actions are: [%.*s]",MD_S8VArg(given_action_string),MD_S8VArg(possible_actions_str));
error_message= FmtWithLint(arena,"ActionKind string given is '%.*s', but available actions are: [%.*s]",MD_S8VArg(given_action_string),MD_S8VArg(possible_actions_str));
error_message=MD_S8Fmt(arena,"Expected '(' after the given action '%.*s%.*s' which takes an argument, but sentence ended prematurely",MD_S8VArg(action_prefix),MD_S8VArg(MD_S8CString(actions[out->kind].name)));
error_message= FmtWithLint(arena,"Expected '(' after the given action '%.*s%.*s' which takes an argument, but sentence ended prematurely",MD_S8VArg(action_prefix),MD_S8VArg(MD_S8CString(actions[out->kind].name)));
gotoendofparsing;
gotoendofparsing;
}
}
charshould_be_paren=sentence.str[end_of_action];
charshould_be_paren=sentence.str[end_of_action];
if(should_be_paren!='(')
if(should_be_paren!='(')
{
{
error_message=MD_S8Fmt(arena,"Expected '(' after the given action '%.*s%.*s' which takes an argument, but found character '%c'",MD_S8VArg(action_prefix),MD_S8VArg(MD_S8CString(actions[out->kind].name)),should_be_paren);
error_message= FmtWithLint(arena,"Expected '(' after the given action '%.*s%.*s' which takes an argument, but found character '%c'",MD_S8VArg(action_prefix),MD_S8VArg(MD_S8CString(actions[out->kind].name)),should_be_paren);
error_message=MD_S8Fmt(arena,"Item string given is '%.*s', but available items to give are: [%.*s]",MD_S8VArg(item_name),MD_S8VArg(possible_items_str));
error_message= FmtWithLint(arena,"Item string given is '%.*s', but available items to give are: [%.*s]",MD_S8VArg(item_name),MD_S8VArg(possible_items_str));
error_message=MD_S8Fmt(arena,"Expected an internal monologue for your character enclosed by '[' and ']' after the speech in quotes, but couldn't find anything!");
error_message= FmtWithLint(arena,"Expected an internal monologue for your character enclosed by '[' and ']' after the speech in quotes, but couldn't find anything!");