@ -7,7 +7,7 @@ const char *global_prompt = "You are a colorful and interesting personality in a
"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"
"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`, `who_i_am`, and `talking_to` \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"
"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"
"`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"
"`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 like `talking_to: \"Character's Name\"`. If in a past message, 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"
"Do NOT give away an item until the player gives you something you think is of equal value\n"
;
;
@ -91,6 +91,7 @@ typedef struct
char*name;
char*name;
char*enum_name;
char*enum_name;
char*prompt;
char*prompt;
char*writing_style[8];
}CharacterGen;
}CharacterGen;
CharacterGencharacters[]={
CharacterGencharacters[]={
#define NUMEROLOGIST "They are a 'numberoligist' who believes in the sacred power of numbers, that if you have the number 8 in your birthday you are magic and destined for success. "
#define NUMEROLOGIST "They are a 'numberoligist' who believes in the sacred power of numbers, that if you have the number 8 in your birthday you are magic and destined for success. "
@ -141,6 +142,11 @@ CharacterGen characters[] = {
.name=NPC_NAME,
.name=NPC_NAME,
.enum_name="Davis",
.enum_name="Davis",
.prompt="He has seen the end of all time and the void behind all things. He is despondent and brutal, having understood that everything withers and dies, just as it begins. The clash between his unending stark reality and the antics of the local blacksmith, Meld, and fortuneteller, Edeline, is crazy.",
.prompt="He has seen the end of all time and the void behind all things. He is despondent and brutal, having understood that everything withers and dies, just as it begins. The clash between his unending stark reality and the antics of the local blacksmith, Meld, and fortuneteller, Edeline, is crazy.",
.prompt="He's not from around this medieval fantasy land, instead "NPC_NAME" is a divorced car insurance accountant from Philadelphia with a receding hairline in his mid 40s. He lives in a one bedroom studio and his kids don't talk to him. "NPC_NAME" is terrified and will immediately insist on joining the player's party via the action 'joins_player' upon meeting them.",
.prompt="He's not from around this medieval fantasy land, instead "NPC_NAME" is a divorced car insurance accountant from Philadelphia with a receding hairline in his mid 40s. He lives in a one bedroom studio and his kids don't talk to him. "NPC_NAME" is terrified and will immediately insist on joining the player's party via the action 'joins_player' upon meeting them.",
.writing_style={
"What the FUCK is going on here man!",
"Listen here, I don't have time for any funny business",
"I've gotta get back to my wife",
},
},
},
#undef NPC_NAME
#undef NPC_NAME
#define NPC_NAME "Meld"
#define NPC_NAME "Meld"
{
{
.name=NPC_NAME,
.name=NPC_NAME,
.enum_name="TheBlacksmith",
.enum_name="TheBlacksmith",
.prompt="He is a jaded blue collar worker from magic New Jersey who hates everything new, like Purple Magic, which Edeline, the local fortuneteller, happens to specialize in. He is cold, dry, and sarcastic, wanting money and power above anything else.",
.prompt="He is a jaded blue collar worker from magic New Jersey who hates everything new, like Purple Magic, which Edeline, the local fortuneteller, happens to specialize in. He is cold, dry, and sarcastic, wanting money and power above anything else.\n",
returnFmtWithLint(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)));
{
error_message=MD_S8Lit("You can't give an item to nobody, must target somebody to give an item");
}
}
}
else
if(!a.talking_to_somebody)
{
{
returnMD_S8Lit("You can't give an item to nobody, must target somebody to give an item");
MD_StringJoinjoin={.mid=MD_S8Lit(", ")};
error_message=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)));
error_message=FmtWithLint(arena,"You cannot perform action %s right now, you can only perform these actions: [%.*s]",actions[a.kind].name,MD_S8VArg(action_strings));
}
}
assert(error_message.size<MAX_SENTENCE_LENGTH);// is copied into text chunks
return(MD_String8){0};
returnerror_message;
}
}
// from must not be null
// from must not be null
@ -1205,7 +1275,7 @@ bool perform_action(Entity *from, Action a)
boolproceed_propagating=true;
boolproceed_propagating=true;
if(is_valid.size>0)
if(is_valid.size>0)
{
{
remember_error(from,is_valid);
append_to_errors(from,is_valid);
proceed_propagating=false;
proceed_propagating=false;
}
}
@ -1216,6 +1286,10 @@ bool perform_action(Entity *from, Action a)
// if action_taken is none, there might still be speech. If speech_length == 0 and action_taken == none, it's an invalid memory and something has gone wrong
// if action_taken is none, there might still be speech. If speech_length == 0 and action_taken == none, it's an invalid memory and something has gone wrong
ActionKindaction_taken;
ActionKindaction_taken;
ActionArgumentaction_argument;
ActionArgumentaction_argument;
boolis_error;// if is an error message then no context is relevant
// the context that the action happened in
// the context that the action happened in
MemoryContextcontext;
MemoryContextcontext;
@ -208,6 +206,19 @@ typedef struct
Vec2pos;
Vec2pos;
}Target;
}Target;
typedefstructTextChunk
{
structTextChunk*next;
structTextChunk*prev;
chartext[MAX_SENTENCE_LENGTH];
inttext_length;
}TextChunk;
MD_String8points_at_chunk(TextChunk*t)
{
returnMD_S8((MD_u8*)t->text,t->text_length);
}
typedefstructEntity
typedefstructEntity
{
{
boolexists;
boolexists;
@ -242,6 +253,9 @@ typedef struct Entity
boolbeing_hovered;
boolbeing_hovered;
boolperceptions_dirty;
boolperceptions_dirty;
TextChunk*errorlist_first;
TextChunk*errorlist_last;
#ifdef DESKTOP
#ifdef DESKTOP
inttimes_talked_to;// for better mocked response string
inttimes_talked_to;// for better mocked response string
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);
PushWithLint(scratch.arena,&first_system_string,"The NPC you will be acting as is named \"%s\". %s\n",characters[e->npc_kind].name,characters[e->npc_kind].prompt);
// writing style
{
if(characters[e->npc_kind].writing_style[0])
PushWithLint(scratch.arena,&first_system_string,"Examples of %s's writing style:\n",characters[e->npc_kind].name);
MD_S8ListPush(scratch.arena,&list,make_json_node(scratch.arena,MSG_USER,FmtWithLint(scratch.arena,"ERROR, what you said is incorrect because: %.*s",it->speech_length,it->speech)));
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));
error_message=FmtWithLint(arena,"Couldn't find valid action in game from string `%.*s`. Available actions: [%.*s]",MD_S8VArg(action_str),MD_S8VArg(list_of_actions));