@ -460,6 +460,14 @@ LPCWSTR windows_string(String8 s)
}
# endif
typedef enum
{
GEN_Deleted = - 1 ,
GEN_NotDoneYet = 0 ,
GEN_Success = 1 ,
GEN_Failed = 2 ,
} GenRequestStatus ;
# ifdef DESKTOP
# ifdef WINDOWS
# pragma warning(push, 3)
@ -472,6 +480,8 @@ typedef struct ChatRequest
{
struct ChatRequest * next ;
struct ChatRequest * prev ;
bool user_is_done_with_this_request ;
bool thread_is_done_with_this_request ;
bool should_close ;
int id ;
int status ;
@ -549,7 +559,7 @@ void generation_thread(void* my_request_voidptr)
WinAssertWithErrorCode ( WinHttpReadData ( hRequest , ( LPVOID ) out_buffer , dwSize , & dwDownloaded ) ) ;
out_buffer [ dwDownloaded - 1 ] = ' \0 ' ;
Log ( " Got this from http, size %lu: %s \n " , dwDownloaded , out_buffer ) ;
S8ListPush ( my_request - > arena , & received_data_list , S8 ( out_buffer , dwDownloaded ) ) ;
S8ListPush ( my_request - > arena , & received_data_list , S8 ( out_buffer , dwDownloaded - 1 ) ) ; // the string shouldn't include a null terminator in its length, and WinHttpReadData has a null terminator here
}
} while ( dwSize > 0 ) ;
String8 received_data = S8ListJoin ( my_request - > arena , received_data_list , & ( StringJoin ) { 0 } ) ;
@ -564,10 +574,13 @@ void generation_thread(void* my_request_voidptr)
chunk_from_s8 ( & my_request - > generated , ai_response ) ;
my_request - > status = 1 ;
}
my_request - > thread_is_done_with_this_request = true ; // @TODO Threads that finish and users who forget to mark them as done aren't collected right now, we should do that to prevent leaks
}
int make_generation_request ( String8 p ost_req_body )
int make_generation_request ( String8 p rompt )
{
ArenaTemp scratch = GetScratch ( 0 , 0 ) ;
String8 post_req_body = FmtWithLint ( scratch . arena , " |%.*s " , S8VArg ( prompt ) ) ;
// checking for taken characters, pipe should only occur at the beginning
for ( u64 i = 1 ; i < post_req_body . size ; i + + )
{
@ -578,8 +591,7 @@ int make_generation_request(String8 post_req_body)
if ( requests_free_list )
{
to_return = requests_free_list ;
requests_free_list = requests_free_list - > next ;
//StackPop(requests_free_list);
StackPop ( requests_free_list ) ;
* to_return = ( ChatRequest ) { 0 } ;
}
else
@ -599,6 +611,7 @@ int make_generation_request(String8 post_req_body)
DblPushBack ( requests_first , requests_last , to_return ) ;
ReleaseScratch ( scratch ) ;
return to_return - > id ;
}
@ -609,28 +622,94 @@ ChatRequest *get_by_id(int id)
{
for ( ChatRequest * cur = requests_first ; cur ; cur = cur - > next )
{
if ( cur - > id = = id )
if ( cur - > id = = id & & ! cur - > user_is_done_with_this_request )
{
return cur ;
}
}
assert ( false ) ;
return 0 ;
}
void done_with_request ( int id )
{
ChatRequest * req = get_by_id ( id ) ;
if ( req )
{
if ( req - > thread_is_done_with_this_request )
{
ArenaRelease ( req - > arena ) ;
DblRemove ( requests_first , requests_last , req ) ;
* req = ( ChatRequest ) { 0 } ;
StackPush ( requests_free_list , req ) ;
}
else
{
req - > user_is_done_with_this_request = true ;
}
}
}
GenRequestStatus gen_request_status ( int id )
{
ChatRequest * req = get_by_id ( id ) ;
if ( ! req )
return GEN_Deleted ;
else
return req - > status ;
}
TextChunk gen_request_content ( int id )
{
assert ( get_by_id ( id ) ) ;
return get_by_id ( id ) - > generated ;
}
# else
ISANERROR ( " Only know how to do desktop http requests on windows " )
# endif // WINDOWS
# endif // DESKTOP
# ifdef WEB
int make_generation_request ( String8 prompt_str )
{
ArenaTemp scratch = GetScratch ( 0 , 0 ) ;
String8 terminated_completion_url = nullterm ( scratch . arena , FmtWithLint ( scratch . arena , " %s://%s:%d/completion " , IS_SERVER_SECURE ? " https " : " http " , SERVER_DOMAIN , SERVER_PORT ) ) ;
int req_id = EM_ASM_INT ( {
return make_generation_request ( UTF8ToString ( $ 0 , $ 1 ) , UTF8ToString ( $ 2 , $ 3 ) ) ;
} ,
prompt_str . str , ( int ) prompt_str . size , terminated_completion_url . str , ( int ) terminated_completion_url . size ) ;
ReleaseScratch ( scratch ) ;
return req_id ;
}
GenRequestStatus gen_request_status ( int id )
{
int status = EM_ASM_INT ( {
return get_generation_request_status ( $ 0 ) ;
} , id ) ;
return status ;
}
TextChunk gen_request_content ( int id )
{
char sentence_cstr [ MAX_SENTENCE_LENGTH ] = { 0 } ;
EM_ASM ( {
let generation = get_generation_request_content ( $ 0 ) ;
stringToUTF8 ( generation , $ 1 , $ 2 ) ;
} ,
id , sentence_cstr , ARRLEN ( sentence_cstr ) - 1 ) ; // I think minus one for null terminator...
TextChunk to_return = { 0 } ;
memcpy ( to_return . text , sentence_cstr , MAX_SENTENCE_LENGTH ) ;
to_return . text_length = strlen ( sentence_cstr ) ;
return to_return ;
}
void done_with_request ( int id )
{
EM_ASM ( {
done_with_generation_request ( $ 0 ) ;
} ,
id ) ;
}
# endif // WEB
Memory * memories_free_list = 0 ;
RememberedError * remembered_error_free_list = 0 ;
@ -1064,6 +1143,7 @@ typedef struct
u64 vertices_length ;
sg_buffer loaded_buffer ;
uint64_t last_updated_bones_frame ;
sg_image bones_texture ;
sg_image image ;
int bones_texture_width ;
@ -1694,10 +1774,12 @@ CanTalkTo get_can_talk_to(Entity *e)
Entity * get_targeted ( Entity * from , NpcKind targeted )
{
bool ignore_radius = from - > npc_kind = = NPC_Player | | targeted = = NPC_Player ; // player conversations can go across the map to make sure the player always sees them
ENTITIES_ITER ( gs . entities )
{
if ( it ! = from & & ( it - > is_npc ) & & LenV2 ( SubV2 ( it - > pos , from - > pos ) ) < PROPAGATE_ACTIONS_RADIUS & & it - > npc_kind = = targeted )
if ( it ! = from & & ( it - > is_npc ) & & it - > npc_kind = = targeted )
{
if ( ignore_radius | | LenV2 ( SubV2 ( it - > pos , from - > pos ) ) < PROPAGATE_ACTIONS_RADIUS )
return it ;
}
}
@ -1740,6 +1822,14 @@ String8 is_action_valid(Arena *arena, Entity *from, Action a)
String8 error_message = ( String8 ) { 0 } ;
if ( error_message . size = = 0 & & a . speech . text_length > 0 )
{
if ( S8FindSubstring ( TextChunkString8 ( a . speech ) , S8Lit ( " assist " ) , 0 , StringMatchFlag_CaseInsensitive ) ! = a . speech . text_length )
{
error_message = S8Lit ( " You cannot use the word 'assist' in any form, you are not an assistant, do not act overtly helpful " ) ;
}
}
CanTalkTo talk = get_can_talk_to ( from ) ;
if ( error_message . size = = 0 & & a . talking_to_kind )
{
@ -1752,7 +1842,7 @@ String8 is_action_valid(Arena *arena, Entity *from, Action a)
break ;
}
}
if ( from - > npc_kind = = NPC_Player ) found = true ; // player can always speak to anybody even if it's too far
if ( from - > npc_kind = = NPC_Player | | a . talking_to_kind = = NPC_Player ) found = true ; // player can always speak to anybody even if it's too far
if ( ! found )
{
error_message = FmtWithLint ( arena , " Character you're talking to, %s, isn't close enough to be talked to " , characters [ a . talking_to_kind ] . enum_name ) ;
@ -1938,6 +2028,7 @@ bool perform_action(GameState *gs, Entity *from, Action a)
context . talking_to_kind = a . talking_to_kind ;
String8 is_valid = is_action_valid ( scratch . arena , from , a ) ;
bool proceed_propagating = true ;
if ( is_valid . size > 0 )
@ -1947,6 +2038,8 @@ bool perform_action(GameState *gs, Entity *from, Action a)
proceed_propagating = false ;
}
bool angel_heard_action = false ;
Entity * targeted = 0 ;
@ -2006,6 +2099,43 @@ bool perform_action(GameState *gs, Entity *from, Action a)
remember_action ( gs , gs - > angel , a , angel_context ) ;
}
if ( from - > npc_kind = = NPC_Daniel | | a . talking_to_kind = = NPC_Daniel )
{
Memory * new_forever = PushArray ( gs - > arena , Memory , 1 ) ;
* new_forever = make_memory ( a , ( MemoryContext ) { . author_npc_kind = from - > npc_kind , . talking_to_kind = a . talking_to_kind , . judgement_memory = true } ) ;
DblPushBack ( gs - > judgement_memories_first , gs - > judgement_memories_last , new_forever ) ;
}
if ( from - > npc_kind = = NPC_Daniel )
{
if ( gs - > judgement_gen_request = = 0 & & gs - > judgement_memories_first )
{
String8List history_list = { 0 } ;
for ( Memory * it = gs - > judgement_memories_first ; it ; it = it - > next )
{
String8List desc = memory_description ( scratch . arena , gs - > world_entity , it ) ;
S8ListConcat ( & history_list , & desc ) ;
}
String8 current_history = S8ListJoin ( scratch . arena , history_list , & ( StringJoin ) { 0 } ) ;
Log ( " Submitting judgement with current history: ``` \n %.*s \n ``` \n " , S8VArg ( current_history ) ) ;
String8List current_list = { 0 } ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_SYSTEM , S8CString ( judgement_system_prompt ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_USER , S8CString ( judgement_yes_example ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_ASSISTANT , S8Lit ( " yes " ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_USER , S8CString ( judgement_no_example ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_ASSISTANT , S8Lit ( " no " ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_USER , S8CString ( judgement_no2_example ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_ASSISTANT , S8Lit ( " no " ) ) ) ;
S8ListPush ( scratch . arena , & current_list , make_json_node ( scratch . arena , MSG_USER , current_history ) ) ;
String8 json_array = S8ListJoin ( scratch . arena , current_list , & ( StringJoin ) { 0 } ) ;
json_array . size - = 1 ; // remove trailing comma. fuck json
String8 prompt = FmtWithLint ( scratch . arena , " [%.*s] " , S8VArg ( json_array ) ) ;
gs - > judgement_gen_request = make_generation_request ( prompt ) ;
}
}
ReleaseScratch ( scratch ) ;
return proceed_propagating ;
}
@ -2183,7 +2313,12 @@ void transition_to_room(GameState *gs, ThreeDeeLevel *level, String8 new_room_na
void initialize_gamestate_from_threedee_level ( GameState * gs , ThreeDeeLevel * level )
{
if ( gs - > arena )
{
ArenaRelease ( gs - > arena ) ;
}
memset ( gs , 0 , sizeof ( GameState ) ) ;
gs - > arena = ArenaAlloc ( ) ;
rnd_gamerand_seed ( & gs - > random , RANDOM_SEED ) ;
// make entities for all rooms
@ -3350,6 +3485,7 @@ String8 make_devtools_help(Arena *arena)
P ( " P - toggles spall profiling on/off, don't leave on for very long as it consumes a lot of storage if you do that. The resulting spall trace is saved to the file '%s' \n " , PROFILING_SAVE_FILENAME ) ;
P ( " If you hover over somebody it will display some parts of their memories, can be somewhat helpful \n " ) ;
P ( " P - immediately kills %s \n " , characters [ NPC_Raphael ] . name ) ;
P ( " J - judges the player and outputs their verdict to the console \n " ) ;
# undef P
String8 to_return = S8ListJoin ( arena , list , & ( StringJoin ) { 0 } ) ;
@ -3432,7 +3568,7 @@ void init(void)
shifted_farmer_armature = load_armature ( persistent_arena , binary_file , S8Lit ( " Farmer.bin " ) ) ;
shifted_farmer_armature . image = image_shifted_farmer ;
Log ( " Done. Used %f of the frame arena, % llu kB\n " , ( double ) frame_arena - > pos / ( double ) frame_arena - > cap , ( frame_arena - > pos / 1024 ) ) ;
Log ( " Done. Used %f of the frame arena, % d kB\n " , ( double ) frame_arena - > pos / ( double ) frame_arena - > cap , ( int ) ( frame_arena - > pos / 1024 ) ) ;
ArenaClear ( frame_arena ) ;
@ -5035,6 +5171,7 @@ double elapsed_time = 0.0;
double unwarped_elapsed_time = 0.0 ;
double last_frame_processing_time = 0.0 ;
double last_frame_gameplay_processing_time = 0.0 ;
uint64_t frame_index = 0 ; // for rendering tick stuff, gamestate tick is used for game logic tick stuff and is serialized/deserialized/saved
uint64_t last_frame_time ;
typedef struct
@ -5114,10 +5251,13 @@ bool imbutton_key(ImbuttonArgs args)
TextParams t = ( TextParams ) { false , args . text , aabb_center ( args . button_aabb ) , BLACK , args . text_scale , . clip_to = args . button_aabb , . do_clipping = true , . layer = layer , . use_font = font } ;
t . dry_run = true ;
AABB aabb = draw_text ( t ) ;
if ( aabb_is_valid ( aabb ) )
{
t . dry_run = false ;
t . pos = SubV2 ( aabb_center ( args . button_aabb ) , MulV2F ( aabb_size ( aabb ) , 0.5f ) ) ;
draw_text ( t ) ;
}
}
hmput ( imui_state , args . key , state ) ;
return to_return ;
@ -5430,10 +5570,16 @@ void flush_all_drawn_things(ShadowMats shadow)
}
}
// sokol prohibits updating an image more than once per frame
if ( armature - > last_updated_bones_frame ! = frame_index )
{
armature - > last_updated_bones_frame = frame_index ;
sg_update_image ( armature - > bones_texture , & ( sg_image_data ) {
. subimage [ 0 ] [ 0 ] = ( sg_range ) { bones_tex , bones_tex_size } ,
} ) ;
}
ReleaseScratch ( scratch ) ;
}
}
@ -5591,7 +5737,7 @@ TextPlacementSettings speech_bubble = {
String8List words_on_current_page ( Entity * it , TextPlacementSettings * settings )
{
String8 last = last_said_sentence ( it ) ;
PlacedWordList placed = place_wrapped_words ( frame_arena , split_by_word ( frame_arena , last ) , settings - > text_scale , settings - > width_in_pixels, * settings - > font , JUST_LEFT ) ;
PlacedWordList placed = place_wrapped_words ( frame_arena , split_by_word ( frame_arena , last ) , settings - > text_scale , settings - > text_ width_in_pixels, * settings - > font , JUST_LEFT ) ;
String8List on_current_page = { 0 } ;
for ( PlacedWord * cur = placed . first ; cur ; cur = cur - > next )
@ -5644,6 +5790,7 @@ void frame(void)
double dt_double = unwarped_dt_double * speed_factor ;
float unwarped_dt = ( float ) unwarped_dt_double ;
float dt = ( float ) dt_double ;
frame_index + = 1 ;
#if 0
{
@ -5669,6 +5816,8 @@ void frame(void)
{
uint64_t time_start_frame = stm_now ( ) ;
gs . time + = dt_double ;
text_input_fade = Lerp ( text_input_fade , unwarped_dt * 8.0f , receiving_text_input ? 1.0f : 0.0f ) ;
Vec3 player_pos = V3 ( gs . player - > pos . x , 0.0 , gs . player - > pos . y ) ;
@ -5713,8 +5862,8 @@ void frame(void)
Vec3 light_dir ;
{
float t = ( float ) ( elapsed_time / 3.0f - floor ( elapsed_time / 3.0f ) ) ;
Vec3 sun_vector = V3 ( 2.0f * t - 1.0f , sinf ( t * PI32 ) , 0.8f ) ; // where the sun is pointing from
float t = clamp01 ( ( float ) ( gs . time / LENGTH_OF_DAY ) ) ;
Vec3 sun_vector = V3 ( 2.0f * t - 1.0f , sinf ( t * PI32 ) * 0.8f + 0.2f , 0.8f ) ; // where the sun is pointing from
light_dir = NormV3 ( MulV3F ( sun_vector , - 1.0f ) ) ;
}
@ -5849,6 +5998,7 @@ void frame(void)
case NPC_Devil :
case NPC_PreviousPlayer1 :
case NPC_PreviousPlayer2 :
case NPC_PreviousPlayer3 :
assert ( false ) ;
break ;
}
@ -6101,6 +6251,39 @@ void frame(void)
}
}
if ( gs . judgement_gen_request ! = 0 )
{
GenRequestStatus stat = gen_request_status ( gs . judgement_gen_request ) ;
switch ( stat )
{
case GEN_NotDoneYet :
break ;
case GEN_Success :
{
TextChunk generated = gen_request_content ( gs . judgement_gen_request ) ;
if ( generated . text_length > 0 & & S8FindSubstring ( TextChunkString8 ( generated ) , S8Lit ( " yes " ) , 0 , StringMatchFlag_CaseInsensitive ) = = 0 )
{
Log ( " Starts with yes, success! \n " ) ;
gs . won = true ;
}
else if ( S8FindSubstring ( TextChunkString8 ( generated ) , S8Lit ( " no " ) , 0 , StringMatchFlag_CaseInsensitive ) = = generated . text_length )
{
Log ( " WARNING: generated judgement string '%.*s', doesn't match yes or no, and so is nonsensical! AI acting up! \n " , TextChunkVArg ( generated ) ) ;
}
}
break ;
case GEN_Failed :
having_errors = true ;
break ;
case GEN_Deleted :
break ;
}
if ( stat ! = GEN_NotDoneYet )
{
done_with_request ( gs . judgement_gen_request ) ;
gs . judgement_gen_request = 0 ;
}
}
// @Place(UI rendering that happens before gameplay processing so can consume events before the gameplay needs them)
PROFILE_SCOPE ( " Entity UI Rendering " )
@ -6303,47 +6486,26 @@ void frame(void)
{
assert ( it - > gen_request_id > 0 ) ;
# ifdef DESKTOP
int status = get_by_id ( it - > gen_request_id ) - > status ;
# else
# ifdef WEB
int status = EM_ASM_INT ( {
return get_generation_request_status ( $ 0 ) ;
} , it - > gen_request_id ) ;
# else
ISANERROR ( " Don't know how to do this stuff on this platform. " )
# endif // WEB
# endif // DESKTOP
if ( status = = 0 )
{
// simply not done yet
}
else
GenRequestStatus status = gen_request_status ( it - > gen_request_id ) ;
switch ( status )
{
if ( status = = 1 )
case GEN_Deleted :
it - > gen_request_id = 0 ;
break ;
case GEN_NotDoneYet :
break ;
case GEN_Success :
{
having_errors = false ;
// done! we can get the string
char sentence_cstr [ MAX_SENTENCE_LENGTH ] = { 0 } ;
# ifdef WEB
EM_ASM ( {
let generation = get_generation_request_content ( $ 0 ) ;
stringToUTF8 ( generation , $ 1 , $ 2 ) ;
} , it - > gen_request_id , sentence_cstr , ARRLEN ( sentence_cstr ) - 1 ) ; // I think minus one for null terminator...
# endif
# ifdef DESKTOP
memcpy ( sentence_cstr , get_by_id ( it - > gen_request_id ) - > generated . text , get_by_id ( it - > gen_request_id ) - > generated . text_length ) ;
# endif
String8 sentence_str = S8CString ( sentence_cstr ) ;
TextChunk sentence_chunk = gen_request_content ( it - > gen_request_id ) ;
String8 sentence_str = TextChunkString8 ( sentence_chunk ) ;
// parse out from the sentence NPC action and dialog
Action out = { 0 } ;
ArenaTemp scratch = GetScratch ( 0 , 0 ) ;
Log ( " Parsing `%.*s`... \n " , S8VArg ( sentence_str ) ) ;
String8 parse_response = parse_chatgpt_response ( scratch. arena, it , sentence_str , & out ) ;
String8 parse_response = parse_chatgpt_response ( frame_arena , it , sentence_str , & out ) ;
// check that it wraps in below two lines
TextPlacementSettings * to_wrap_to = & speech_bubble ;
@ -6368,8 +6530,6 @@ ISANERROR("Don't know how to do this stuff on this platform.")
{
Log ( " Performing action %s! \n " , actions [ out . kind ] . name ) ;
perform_action ( & gs , it , out ) ;
}
else
{
@ -6378,42 +6538,19 @@ ISANERROR("Don't know how to do this stuff on this platform.")
}
}
ReleaseScratch ( scratch ) ;
# ifdef WEB
EM_ASM ( {
done_with_generation_request ( $ 0 ) ;
} , it - > gen_request_id ) ;
# endif
# ifdef DESKTOP
done_with_request ( it - > gen_request_id ) ;
# endif
it - > gen_request_id = 0 ;
}
else if ( status = = 2 )
{
break ;
case GEN_Failed :
Log ( " Failed to generate dialog! Fuck! \n " ) ;
having_errors = true ;
/*
Action to_perform = { 0 } ;
String8 speech_mdstring = S8Lit ( " I'm not sure... " ) ;
memcpy ( to_perform . speech , speech_mdstring . str , speech_mdstring . size ) ;
to_perform . speech_length = ( int ) speech_mdstring . size ;
perform_action ( & gs , it , to_perform ) ;
*/
}
else if ( status = = - 1 )
{
Log ( " Generation request doesn't exist anymore, that's fine... \n " ) ;
}
else
{
it - > gen_request_id = 0 ;
break ;
default :
Log ( " Unknown generation request status: %d \n " , status ) ;
}
it - > gen_request_id = 0 ;
break ;
}
}
}
@ -6830,38 +6967,19 @@ ISANERROR("Don't know how to do this stuff on this platform.")
{
it - > perceptions_dirty = false ; // needs to be in beginning because they might be redirtied by the new perception
String8 prompt_str = { 0 } ;
# ifdef DO_CHATGPT_PARSING
prompt_str = generate_chatgpt_prompt ( frame_arena , & gs , it , get_can_talk_to ( it ) ) ;
# else
generate_prompt ( it , & prompt ) ;
# endif
Log ( " Sending request with prompt `%.*s` \n " , S8VArg ( prompt_str ) ) ;
# ifdef WEB
// fire off generation request, save id
ArenaTemp scratch = GetScratch ( 0 , 0 ) ;
String8 terminated_completion_url = nullterm ( scratch . arena , FmtWithLint ( scratch . arena , " %s://%s:%d/completion " , IS_SERVER_SECURE ? " https " : " http " , SERVER_DOMAIN , SERVER_PORT ) ) ;
int req_id = EM_ASM_INT ( {
return make_generation_request ( UTF8ToString ( $ 0 , $ 1 ) , UTF8ToString ( $ 2 , $ 3 ) ) ;
} ,
prompt_str . str , ( int ) prompt_str . size , terminated_completion_url . str , ( int ) terminated_completion_url . size ) ;
it - > gen_request_id = req_id ;
ReleaseScratch ( scratch ) ;
# endif
Log ( " Want to make request with prompt `%.*s` \n " , S8VArg ( prompt_str ) ) ;
# ifdef DESKTOP
ArenaTemp scratch = GetScratch ( 0 , 0 ) ;
String8 ai_response = { 0 } ;
bool mocking_the_ai_response = false ;
# ifdef DEVTOOLS
# ifdef MOCK_AI_RESPONSE
mocking_the_ai_response = true ;
# endif
# endif
# endif // mock
# endif // devtools
bool succeeded = true ; // couldn't get AI response if false
if ( mocking_the_ai_response )
{
String8 ai_response = { 0 } ;
if ( it - > memories_last - > context . talking_to_kind = = it - > npc_kind )
//if (it->memories_last->context.author_npc_kind != it->npc_kind)
{
@ -6898,14 +7016,13 @@ ISANERROR("Don't know how to do this stuff on this platform.")
}
// something to mock
if ( ai_response . size > 0 )
{
assert ( ai_response . size > 0 ) ;
Log ( " Mocking... \n " ) ;
Action a = { 0 } ;
String8 error_message = S8Lit ( " Something really bad happened bro. File " STRINGIZE ( __FILE__ ) " Line " STRINGIZE ( __LINE__ ) ) ;
if ( succeeded )
{
error_message = parse_chatgpt_response ( scratch. arena, it , ai_response , & a ) ;
error_message = parse_chatgpt_response ( frame_ arena, it , ai_response , & a ) ;
}
assert ( succeeded ) ;
@ -6915,17 +7032,11 @@ ISANERROR("Don't know how to do this stuff on this platform.")
assert ( valid_str . size = = 0 ) ;
perform_action ( & gs , it , a ) ;
}
}
else
{
String8 post_request_body = FmtWithLint ( scratch . arena , " |%.*s " , S8VArg ( prompt_str ) ) ;
it - > gen_request_id = make_generation_request ( post_request_body ) ;
it - > gen_request_id = make_generation_request ( prompt_str ) ;
}
ReleaseScratch ( scratch ) ;
# undef SAY
# endif // desktop endif
}
}
}
@ -7169,6 +7280,11 @@ ISANERROR("Don't know how to do this stuff on this platform.")
}
}
if ( gs . time > LENGTH_OF_DAY )
{
gs . player - > killed = true ;
}
// killed screen
{
static float visible = 0.0f ;
@ -7189,12 +7305,12 @@ ISANERROR("Don't know how to do this stuff on this platform.")
float shake_speed = 9.0f ;
Vec2 win_offset = V2 ( sinf ( ( float ) unwarped_elapsed_time * shake_speed * 1.5f + 0.1f ) , sinf ( ( float ) unwarped_elapsed_time * shake_speed + 0.3f ) ) ;
win_offset = MulV2F ( win_offset , 10.0f ) ;
draw_centered_text ( ( TextParams ) { false , S8Lit ( " YOU WERE KILLED " ) , AddV2 ( MulV2F ( screen_size ( ) , 0.5f ) , win_offset ) , WHITE , 3.0f * visible } ) ; // YOU DIED
draw_centered_text ( ( TextParams ) { false , S8Lit ( " YOU FAILED TO SAVE DANIEL " ) , AddV2 ( MulV2F ( screen_size ( ) , 0.5f ) , win_offset ) , WHITE , 3.0f * visible } ) ; // YOU DIED
if ( imbutton ( aabb_centered ( V2 ( screen_size ( ) . x / 2.0f , screen_size ( ) . y * 0.25f ) , MulV2F ( V2 ( 170.0f , 60.0f ) , visible ) ) , 1.5f * visible , S8Lit ( " Continue " ) ) )
{
gs . player - > killed = false ;
transition_to_room ( & gs , & level_threedee , S8Lit ( " StartingRoom " ) ) ;
//transition_to_room(&gs, &level_threedee, S8Lit("StartingRoom"));
reset_level ( ) ;
}
}
@ -7202,7 +7318,6 @@ ISANERROR("Don't know how to do this stuff on this platform.")
# define HELPER_SIZE 250.0f
// keyboard tutorial icons
if ( false )
if ( ! mobile_controls )
@ -7235,6 +7350,11 @@ ISANERROR("Don't know how to do this stuff on this platform.")
# ifdef DEVTOOLS
if ( keypressed [ SAPP_KEYCODE_J ] )
{
Log ( " Judgement Day! \n " ) ;
}
// statistics @Place(devtools drawing developer menu drawing)
if ( show_devtools )
PROFILE_SCOPE ( " devtools drawing " )
@ -7492,25 +7612,16 @@ void cleanup(void)
void event ( const sapp_event * e )
{
if ( e - > key_repeat ) return ;
if ( e - > type = = SAPP_EVENTTYPE_RESIZED )
{
create_screenspace_gfx_state ( ) ;
}
if ( e - > type = = SAPP_EVENTTYPE_TOUCHES_BEGAN )
{
if ( ! mobile_controls )
{
thumbstick_base_pos = V2 ( screen_size ( ) . x * 0.25f , screen_size ( ) . y * 0.25f ) ;
thumbstick_nub_pos = thumbstick_base_pos ;
}
mobile_controls = true ;
}
# ifdef DESKTOP
// the desktop text backend, for debugging purposes
if ( receiving_text_input )
{
if ( e - > type = = SAPP_EVENTTYPE_KEY_DOWN & & e - > key_code = = SAPP_KEYCODE_BACKSPACE )
{
if ( text_input_buffer_length > 0 )
text_input_buffer_length - = 1 ;
}
else
{
if ( e - > type = = SAPP_EVENTTYPE_CHAR )
{
@ -7519,6 +7630,8 @@ void event(const sapp_event *e)
APPEND_TO_NAME ( text_input_buffer , text_input_buffer_length , ARRLEN ( text_input_buffer ) , ( char ) e - > char_code ) ;
}
}
}
if ( e - > type = = SAPP_EVENTTYPE_KEY_DOWN & & e - > key_code = = SAPP_KEYCODE_ENTER )
{
// doesn't account for, if the text input buffer is completely full and doesn't have a null terminator.
@ -7532,6 +7645,25 @@ void event(const sapp_event *e)
}
# endif
if ( e - > key_repeat ) return ;
if ( e - > type = = SAPP_EVENTTYPE_RESIZED )
{
create_screenspace_gfx_state ( ) ;
}
if ( e - > type = = SAPP_EVENTTYPE_TOUCHES_BEGAN )
{
if ( ! mobile_controls )
{
thumbstick_base_pos = V2 ( screen_size ( ) . x * 0.25f , screen_size ( ) . y * 0.25f ) ;
thumbstick_nub_pos = thumbstick_base_pos ;
}
mobile_controls = true ;
}
if ( e - > type = = SAPP_EVENTTYPE_KEY_DOWN & &
( e - > key_code = = SAPP_KEYCODE_F11 | |
e - > key_code = = SAPP_KEYCODE_ENTER & & ( ( e - > modifiers & SAPP_MODIFIER_ALT ) | | ( e - > modifiers & SAPP_MODIFIER_SHIFT ) ) ) )