Formatting, initial datastructure sketch of new character engine

main
Cameron Murphy Reikes 7 months ago
parent b23078f219
commit 14d33756cd

2869
main.c

File diff suppressed because it is too large Load Diff

@ -111,7 +111,7 @@ typedef struct
} ActionArgument;
typedef struct Action
typedef struct ActionOld
{
ActionKind kind;
ActionArgument argument;
@ -119,7 +119,7 @@ typedef struct Action
TextChunk speech;
NpcKind talking_to_kind;
} Action;
} ActionOld;
typedef struct
{
@ -279,10 +279,70 @@ float entity_max_damage(Entity *e)
typedef BUFF(ActionKind, 8) AvailableActions;
typedef enum HealthStatus {
HEALTH_ok,
HEALTH_decent,
HEALTH_dying,
HEALTH_verge_of_death,
} HealthStatus;
typedef struct Health {
HealthStatus status;
float drunkenness; // 1.0 is max drunkenness
} Health;
typedef enum ItemKind {
ITEM_none,
ITEM_whiskey,
} ItemKind;
typedef struct Item {
ItemKind kind;
int times_used;
} Item;
typedef enum EventKind {
EVENT_none,
EVENT_said_to,
EVENT_stopped_talking,
} EventKind;
typedef struct Response {
TextChunk text;
ActionKind action;
NpcKind target;
int memory_slot;
} Response;
typedef BUFF(Response, 5) FullResponse; // what the AI is allowed to output
typedef struct CharacterPerception {
Health health;
} CharacterPerception;
typedef struct CharacterStatus {
TextChunk goal;
u64 in_room;
Item held_item;
Health health;
} CharacterStatus;
// the situation for somebody
typedef struct CharacterSituation {
TextChunk memories[4]; // explicit numbered memories
BUFF(TextChunk, 5) events; // events that this character has observed
CharacterStatus status;
} CharacterSituation;
typedef struct TrainingSample {
CharacterSituation situation;
Response response;
} TrainingSample;
typedef struct Npc {
TextChunk name;
NpcKind kind; // must not be 0, that's nobody!
TextChunk prompt;
BUFF(TrainingSample, 4) soul;
} Npc;
typedef struct EditorState {
@ -291,6 +351,7 @@ typedef struct EditorState {
Vec2 camera_panning_target;
Vec2 camera_panning;
NpcKind placing_npc;
NpcKind editing_npc;
bool placing_spawn;
u64 player_spawn_roomid;
@ -343,9 +404,7 @@ Npc *npc_data(GameState *gs, NpcKind kind) {
return it;
}
}
Log("Unknown npc kind '%d'\n", kind);
assert(false);
return 0;
return &nobody_data;
}
NpcKind get_next_kind(GameState *gs) {
NpcKind max_found = 0;
@ -587,7 +646,7 @@ String8 generate_chatgpt_prompt(Arena *arena, GameState *gs, Entity *e, CanTalkT
{
String8List current_list = {0};
AddFmt("%s\n\n", global_prompt);
AddFmt("%.*s\n\n", TextChunkVArg(npc_data(gs, e->npc_kind)->prompt));
// AddFmt("%.*s\n\n", TextChunkVArg(npc_data(gs, e->npc_kind)->prompt));
AddFmt("The characters who are near you, that you can target:\n");
BUFF_ITER(Entity*, &can_talk_to)
{
@ -706,13 +765,13 @@ void parse_action_argument(Arena *error_arena, GameState *gs, String8 *cur_error
// if returned string has size greater than 0, it's the error message. Allocated
// on arena passed into it or in constant memory
String8 parse_chatgpt_response(Arena *arena, GameState *gs, Entity *e, String8 action_in_json, Action *out)
String8 parse_chatgpt_response(Arena *arena, GameState *gs, Entity *e, String8 action_in_json, ActionOld *out)
{
ArenaTemp scratch = GetScratch(&arena, 1);
String8 error_message = {0};
*out = (Action) { 0 };
*out = (ActionOld) { 0 };
ParseResult result = ParseWholeString(scratch.arena, S8Lit("chat_message"), action_in_json);
if(result.errors.node_count > 0)

@ -0,0 +1,9 @@
@echo off
cl /nologo /diagnostics:caret /DDEVTOOLS /Igen /Ithirdparty /Wall /FC /Zi /WX playground.c /link /noimplib /noexp || goto :error
goto :EOF
:error
echo Failed to build
exit /B %ERRORLEVEL%

@ -0,0 +1,111 @@
#include <stdio.h>
#pragma warning(disable : 4820) // don't care about padding
#pragma warning(disable : 4388) // signed/unsigned mismatch probably doesn't matter
// #pragma warning(disable : 4100) // unused local doesn't matter, because sometimes I want to kee
#pragma warning(disable : 4053) // void operands are used for tricks like applying printf linting to non printf function calls
#pragma warning(disable : 4255) // strange no function prototype given thing?
#pragma warning(disable : 4456) // I shadow local declarations often and it's fine
#pragma warning(disable : 4061) // I don't need to *explicitly* handle everything, having a default: case should mean no more warnings
#pragma warning(disable : 4201) // nameless struct/union occurs
#pragma warning(disable : 4366) // I think unaligned memory addresses are fine to ignore
#pragma warning(disable : 4459) // Local function decl hiding global declaration I think is fine
#pragma warning(disable : 5045) // spectre mitigation??
#pragma warning(disable : 4244) // loss of data warning
#pragma warning(disable : 4101) // unreferenced local variable
#pragma warning(disable : 4100) // unreferenced local variable again?
#pragma warning(disable : 4189) // initialized and not referenced
#pragma warning(disable : 4242) // conversion
#pragma warning(disable : 4457) // hiding function variable happens
#pragma warning(disable : 4668) // __GNU_C__ macro undefined, fixing
#pragma warning(disable : 4996) // fopen is safe. I don't care about fopen_s
#include "md.h"
#include "md.c"
#define DESKTOP
#define WINDOWS
#define RND_IMPLEMENTATION
#include "makeprompt.h"
#include <windows.h> // for sleep.
void error_impl(Arena *arena, String8List *errors, String8 message)
{
S8ListPush(arena, errors, message);
// this is a function so you can breakpoint here and discover when errors occur
}
#define error(fmt_str, ...) error_impl(arena, errors, S8Fmt(arena, fmt_str, __VA_ARGS__))
// Allows you to not need to quote children of a parent.
String8 all_children_as_string(Arena *arena, Node *parent)
{
String8List children = {0};
for (Node *cur = parent->first_child; !NodeIsNil(cur); cur = cur->next)
{
S8ListPush(arena, &children, cur->string);
}
return S8ListJoin(arena, children, &(StringJoin){.mid = S8Lit(" ")});
}
Node *get_child_should_exist(Arena *arena, String8List *errors, Node *parent, String8 child_name)
{
if (errors->node_count > 0)
return NilNode();
Node *child = MD_ChildFromString(parent, child_name, StringMatchFlag_CaseInsensitive);
if (NodeIsNil(child))
{
error("Couldn't find child with name '%.*s' on node '%.*s'", S8VArg(child_name), S8VArg(parent->string));
}
return child;
}
typedef struct {
}
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
Arena *arena = ArenaAlloc();
ParseResult result = ParseWholeFile(arena, S8Lit("playground.mdesk"));
if (result.errors.node_count > 0)
{
printf("Failed to parse file:\n");
for (Message *cur = result.errors.first; cur->next; cur = cur->next)
{
printf("%.*s\n", S8VArg(cur->string));
}
}
else
{
Node *node = result.node;
String8List errors_list = {0};
String8List *errors = &errors_list;
Npc out;
chunk_from_s8(&out.name, all_children_as_string(arena, get_child_should_exist(arena, errors, node, S8Lit("name"))));
if (errors->node_count == 0)
{
// unit testing asserts
assert(S8Match(TextChunkString8(out.name), S8Lit("Roger Penrose"), 0));
}
else
{
printf("Corrupt character soul:\n");
for (String8Node *cur = errors->first; cur->next; cur = cur->next)
{
printf("%.*s\n", S8VArg(cur->string));
}
assert(false);
}
}
printf("Success.\n");
__debugbreak();
}

@ -0,0 +1,27 @@
Name: Roger Penrose
Prompt: He is an illusive testing character, who confounds even the most brilliant philosophers and doctors to this date.
Soul:
{
{
Situation: {
Memories: [
"mem1",
"",
"mem3",
]
Events: [
{
Author: Jesse Pinkman
Response: {
speech: "How dare you!"
action: SAY_TO
}
}
]
}
Response: {
}
},
}

@ -0,0 +1,31 @@
Name: Roger Penrose
Description: He is an illusive testing character, who confounds even the most brilliant philosophers and doctors to this date.
Soul:
Situation #0:
Memory #0: I'm being
Memory #1: Silly
Perception:
In Room: Farm
Characters Around Me:
John:
Health Status: decent
Drunkenness: 0.0
Holding: nothing
Items Around Me:
Whiskey
My Status:
Health Status: decent
Drunkenness: 0.5
Holding: whiskey
Previous Event #0: John said to me, "Why are you like that bro?"
Previous Event #1: I said to John, "Just because"
Response:
Say_To:
To: John
Speech: Why are you like that dude?
Throw:
To: John
Loading…
Cancel
Save