From 3cda5f09226f64d8fb548d843e63ce1c55a53cee Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 12 May 2025 01:24:32 +0100 Subject: [PATCH] NPC's R us --- content_skaterift/maps/dev_hub/main.mdl | Bin 2115768 -> 2115312 bytes content_skaterift/maps/dev_tutorial/main.mdl | Bin 4768944 -> 4769144 bytes skaterift_blender/sr_main.py | 54 ++- skaterift_blender/sr_mdl.py | 13 +- src/ent_list.c | 89 +++++ src/ent_list.h | 14 + src/ent_npc.c | 338 +++++++++++++++++ src/ent_npc.h | 16 + src/entity.c | 7 +- src/entity.h | 17 +- src/metascene.c | 323 +++++++---------- src/metascene.h | 4 +- src/npc_gino.c | 258 ------------- src/npc_gino.h | 9 - src/scripts/blocker_break.c | 56 +-- src/scripts/city.c | 7 +- src/scripts/generic.c | 3 +- src/scripts/heaven.c | 79 +--- src/scripts/hub.c | 209 +++-------- src/scripts/mtzero.c | 27 +- src/scripts/tutorial_island.c | 358 ++++++++++--------- src/skaterift.c | 8 +- src/skaterift_script.c | 93 +---- src/skaterift_script.h | 2 + src/world.c | 3 +- src/world.h | 2 +- src/world_load.c | 3 +- src/world_render.c | 2 +- src/world_volumes.c | 23 +- 29 files changed, 956 insertions(+), 1061 deletions(-) create mode 100644 src/ent_list.c create mode 100644 src/ent_list.h create mode 100644 src/ent_npc.c create mode 100644 src/ent_npc.h delete mode 100644 src/npc_gino.c delete mode 100644 src/npc_gino.h diff --git a/content_skaterift/maps/dev_hub/main.mdl b/content_skaterift/maps/dev_hub/main.mdl index 01201377bf97b60e8727b99e0094d0d17b628fac..5dc735a54e5ab4126737aabe6542a1f369e3337d 100644 GIT binary patch delta 38603 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

hNhYd!p!m!ClQGc*SL}K+cCZb97=>(Bz3jL4 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 Qb;h3|{<`d~RT*jhAIZ=CasU7T diff --git a/content_skaterift/maps/dev_tutorial/main.mdl b/content_skaterift/maps/dev_tutorial/main.mdl index 2765056846aa4afecdb2003348a2f331c94c5cb1..4aeae1ecb1f1c247d342325dcf96b7b10ddc9861 100644 GIT binary patch delta 1704 zcmX|=ZBSHI7{|}Oy9iuXK@nJY)s|dzOA0bd-mZ5sO+QdWO-?nb%eGu#hh;%n+{MDt zT32W=pab6fp>b>k6~-x?RdA+e)2y@^r}2gHt%hvuL()t#YDP_s{m;FZ&dl$g=RVK> zKF>MNJ!iD*5I^(5Azo}Ggg6WqWA+DY(L{O8~!0pcr@01=8KM~d+J`lJ0-H4{u$kt;nLFCwdW}$rI9_A+%5Xep1a%wdNOvG zw`9i;@0~O!S+mj3cvtrkK6M>THcYgnXG2z%@y20k?60tyrvp9lx%EcG%&tp(Q}1mP zw<})KpU(09+4N`GO5YwhP(2FK*I>dBzlKE^Lt>qpHvG(I#{D#DcMtamwtf$B%r%?6 z6XJr+8yc%qZkng8#&e6}NuGxjJ(tX(pDVeQOrRe_{bMsp*7i_^Bx%|S(f#R~ zSGO~?TcO+R`x%Ft$PV+V?w_`{N^FrSEj~4|8XK85Kop8Fs()Sy7i%RFsROfj9Wuc0*L{GXCR|bNT zdFVhw>AWKRV!1zdJaM8lC>`7QyQo+vQ=OJAv3R2Tr$))-y(=mac+xV4uO@D@pQ8^tP9MJST~n5^MN+F* zCN}51Bb|s|Fe-gEIG)J2Y?Ven8BHiDkAytII+m!c-zx10j4I*D)V#DK3vVW@)tjWV zg(t>WTou-5TGSst6$?&vNUv_XBr3&r!8!i%9qc%*$Me3(Z)}s^y7l4Sb5jCH0~RnB z%me8l1Iz~tKqgoSvOqS-0amaG*nk}@21~$F@ECA_T<|zp2Am)dEC(xq3p@dy1S>&4 zcnUlX3P2%v2CM?lf+Fx7cpj_<#h?U~f-+DJM6d=(zzr(ETJQo`2iAiZ$Ine|xO3w_ D|J*Yr delta 1639 zcmYk*drVVT90%}oZi}>+A|fEzik6A9IAEY`qN7wdHvIz$TZm&BTU*-;t+u7oiy+Yr zGkmbfq&w*CmOY%Zh|DZ5h1Ho@z|5sHCX>ZSSk$p>fB4uY+uVX?&V6rtU3QYsJ->T? zzkAMoo#{6ZbH}?6b7n6g#0U#u9=Lr@p&k9hwns%sXEq@e0|Bwc?Q04=Oc71cY@i2& zFB#0HEreuXJO{i^kJW1zg%-EnBbQFK5u!mqOUa2syV%+y$SLB-Qkvjr*>o!SwPB^H zBT-d?jNlWk0l&S?7q274w4IQdh(k(lOS7ldo0x>O?_~3-o~~sps9}X>A0ZryYL!BV z%kJ?Az9zYL068^!`9b9c9CokJV#f(u4(p)?YGX$+M=v8}DaPb^$En!%9^KZnTuusPtU#cD7NaH;3@ky)C)9lz}b>a{ps25Z7$D7=~=3;ys2L=`k$I{%Q z;FXg%y4Gh2?QYS!LB56zTK*ibusdAFfFK&nOBzM_dN#SWFkENY+dxmSAKJ2MExX&+ zmOh$=-()XOj6I2mtqt#Jw^9}gnV7#r6Q0~!%~KUC>XH^Fk=%GmKdxvfICT2*&7-T$ zu0vxRe^sp>`Mi78S08`JUf;Qy&1zKZl9k#AXm9VTrsvqYUAO5ZGw;65O=pFR_gqsa zspsHN38(iQ;j|?P<)&t1`_^PtC}*5936*=6+Z#@;dsv5^Fe7}m_eT}=gva{QD8BIc z{)qNHfcE>^#I8cEa zl3)fTg9fybScpGXuG{fp?#T7CQ6;>cQRL3I zd@a=tRlG9t!kq_|+kSVQl6vd;d`Y~(kLupNe<<2>!*8iczG;>whqO6TXh^Hmm0swN zUhDH))|cHC%v7Ijhx6-NV|H zl(8k%Be7$5E3ZrpOWzM^=O$*p7aWLQT4%LLKIRwG*2 z%fZAny9aLZkODeLg_)2BvmhO2Lk46*7R-Tc$bq?_2LsH5T$m3FzzBKp2rPtrSOky4 zVlY7gEP=ent_list ); i ++ ) + { + ent_list *list = af_arritm( &world->ent_list, i ); + if( list->alias_type == k_list_alias_string ) + if( af_str_eq( &world->meta.af, list->pstr_alias, alias, hash ) ) + return list; + } + return NULL; +} + +void _ent_list_iter_start( struct ent_list_iter *iter, ent_list *list, enum entity_alias filter_type ) +{ + iter->list = list; + iter->i = 0; + iter->specific_type = filter_type; +} + +bool _ent_list_iter( struct ent_list_iter *iter ) +{ + if( !iter->list ) + return 0; + + world_instance *world = &_world.main; +AGAIN: + if( iter->i < iter->list->entity_ref_count ) + { + u32 ref_index = iter->list->entity_ref_start + iter->i; + file_entity_ref *ref = af_arritm( &world->file_entity_ref, ref_index ); + iter->type = mdl_entity_id_type( ref->entity_id ); + iter->index = mdl_entity_id_id( ref->entity_id ); + iter->i ++; + + if( iter->specific_type != k_ent_none ) + { + if( iter->specific_type == iter->type ) return 1; + else goto AGAIN; + } + else return 1; + } + else return 0; +} + +void _ent_list_set_visible( ent_list *list, bool visible ) +{ + world_instance *world = &_world.main; + struct ent_list_iter iter; + _ent_list_iter_start( &iter, list, 0 ); + + while( _ent_list_iter( &iter ) ) + { + if( iter.type == k_ent_objective ) + { + ent_objective *objective = af_arritm( &world->ent_objective, iter.index ); + if( visible ) objective->flags &= ~((u32)k_ent_objective_hidden); + else objective->flags |= k_ent_objective_hidden; + } + else if( iter.type == k_ent_prop ) + { + ent_prop *prop = af_arritm( &world->ent_prop, iter.index ); + if( visible ) prop->flags &= ~((u32)k_prop_flag_hidden); + else prop->flags |= k_prop_flag_hidden; + } + else if( iter.type == k_ent_challenge ) + { + ent_challenge *challenge = af_arritm( &world->ent_challenge, iter.index ); + if( visible ) challenge->flags &= ~((u32)k_ent_challenge_locked); + else challenge->flags |= (u32)k_ent_challenge_locked; + } + else if( iter.type == k_ent_volume ) + { + ent_volume *volume = af_arritm( &world->ent_volume, iter.index ); + if( visible ) volume->flags &= ~((u32)k_ent_volume_flag_disabled); + else volume->flags |= (u32)k_ent_volume_flag_disabled; + } + else if( iter.type == k_ent_marker ) + { + ent_marker *marker = af_arritm( &world->ent_marker, iter.index ); + if( visible ) marker->flags &= ~((u32)k_ent_marker_flag_hidden); + else marker->flags |= (u32)k_ent_marker_flag_hidden; + } + } +} + diff --git a/src/ent_list.h b/src/ent_list.h new file mode 100644 index 0000000..3ab9e74 --- /dev/null +++ b/src/ent_list.h @@ -0,0 +1,14 @@ +#pragma once + +struct ent_list_iter +{ + ent_list *list; + u32 i; + u32 type, index; + enum entity_alias specific_type; +}; + +ent_list *_ent_list_get_aliased( const char *alias ); +void _ent_list_iter_start( struct ent_list_iter *iter, ent_list *list, enum entity_alias filter_type ); +bool _ent_list_iter( struct ent_list_iter *iter ); +void _ent_list_set_visible( ent_list *list, bool visible ); diff --git a/src/ent_npc.c b/src/ent_npc.c new file mode 100644 index 0000000..29c9689 --- /dev/null +++ b/src/ent_npc.c @@ -0,0 +1,338 @@ +#include "ent_npc.h" + +struct +{ + struct + { + enum gino_state + { + k_gino_none, + k_gino_intro, + k_gino_normal, + } + state; + + mdl_context mdl; + i32 sm_main, sm_hat, sm_glow; + v3f co, p0, p1; + f64 command_t; + u32 current_entity_id; + f32 spark_t; + } + gino; + + enum npc_sub_state + { + k_npc_sub_off, + k_npc_sub_reading, + } + sub_state; + + const cs_subtitle *subtitles; + i32 sub_index; + v3f sub_position; +} +_npc; + +struct gino_context +{ + const char *alias; + u32 alias_hash; + + const cs_subtitle *subtitles; +} +static _gino_contexts[] = +{ + /* HEAVEN world */ + { + "heave:introduction", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "Hmm.. I'm Gino, hello" }, + { "a2", KCOL_JESUS "Do you remember who you are?" }, + { "a3", KCOL_JESUS "Pick here.." }, + { NULL, NULL }, + }, + }, + { + "heaven:locked", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "Welcome to almost Heaven.." }, + { "a2", KCOL_JESUS "The entrance is blocked.." }, + { "a3", KCOL_JESUS "You'll go back to earth for now.." }, + { "a4", KCOL_JESUS "There are people waiting for you.." }, + { "a5", KCOL_JESUS "I think.." }, + { NULL, NULL }, + } + }, + { + "heaven:shop", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "Might want to pick up one of these.." }, + { "a2", KCOL_JESUS "See you at the center Island.." }, + { NULL, NULL }, + } + }, + + /* HUB world */ + { + "mtzero:locked", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "Someone put boxes here.." }, + { "a2", KCOL_JESUS "Hmm.." }, + { NULL, NULL }, + } + }, + { + "city:locked", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "Again with the boxes!" }, + { "a2", KCOL_JESUS "Who is doing that?" }, + { NULL, NULL }, + } + }, + { + "valley:locked", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS ".." }, + { "a2", KCOL_JESUS "You know what to do.." }, + { NULL, NULL }, + } + }, + + /* VOLCANO world */ + { + "docks:locked", .subtitles = (const cs_subtitle[]) + { + { "a1", KCOL_JESUS "To get to the docks.." }, + { "a2", KCOL_JESUS "Hmm.." }, + { "a3", KCOL_JESUS "JC demands you do all the tasks here.." }, + { "a4", KCOL_JESUS "Before going home.." }, + { "a5", KCOL_JESUS "Take a look at the map.." }, + { NULL, NULL }, + } + }, +}; + +void _ent_npc_init(void) +{ + for( u32 i=0; ikey ) + { + _npc.sub_state = k_npc_sub_reading; + _cutscene.subtitle = sub->value; + + gui_helper_reset( k_gui_helper_mode_black_bars ); + vg_str text; + if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) + vg_strcat( &text, "Next" ); + v3_copy( localplayer.rb.co, _npc.sub_position ); + } + else + { + _npc.sub_index = 0; + _npc.sub_state = k_npc_sub_off; + _npc.subtitles = NULL; + _cutscene.subtitle = NULL; + gui_helper_reset( k_gui_helper_mode_clear ); + } +} + +void _ent_npc_preupdate(void) +{ + if( _npc.sub_state == k_npc_sub_reading ) + { + f32 dist2 = v3_dist2( _npc.sub_position, localplayer.rb.co ); + if( dist2 > 5.0f*5.0f ) + { + _npc.sub_state = k_npc_sub_off; + _cutscene.subtitle = NULL; + gui_helper_reset( k_gui_helper_mode_clear ); + } + } + + /* gino */ + if( _npc.gino.state == k_gino_intro ) + { + f32 t = (vg.time - _npc.gino.command_t) / 2.0; + bool end = 0; + + if( t >= 1.0f ) + { + end = 1; + t = 1.0f; + } + + if( end ) + _npc.gino.state = k_gino_normal; + + f32 ts = vg_smoothstepf( t ); + v3_lerp( _npc.gino.p0, _npc.gino.p1, ts, _npc.gino.co ); + _npc.gino.co[1] += vg_smoothstepf(1.0f-(fabsf(t-0.5f)*2.0f)) * 8.0f; + } + else + v3_copy( _npc.gino.p1, _npc.gino.co ); + + if( _npc.gino.state != k_gino_none ) + { + f32 dist2 = v3_dist2( _npc.gino.co, localplayer.rb.co ); + _npc.gino.co[0] += cos( vg.time * 1.23 + 0.3 ) * 0.07f; + _npc.gino.co[1] += sin( vg.time ) * 0.1f; + _npc.gino.co[2] += cos( vg.time * 1.1 + 0.3 ) * 0.04f; + + if( dist2 < 40.0f*40.0f ) + { + if( _npc.gino.spark_t < 0.0f ) + { + _npc.gino.spark_t += 0.05f+vg_randf64(&vg.rand)*0.1f; + + v3f pos; + v3_add( _npc.gino.co, (v3f){0,0.16f,0}, pos ); + f32 a = vg_randf64(&vg.rand) * VG_TAUf, + r = 0.43f; + pos[0] += sinf( a ) * r; + pos[2] += cosf( a ) * r; + particle_spawn_cone( &particles_grind, pos, (v3f){0,-1,0}, VG_PIf/2.0f, 2, 4.0f, 0xffffffff ); + } + else + _npc.gino.spark_t -= vg.time_delta; + } + } +} + +void _ent_npc_render( vg_camera *cam ) +{ + if( _npc.gino.state == k_gino_none ) + return; + + world_instance *world = &_world.main; + shader_model_entity_use(); + shader_model_entity_uTexMain( 0 ); + shader_model_entity_uCamera( cam->transform[3] ); + shader_model_entity_uPv( cam->mtx.pv ); + WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); + + mesh_bind( &_npc.gino.mdl.mesh ); + glActiveTexture( GL_TEXTURE0 ); + + glDepthMask(GL_FALSE); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquation(GL_FUNC_ADD); + glBindTexture( GL_TEXTURE_2D, _npc.gino.mdl.textures[1].glname ); + + m4x3f mmdl; + m3x3_copy( cam->transform, mmdl ); + v3_copy( _npc.gino.co, mmdl[3] ); + shader_model_entity_uMdl( mmdl ); + glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } ); + mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_glow ] ); + glDrawBuffers( 2, (GLenum[]){ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 } ); + + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); + glBindTexture( GL_TEXTURE_2D, _npc.gino.mdl.textures[0].glname ); + + v3f v0 = { localplayer.rb.co[0] - _npc.gino.co[0], 0.0f, localplayer.rb.co[2] - _npc.gino.co[2] }; + v3_normalize( v0 ); + v3_copy( v0, mmdl[0] ); + v3_copy( (v3f){0,1,0}, mmdl[1] ); + v3_cross( mmdl[0], mmdl[1], mmdl[2] ); + v3_copy( _npc.gino.co, mmdl[3] ); + + m4x4f m4mmdl; + m4x3_expand( mmdl, m4mmdl ); + m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); + shader_model_entity_uMdl( mmdl ); + shader_model_entity_uPvmPrev( m4mmdl ); + mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_main ] ); + + m3x3f mspin; + v4f qspin; + q_axis_angle( qspin, (v3f){0,1,0}, vg_fractf(vg.time)*VG_TAUf*16.0f ); + q_m3x3( qspin, mspin ); + m3x3_mul( mspin, mmdl, mmdl ); + m4x3_expand( mmdl, m4mmdl ); + m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); + shader_model_entity_uMdl( mmdl ); + shader_model_entity_uPvmPrev( m4mmdl ); + mdl_draw_submesh( &_npc.gino.mdl.submeshes[ _npc.gino.sm_hat ] ); +} + +entity_call_result ent_npc_call( world_instance *world, ent_call *call ) +{ + u32 index = mdl_entity_id_id( call->id ); + ent_npc *npc = af_arritm( &world->ent_npc, index ); + + if( AF_STR_EQ( &world->meta.af, npc->pstr_id, "gino" ) ) + { + /* interact */ + if( call->function == 0 ) + { + const char *alias = af_str( &world->meta.af, npc->pstr_context_id ); + u32 hash = vg_strdjb2( alias ); + for( u32 i=0; ifunction == 1 ) + { + if( _npc.gino.current_entity_id != call->id ) + { + _npc.gino.current_entity_id = call->id; + v3_copy( npc->transform.co, _npc.gino.p1 ); + if( _npc.gino.state == k_gino_none ) + v3_add( npc->transform.co, (v3f){0,30,0}, _npc.gino.p0 ); + else + v3_copy( _npc.gino.co, _npc.gino.p0 ); + + _npc.gino.state = k_gino_intro; + _npc.gino.command_t = vg.time; + } + } + + return k_entity_call_result_OK; + } + else if( AF_STR_EQ( &world->meta.af, npc->pstr_id, "JC" ) ) + { + return k_entity_call_result_OK; + } + + return k_entity_call_result_unhandled; +} diff --git a/src/ent_npc.h b/src/ent_npc.h new file mode 100644 index 0000000..94cefd6 --- /dev/null +++ b/src/ent_npc.h @@ -0,0 +1,16 @@ +#pragma once + +enum npc +{ + k_npc_none = 0, + k_npc_gino, + k_npc_jc, +}; + +void _ent_npc_init(void); +void _ent_npc_render( vg_camera *cam ); +void _ent_npc_goto( v3f pos, i32 uid ); +void _ent_npc_preupdate(void); +void _ent_npc_speech( enum npc npc_id, const cs_subtitle *subs ); +void _ent_npc_reset(void); +entity_call_result ent_npc_call( world_instance *world, ent_call *call ); diff --git a/src/entity.c b/src/entity.c index ee2720a..7a64422 100644 --- a/src/entity.c +++ b/src/entity.c @@ -36,6 +36,7 @@ void entity_call( world_instance *world, ent_call *call ) [k_ent_glider] = ent_glider_call, [k_ent_water] = ent_water_call, [k_ent_script] = ent_script_call, + [k_ent_npc] = ent_npc_call, }; if( type >= VG_ARRAY_LEN(table) ){ @@ -47,17 +48,13 @@ void entity_call( world_instance *world, ent_call *call ) if( !fn ) { - vg_error( "Entity type %u does not have a call handler, " - "but was called anyway\n", type ); + vg_error( "Entity type %u does not have a call handler, but was called anyway\n", type ); return; } enum entity_call_result res = fn( world, call ); - if( res == k_entity_call_result_unhandled ) - { vg_warn( "Call to entity %u#%u was unhandled.\n", type, index ); - } } ent_marker *ent_find_marker( mdl_context *mdl, array_file_ptr *arr, diff --git a/src/entity.h b/src/entity.h index d91ad89..b781e0d 100644 --- a/src/entity.h +++ b/src/entity.h @@ -182,9 +182,17 @@ enum gate_type{ }; #endif +enum list_alias_type +{ + k_list_alias_none = 0, + k_list_alias_string = 1 +}; + struct ent_list { u16 entity_ref_start, entity_ref_count; + u8 alias_type, none0, none1, none2; + u32 pstr_alias; }; struct file_entity_ref @@ -334,7 +342,8 @@ enum ent_volume_flag { k_ent_volume_flag_disabled = 0x2, k_ent_volume_flag_removed0 = 0x4, k_ent_volume_flag_interact = 0x8, - k_ent_volume_flag_water = 0x10 + k_ent_volume_flag_water = 0x10, + k_ent_volume_flag_repeatable= 0x20 }; struct ent_volume @@ -728,7 +737,7 @@ struct ent_glider { struct ent_npc { mdl_transform transform; - u32 id, context, camera; + u32 pstr_id, pstr_context_id; }; #include "world.h" @@ -739,7 +748,5 @@ struct ent_call{ void *data; }; -typedef enum entity_call_result - (*fn_entity_call_handler)( world_instance *, ent_call *); - +typedef enum entity_call_result (*fn_entity_call_handler)( world_instance *, ent_call *); void entity_call( world_instance *world, ent_call *call ); diff --git a/src/metascene.c b/src/metascene.c index 437f42f..910dc30 100644 --- a/src/metascene.c +++ b/src/metascene.c @@ -15,8 +15,7 @@ void metascene_load( ms_context *ms, const char *path, void *alloc ) AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->cameras, ent_camera, alloc ); AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->audios, ent_audio, alloc ); AF_LOAD_ARRAY_STRUCT( &ms->af, &ms->audio_clips, ent_audio_clip, alloc ); - af_load_array( &ms->af, &ms->curves, "ms_curves", - alloc, sizeof(ms_curve_keyframe) ); + af_load_array( &ms->af, &ms->curves, "ms_curves", alloc, sizeof(ms_curve_keyframe) ); af_close( &ms->af ); if( af_arrcount( &ms->infos ) ) @@ -25,9 +24,7 @@ void metascene_load( ms_context *ms, const char *path, void *alloc ) ms->info = *src_inf; } else - { vg_fatal_error( "No scene info in metascene.\n" ); - } } struct cs_instance *_cutscene_get_first_model_instance( const char *mdl_name ) @@ -38,44 +35,12 @@ struct cs_instance *_cutscene_get_first_model_instance( const char *mdl_name ) struct model_ref *mref = &_cutscene.refs[ inst->ref_id ]; if( vg_str_eq( mdl_name, mref->name ) ) - { return inst; - } } return NULL; } -void _cutscene_play(void) -{ - _cutscene.state = k_cutscene_state_playing; - - vg_audio_lock(); - for( u32 j=0; jclip_start ); - - if( audio->flags & AUDIO_FLAG_AUTO_START ) - { - const u16 group = 0xfff1; - const u32 flags = AUDIO_FLAG_CUTSCENE; - - if( audio->flags & AUDIO_FLAG_SPACIAL_3D ) - vg_audio_oneshot_3d( &clip->_.clip, audio->transform.co, audio->transform.s[0], audio->volume, group,flags); - else - vg_audio_oneshot( &clip->_.clip, 1.0f, 0.0f, group, flags ); - } - } - vg_audio_unlock(); -} - -void _cutscene_set_subtitle_list( const cs_subtitle *subtitles ) -{ - _cutscene.subtitle_list = subtitles; - _cutscene.subtitle_index = 0; -} - void _cutscene_unload(void) { vg_info( "Unloading cutscene\n" ); @@ -116,9 +81,7 @@ static void _cutscene_override_asoc( u32 instance_id, u32 override_index, struct mdl_context *mdl = &_cutscene.refs[ instance->ref_id ].mdl; ms_instance *oins = af_arritm( &_cutscene.meta.instances, instance_id ); - ms_override *override = - af_arritm( &_cutscene.meta.overrides, - oins->override_start + override_index ); + ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + override_index ); out_asoc->orig_data = mdl; out_asoc->entity_type = override->entity_type; @@ -159,9 +122,7 @@ static void _cutscene_get_strip_asoc( ms_strip *strip, out_asoc->override = NULL; } else - { _cutscene_override_asoc( strip->instance_id, strip->object_id, out_asoc ); - } } static void sync_cutscene_loaded( void *userdata ) @@ -204,8 +165,7 @@ static void cutscene_load_thread( vg_async_task *task ) { struct model_ref *ref_j = &_cutscene.refs[ j ]; - if( af_str_eq( &_cutscene.meta.af, instance->pstr_name, - ref_j->name, ref_j->name_hash ) ) + if( af_str_eq( &_cutscene.meta.af, instance->pstr_name, ref_j->name, ref_j->name_hash ) ) { ref = ref_j; ref_id = j; @@ -226,7 +186,6 @@ static void cutscene_load_thread( vg_async_task *task ) } ref->reference_count ++; - _cutscene.instances[ i ].ref_id = ref_id; _cutscene.instances[ i ].skinning_data = NULL; _cutscene.instances[ i ].disable_render = 0; @@ -251,8 +210,7 @@ static void cutscene_load_thread( vg_async_task *task ) u32 skeleton_count = ref->mdl.armature_count; if( skeleton_count ) { - ref->skeletons = vg_linear_alloc( _cutscene.arena, - sizeof(struct cs_skeleton) * skeleton_count ); + ref->skeletons = vg_linear_alloc( _cutscene.arena, sizeof(struct cs_skeleton) * skeleton_count ); ref->total_skinning_bones = 0; for( u32 j=0; jref_id ]; - ins->skinning_data = vg_linear_alloc( _cutscene.arena, - sizeof(m4x3f) * ref->total_skinning_bones ); - + ins->skinning_data = vg_linear_alloc( _cutscene.arena, sizeof(m4x3f) * ref->total_skinning_bones ); for( u32 j=0; jtotal_skinning_bones; j ++ ) - { m4x3_identity( ins->skinning_data[ j ] ); - } /* load overrides */ ms_instance *oins = af_arritm( &_cutscene.meta.instances, i ); for( u32 j=0; joverride_count; j ++ ) { - ms_override *override = - af_arritm( &_cutscene.meta.overrides, oins->override_start + j ); + ms_override *override = af_arritm( &_cutscene.meta.overrides, oins->override_start + j ); struct cs_asoc asoc; _cutscene_override_asoc( i, j, &asoc ); @@ -297,14 +250,11 @@ static void cutscene_load_thread( vg_async_task *task ) VG_ASSERT( asoc.entity_type == 28 ); struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; - m4x3f mmdl; mdl_transform_m4x3( &override->transform, mmdl ); for( u32 l=0; lsk.bone_count; l ++ ) - { m4x3_copy( mmdl, ins->skinning_data[skele->skinning_offset+l] ); - } } } @@ -318,9 +268,7 @@ static void cutscene_load_thread( vg_async_task *task ) ent_audio_clip *clip = af_arritm( &_cutscene.meta.audio_clips, audio->clip_start+k ); if( clip->_.file.pack_size ) - { vg_error( "Currently not support packed audio in metascene..." ); - } else { clip->_.clip.path = af_str( &_cutscene.meta.af, clip->_.file.pstr_path ); @@ -336,40 +284,29 @@ static void cutscene_load_thread( vg_async_task *task ) vg_async_call( &vg.main_tasks, sync_cutscene_loaded, NULL ); } -static int cmd_cutscene_load( int argc, const char *argv[] ) +void _cutscene_load_and_play( const char *path, const cs_subtitle *subtitles, bool freeze_player ) { - if( argc == 1 ) - { - if( _cutscene.state != k_cutscene_state_none ) - { - vg_error( "Cutscene already in use..\n" ); - return 0; - } + VG_ASSERT( _cutscene.state == k_cutscene_state_none ); - _cutscene.state = k_cutscene_state_loading; - _cutscene.time = 0.0f; - _cutscene.strip = 0; - _cutscene.active_samplers = 0; - - u32 len = strlen( argv[0] ) +1; - vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cutscene_load_info) + len, 1 ); - struct cutscene_load_info *info = (void *)task->data; - strcpy( info->path, argv[0] ); - vg_async_task_dispatch( task, cutscene_load_thread ); - return 1; - } - else - { - vg_error( "Usage: cutscene path/to/cutscene.ms\n" ); - return 0; - } + _cutscene.state = k_cutscene_state_loading; + _cutscene.subtitle_list = subtitles; + _cutscene.subtitle_index = 0; + _cutscene.time = 0.0f; + _cutscene.strip = 0; + _cutscene.active_samplers = 0; + _cutscene.freeze_player = freeze_player; + + u32 len = strlen( path ) +1; + vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cutscene_load_info) + len, 1 ); + struct cutscene_load_info *info = (void *)task->data; + strcpy( info->path, path ); + vg_async_task_dispatch( task, cutscene_load_thread ); } /* * Currently draws everything as skinned meshes. */ -void cutscene_render_instance( struct cs_instance *ins, - world_instance *world, vg_camera *cam ) +void cutscene_render_instance( struct cs_instance *ins, world_instance *world, vg_camera *cam ) { if( ins->disable_render ) return; @@ -471,15 +408,12 @@ static bool link_internal_datapath( struct cs_asoc *asoc, const char *datapath, out_link->target = reference[i].arr + offset; out_link->semantic_type = reference[i].semantic + offset; - vg_info( "Linked %d#%d:'%s'\n", - asoc->entity_type, asoc->entity_index, datapath ); + vg_info( "Linked %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); return 1; } } - vg_warn( "Failed link %d#%d:'%s'\n", - asoc->entity_type, asoc->entity_index, datapath ); - + vg_warn( "Failed link %d#%d:'%s'\n", asoc->entity_type, asoc->entity_index, datapath ); return 0; } @@ -490,6 +424,37 @@ ent_camera *_cutscene_active_camera(void) void cutscene_update( f32 delta ) { + if( _cutscene.state == k_cutscene_state_ready ) + { + _cutscene.player_binding = _cutscene_get_first_model_instance( "models/ch_none" ); + if( _cutscene.player_binding ) + _cutscene.player_binding->disable_render = 1; + + /* start playing */ + if( _cutscene.freeze_player ) + localplayer.immobile = 1; + + _cutscene.state = k_cutscene_state_playing; + vg_audio_lock(); + for( u32 j=0; jclip_start ); + + if( audio->flags & AUDIO_FLAG_AUTO_START ) + { + const u16 group = 0xfff1; + const u32 flags = AUDIO_FLAG_CUTSCENE; + + if( audio->flags & AUDIO_FLAG_SPACIAL_3D ) + vg_audio_oneshot_3d( &clip->_.clip, audio->transform.co, audio->transform.s[0], audio->volume, group,flags); + else + vg_audio_oneshot( &clip->_.clip, 1.0f, 0.0f, group, flags ); + } + } + vg_audio_unlock(); + } + if( _cutscene.state == k_cutscene_state_unloading ) { if( !vg_audio_flagged_stopped( AUDIO_FLAG_CUTSCENE ) ) @@ -519,9 +484,7 @@ void cutscene_update( f32 delta ) struct cs_sampler *si = &_cutscene.samplers[i]; if( frame > (si->strip->offset + si->strip->length) ) - { move = 1; - } else { if( move ) @@ -541,9 +504,7 @@ void cutscene_update( f32 delta ) ms_strip *strip = af_arritm(&_cutscene.meta.strips, i); if( frame < strip->offset ) - { break; - } if( frame > strip->offset + strip->length ) { @@ -560,8 +521,7 @@ void cutscene_update( f32 delta ) _cutscene_get_strip_asoc( strip, &asoc ); VG_ASSERT( asoc.entity_type == k_ent_camera ); - ent_camera *cam = - af_arritm( &_cutscene.meta.cameras, asoc.entity_index ); + ent_camera *cam = af_arritm( &_cutscene.meta.cameras, asoc.entity_index ); _cutscene.active_camera = cam; } @@ -606,78 +566,66 @@ void cutscene_update( f32 delta ) } else { - if( strip->instance_id == 0xffffffff ) - { - vg_info( "+ Strip: '%s' entity: %u\n", - af_str( &_cutscene.meta.af, strip->pstr_name ), - strip->object_id ); - /* internal link */ - struct cs_asoc asoc; - _cutscene_get_strip_asoc( strip, &asoc ); - - if( strip->data_mode == 1 ) + if( strip->instance_id == 0xffffffff ) { - for( u32 j=0; jdata_count; j ++ ) - { - ms_track *track = af_arritm( &_cutscene.meta.tracks, - strip->data_start + j ); - - const char *datapath = - af_str( &_cutscene.meta.af, track->pstr_datapath ); - - struct cs_link_info link; - if( !link_internal_datapath( &asoc, datapath, &link ) ) - continue; - - VG_ASSERT( _cutscene.active_samplers < - VG_ARRAY_LEN(_cutscene.samplers) ); - - struct cs_sampler *samp = - &_cutscene.samplers[ _cutscene.active_samplers ++ ]; - samp->strip = strip; - samp->curves.track = track; + vg_info( "+ Strip: '%s' entity: %u\n", af_str( &_cutscene.meta.af, strip->pstr_name ), strip->object_id ); + /* internal link */ + struct cs_asoc asoc; + _cutscene_get_strip_asoc( strip, &asoc ); - samp->curves.target = link.target; - samp->curves.semantic = link.semantic_type; - samp->curves.keyframe = 0; - samp->override = asoc.override; - VG_ASSERT( samp->curves.target ); + if( strip->data_mode == 1 ) + { + for( u32 j=0; jdata_count; j ++ ) + { + ms_track *track = af_arritm( &_cutscene.meta.tracks, strip->data_start + j ); + const char *datapath = af_str( &_cutscene.meta.af, track->pstr_datapath ); + + struct cs_link_info link; + if( !link_internal_datapath( &asoc, datapath, &link ) ) + continue; + + VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); + struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; + samp->strip = strip; + samp->curves.track = track; + + samp->curves.target = link.target; + samp->curves.semantic = link.semantic_type; + samp->curves.keyframe = 0; + samp->override = asoc.override; + VG_ASSERT( samp->curves.target ); + } } - } - else VG_ASSERT(0); - } - else - { - /* external link */ - struct cs_instance *ins = &_cutscene.instances[ strip->instance_id ]; - - struct cs_asoc asoc; - _cutscene_get_strip_asoc( strip, &asoc ); - VG_ASSERT( asoc.entity_type == 28 ); - - if( strip->data_mode == 1 ) - { - VG_ASSERT(0); + else VG_ASSERT(0); } else { - VG_ASSERT( _cutscene.active_samplers < - VG_ARRAY_LEN(_cutscene.samplers) ); + /* external link */ + struct cs_instance *ins = &_cutscene.instances[ strip->instance_id ]; + + struct cs_asoc asoc; + _cutscene_get_strip_asoc( strip, &asoc ); + VG_ASSERT( asoc.entity_type == 28 ); - struct cs_sampler *samp = - &_cutscene.samplers[ _cutscene.active_samplers ++ ]; + if( strip->data_mode == 1 ) + { + VG_ASSERT(0); + } + else + { + VG_ASSERT( _cutscene.active_samplers < VG_ARRAY_LEN(_cutscene.samplers) ); - struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; - struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; + struct cs_sampler *samp = &_cutscene.samplers[ _cutscene.active_samplers ++ ]; + struct model_ref *ref = &_cutscene.refs[ ins->ref_id ]; + struct cs_skeleton *skele = &ref->skeletons[ asoc.entity_index ]; - samp->strip = strip; - samp->skeleton.skinning_data = - &ins->skinning_data[ skele->skinning_offset ]; - samp->skeleton.ref_sk = &skele->sk; - samp->override = asoc.override; + samp->strip = strip; + samp->skeleton.skinning_data = &ins->skinning_data[ skele->skinning_offset ]; + samp->skeleton.ref_sk = &skele->sk; + samp->override = asoc.override; + } } } - } _cutscene.strip ++; } @@ -693,8 +641,7 @@ void cutscene_update( f32 delta ) { .strip = samp->strip, .framerate = _cutscene.meta.info.framerate, - .keyframes_base = af_arritm( &_cutscene.meta.keyframes, - samp->strip->data_start ) + .keyframes_base = af_arritm( &_cutscene.meta.keyframes, samp->strip->data_start ) }; f32 t = _cutscene.time; @@ -706,11 +653,9 @@ void cutscene_update( f32 delta ) ms_keyframe pose[32]; skeleton_sample_anim_clamped( ref_sk, &temp_anim, t, pose ); - skeleton_apply_pose( ref_sk, pose, - k_anim_apply_defer_ik, final_mtx ); + skeleton_apply_pose( ref_sk, pose, k_anim_apply_defer_ik, final_mtx ); skeleton_apply_ik_pass( ref_sk, final_mtx ); - skeleton_apply_pose( ref_sk, pose, - k_anim_apply_deffered_only, final_mtx ); + skeleton_apply_pose( ref_sk, pose, k_anim_apply_deffered_only, final_mtx ); skeleton_apply_inverses( ref_sk, final_mtx ); if( samp->override ) @@ -735,12 +680,9 @@ void cutscene_update( f32 delta ) { if( samp->curves.track->keyframe_count > 1 ) { - for( u32 j=samp->curves.keyframe+1; - jcurves.track->keyframe_count; j ++ ) + for( u32 j=samp->curves.keyframe+1; jcurves.track->keyframe_count; j ++ ) { - kr = af_arritm( &_cutscene.meta.curves, - samp->curves.track->keyframe_start + j ); - + kr = af_arritm( &_cutscene.meta.curves, samp->curves.track->keyframe_start + j ); if( kr->co[0] <= t ) { kl = kr; @@ -753,14 +695,9 @@ void cutscene_update( f32 delta ) } if( kl && kr ) - { - *samp->curves.target = - explicit_bezier( kl->co, kl->r, kr->l, kr->co, t ); - } + *samp->curves.target = explicit_bezier( kl->co, kl->r, kr->l, kr->co, t ); else - { *samp->curves.target = kl->co[1]; - } if( samp->curves.semantic == CS_FOV ) { @@ -777,19 +714,16 @@ void cutscene_update( f32 delta ) vg_line_cross( cam->co, VG__RED, 0.2f ); } -#if 0 - if( (_cutscene.strip == af_arrcount(&_cutscene.meta.strips)) && - (_cutscene.active_samplers == 0 ) ) - { - _cutscene.state = k_cutscene_state_done; - } -#endif - f32 scene_t = _cutscene.time * _cutscene.meta.info.framerate, end_t = _cutscene.meta.info.end_frame; if( scene_t >= end_t ) - _cutscene.state = k_cutscene_state_done; + { + if( _cutscene.freeze_player ) + localplayer.immobile = 0; + + _cutscene_unload(); + } } void cutscene_render_fadeout(void) @@ -836,9 +770,7 @@ void cutscene_render( world_instance *world, vg_camera *cam ) if( _cutscene.state >= k_cutscene_state_ready ) { for( u32 i=0; i<_cutscene.instance_count; i ++ ) - { cutscene_render_instance( &_cutscene.instances[i], world, cam ); - } } } @@ -950,9 +882,7 @@ static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_pane struct model_ref *mref = &_cutscene.refs[i]; char inf[128]; - snprintf( inf, sizeof(inf), "%s (%u references)", - mref->name, mref->reference_count ); - + snprintf( inf, sizeof(inf), "%s (%u references)", mref->name, mref->reference_count ); ui_text( ctx, box, inf, 1, k_ui_align_middle_left, 0 ); box[1] += 16; } @@ -976,10 +906,7 @@ static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_pane box[3] = 16; if( ui_clip( panel_r, box, box ) ) - { - ui_text( ctx, box, af_str( &_cutscene.meta.af, strip->pstr_name ), - 1, k_ui_align_middle_left, 0 ); - } + ui_text( ctx, box, af_str( &_cutscene.meta.af, strip->pstr_name ), 1, k_ui_align_middle_left, 0 ); continue; } @@ -987,12 +914,8 @@ static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_pane for( u32 k=0; koffset + usage[k]->length < strip->offset ) - { usage[k] = NULL; - } - } if( !usage[k] ) { @@ -1011,13 +934,11 @@ static void cb_cutscene_view( ui_context *ctx, ui_rect rect, struct vg_magi_pane u32 colour = af_str_hash( &_cutscene.meta.af, strip->pstr_name ); ui_fill( ctx, box, colour | 0xff000000 ); - ui_text( ctx, box, af_str( &_cutscene.meta.af, strip->pstr_name ), 1, - k_ui_align_middle_center, 0 ); + ui_text( ctx, box, af_str( &_cutscene.meta.af, strip->pstr_name ), 1, k_ui_align_middle_center, 0 ); } } - ui_rect cursor = { (f32)_cutscene.time*_cutscene.meta.info.framerate, - 0, 1, VG_ARRAY_LEN(usage)*32 }; + ui_rect cursor = { (f32)_cutscene.time*_cutscene.meta.info.framerate, 0, 1, VG_ARRAY_LEN(usage)*32 }; cursor[0] += root[0]; cursor[1] += root[1]; if( ui_clip( panel_r, cursor, cursor ) ) @@ -1038,6 +959,6 @@ static int cmd_cutscene_inspector( int argc, const char *argv[] ) void cutscene_init(void) { - vg_console_reg_cmd( "cutscene", cmd_cutscene_load, NULL ); + //vg_console_reg_cmd( "cutscene", cmd_cutscene_load, NULL ); vg_console_reg_cmd( "cutscene_inspector", cmd_cutscene_inspector, NULL ); } diff --git a/src/metascene.h b/src/metascene.h index 6988211..7419468 100644 --- a/src/metascene.h +++ b/src/metascene.h @@ -170,6 +170,8 @@ struct _cutscene const *subtitle_list; u32 subtitle_index; bool subtitle_length_warning; + + bool freeze_player; } extern _cutscene; @@ -177,7 +179,7 @@ void metascene_load( ms_context *ms, const char *path, void *alloc ); void cutscene_init(void); void cutscene_render( world_instance *world, vg_camera *cam ); void cutscene_render_fadeout(void); -void _cutscene_play(void); +void _cutscene_load_and_play( const char *path, const cs_subtitle *subtitles, bool freeze_player ); void _cutscene_unload(void); void cutscene_update( f32 delta ); ent_camera *_cutscene_active_camera(void); diff --git a/src/npc_gino.c b/src/npc_gino.c deleted file mode 100644 index b5d44a1..0000000 --- a/src/npc_gino.c +++ /dev/null @@ -1,258 +0,0 @@ -#include "npc_gino.h" - -struct -{ - enum gino_state - { - k_gino_none, - k_gino_intro, - k_gino_normal, - } - state; - - mdl_context mdl; - i32 sm_main, sm_hat, sm_glow; - - f64 command_t; - v3f co, p0, p1; - - i32 uid; - - enum gino_sub_state - { - k_gino_sub_off, - k_gino_sub_reading, - k_gino_sub_read - } - sub_state; - - const cs_subtitle *subtitles; - i32 sub_index; - - f32 spark_t; -} -_gino; - -void _npc_gino_reset(void) -{ - _gino.state = k_gino_none; - _gino.sub_state = k_gino_sub_off; - _gino.spark_t = 0.0f; - _gino.sub_index = 0; - _gino.subtitles = NULL; - _gino.uid = 0; - _gino.command_t = 0.0; -} - -void _npc_gino_speech( const cs_subtitle *subs ) -{ - _gino.subtitles = subs; -} - -void _npc_gino_goto( v3f pos, i32 uid ) -{ - if( _gino.uid == uid ) - return; - - v3_copy( pos, _gino.p1 ); - - if( _gino.state == k_gino_none ) - v3_add( pos, (v3f){0,30,0}, _gino.p0 ); - else - v3_copy( _gino.co, _gino.p0 ); - - _gino.uid = uid; - _gino.state = k_gino_intro; - _gino.command_t = vg.time; -} - -void _npc_gino_init(void) -{ - void *alloc = vg_mem.rtmemory; - mdl_context *mdl = &_gino.mdl; - mdl_open( mdl, "models/gino.mdl", alloc ); - mdl_load_metadata_block( mdl, alloc ); - mdl_async_full_load_std( mdl, NULL ); - _gino.sm_main = mdl_get_submesh_index( mdl, "gino" ); - _gino.sm_hat = mdl_get_submesh_index( mdl, "gino.hat" ); - _gino.sm_glow = mdl_get_submesh_index( mdl, "gino.spt" ); - mdl_close( mdl ); -} - -void _npc_gino_preupdate(void) -{ - if( _gino.state == k_gino_none ) - return; - - f32 dist2 = v3_dist2( _gino.p1, localplayer.rb.co ); - if( _world.event == k_world_event_gino ) - { - if( dist2 > 4.0f*4.0f ) - { - if( world_clear_event( k_world_event_gino ) ) - { - _gino.sub_state = k_gino_sub_off; - _cutscene.subtitle = NULL; - gui_helper_reset( k_gui_helper_mode_clear ); - } - } - else - { - if( (_gino.sub_state != k_gino_sub_read) && button_down( k_srbind_maccept ) && _gino.subtitles ) - { - srinput.state = k_input_state_resume; - if( _gino.sub_state == k_gino_sub_reading ) - _gino.sub_index ++; - - const cs_subtitle *sub = &_gino.subtitles[ _gino.sub_index ]; - - if( sub->key ) - { - _gino.sub_state = k_gino_sub_reading; - _cutscene.subtitle = sub->value; - - gui_helper_reset( k_gui_helper_mode_black_bars ); - vg_str text; - if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) - vg_strcat( &text, "Next" ); - } - else - { - _gino.sub_index = 0; - _gino.sub_state = k_gino_sub_read; - _cutscene.subtitle = NULL; - gui_helper_reset( k_gui_helper_mode_clear ); - } - } - } - } - - v3f co; - - if( _gino.state == k_gino_normal ) - { - v3_copy( _gino.p1, co ); - - if( _world.event == k_world_event_none ) - { - if( dist2 < 3.0f*3.0f ) - { - if( localplayer.subsystem == k_player_subsystem_walk ) - { - if( world_set_event( k_world_event_gino ) ) - { - gui_helper_reset( k_gui_helper_mode_black_bars ); - vg_str text; - if( gui_new_helper( input_button_list[k_srbind_maccept], &text )) - vg_strcat( &text, "Talk to Gino" ); - } - } - } - } - } - else - { - f32 t = (vg.time - _gino.command_t) / 2.0; - bool end = 0; - - if( t >= 1.0f ) - { - end = 1; - t = 1.0f; - } - - if( end ) - _gino.state = k_gino_normal; - - f32 ts = vg_smoothstepf( t ); - v3_lerp( _gino.p0, _gino.p1, ts, co ); - co[1] += vg_smoothstepf(1.0f-(fabsf(t-0.5f)*2.0f)) * 8.0f; - } - - co[0] += cos( vg.time * 1.23 + 0.3 ) * 0.07f; - co[1] += sin( vg.time ) * 0.1f; - co[2] += cos( vg.time * 1.1 + 0.3 ) * 0.04f; - v3_copy( co, _gino.co ); - - if( dist2 < 40.0f*40.0f ) - { - if( _gino.spark_t < 0.0f ) - { - _gino.spark_t += 0.05f+vg_randf64(&vg.rand)*0.1f; - - v3f pos; - v3_add( co, (v3f){0,0.16f,0}, pos ); - f32 a = vg_randf64(&vg.rand) * VG_TAUf, - r = 0.43f; - pos[0] += sinf( a ) * r; - pos[2] += cosf( a ) * r; - particle_spawn_cone( &particles_grind, pos, (v3f){0,-1,0}, VG_PIf/2.0f, 2, 4.0f, 0xffffffff ); - } - else - _gino.spark_t -= vg.time_delta; - } -} - -void _npc_gino_render( vg_camera *cam ) -{ - if( _gino.state == k_gino_none ) - return; - - world_instance *world = &_world.main; - shader_model_entity_use(); - shader_model_entity_uTexMain( 0 ); - shader_model_entity_uCamera( cam->transform[3] ); - shader_model_entity_uPv( cam->mtx.pv ); - WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_entity ); - - mesh_bind( &_gino.mdl.mesh ); - glActiveTexture( GL_TEXTURE0 ); - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - glBlendEquation(GL_FUNC_ADD); - glBindTexture( GL_TEXTURE_2D, _gino.mdl.textures[1].glname ); - - m4x3f mmdl; - m3x3_copy( cam->transform, mmdl ); - v3_copy( _gino.co, mmdl[3] ); - shader_model_entity_uMdl( mmdl ); - glDrawBuffers( 1, (GLenum[]){ GL_COLOR_ATTACHMENT0 } ); - mdl_draw_submesh( &_gino.mdl.submeshes[ _gino.sm_glow ] ); - glDrawBuffers( 2, (GLenum[]){ GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 } ); - - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); - glBindTexture( GL_TEXTURE_2D, _gino.mdl.textures[0].glname ); - - v3f v0 = { localplayer.rb.co[0] - _gino.co[0], 0.0f, localplayer.rb.co[2] - _gino.co[2] }; - v3_normalize( v0 ); - v3_copy( v0, mmdl[0] ); - v3_copy( (v3f){0,1,0}, mmdl[1] ); - v3_cross( mmdl[0], mmdl[1], mmdl[2] ); - v3_copy( _gino.co, mmdl[3] ); - - m4x4f m4mmdl; - m4x3_expand( mmdl, m4mmdl ); - m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); - shader_model_entity_uMdl( mmdl ); - shader_model_entity_uPvmPrev( m4mmdl ); - mdl_draw_submesh( &_gino.mdl.submeshes[ _gino.sm_main ] ); - - m3x3f mspin; - v4f qspin; - q_axis_angle( qspin, (v3f){0,1,0}, vg_fractf(vg.time)*VG_TAUf*16.0f ); - q_m3x3( qspin, mspin ); - m3x3_mul( mspin, mmdl, mmdl ); - m4x3_expand( mmdl, m4mmdl ); - m4x4_mul( cam->mtx_prev.pv, m4mmdl, m4mmdl ); - shader_model_entity_uMdl( mmdl ); - shader_model_entity_uPvmPrev( m4mmdl ); - mdl_draw_submesh( &_gino.mdl.submeshes[ _gino.sm_hat ] ); -} - -void _npc_gino_imgui( ui_context *ctx ) -{ - vg_camera *cam = &g_render.cam; -} diff --git a/src/npc_gino.h b/src/npc_gino.h deleted file mode 100644 index 00bdfed..0000000 --- a/src/npc_gino.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -void _npc_gino_init(void); -void _npc_gino_render( vg_camera *cam ); -void _npc_gino_goto( v3f pos, i32 uid ); -void _npc_gino_preupdate(void); -void _npc_gino_imgui( ui_context *ctx ); -void _npc_gino_speech( const cs_subtitle *subs ); -void _npc_gino_reset(void); diff --git a/src/scripts/blocker_break.c b/src/scripts/blocker_break.c index 37f9a11..edb1a06 100644 --- a/src/scripts/blocker_break.c +++ b/src/scripts/blocker_break.c @@ -1,20 +1,17 @@ -void _explode_template_boom( ent_script_event *event ) +void _explode_template_boom( ent_list *list ) { - ent_list_set_visible( event->world, event->entity_list, 0 ); - + world_instance *world = &_world.main; + _ent_list_set_visible( list, 0 ); v3f where = {0,0,0}; - ent_list *list = event->entity_list; - for( u32 i=0; ientity_ref_count; i ++ ) - { - file_entity_ref *ref = af_arritm( &event->world->file_entity_ref, list->entity_ref_start + i ); - - u32 type = mdl_entity_id_type( ref->entity_id ), - index = mdl_entity_id_id( ref->entity_id ); + struct ent_list_iter iter; + _ent_list_iter_start( &iter, list, 0 ); - if( type == k_ent_marker ) + while( _ent_list_iter( &iter ) ) + { + if( iter.type == k_ent_marker ) { - ent_marker *marker = af_arritm( &event->world->ent_marker, index ); + ent_marker *marker = af_arritm( &world->ent_marker, iter.index ); for( u32 j=0; j<80; j ++ ) { particle_spawn_cone( &particles_env, marker->transform.co, @@ -27,38 +24,3 @@ void _explode_template_boom( ent_script_event *event ) vg_audio_oneshot_3d( &audio_wood_break, where, 100.0f, 1.0f, 0, 0 ); vg_audio_unlock(); } - -static bool _skaterift_script_blocker_break_template( ent_script_event *event, - const struct generic_cutscene *cutscene_template, - const char *once_nugget_trigger ) -{ - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/unlock_docks.ms", - .freeze_player = 1, - }; - generic_cutscene_wrapper( &cutscene, event ); - - if( on_function_trigger( event, 1 ) ) - { - vg_error( "Show required objectives here\n" ); - } - - if( on_function_trigger( event, 2 ) ) - { - if( on_nugget_once( event, "unlock_docks_view" ) ) - { - play_generic_cutscene( event ); - } - else - { - ent_list_set_visible( event->world, event->entity_list, 0 ); - } - } - - if( on_cutscene_marker( event, "$break" ) ) - { - } - - return 1; -} diff --git a/src/scripts/city.c b/src/scripts/city.c index 378b0f5..8a47073 100644 --- a/src/scripts/city.c +++ b/src/scripts/city.c @@ -1,5 +1,6 @@ static bool _skaterift_script_ch3s1( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "j1", KCOL_JOHN "Ohh this is it guys." }, @@ -22,12 +23,13 @@ static bool _skaterift_script_ch3s1( ent_script_event *event ) { play_generic_cutscene( event ); } - +#endif return 1; } static bool _skaterift_script_ch3s2( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "m1", KCOL_MIKE "Is that the FBI??" }, @@ -44,11 +46,13 @@ static bool _skaterift_script_ch3s2( ent_script_event *event ) .subtitles = EN, }; optional_video_wrapper( &cutscene, "ch3s2_view", 0, event ); +#endif return 1; } static bool _skaterift_script_ch3s3( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "p1", KCOL_PRES "Yall have some explaining to do here.." }, @@ -94,5 +98,6 @@ static bool _skaterift_script_ch3s3( ent_script_event *event ) .subtitles = EN, }; optional_video_wrapper( &cutscene, "ch3s3_view", 0, event ); +#endif return 1; } diff --git a/src/scripts/generic.c b/src/scripts/generic.c index 91ff462..e9bbc90 100644 --- a/src/scripts/generic.c +++ b/src/scripts/generic.c @@ -1,3 +1,4 @@ + struct board_maker_unlock_waiter { bool changed; @@ -30,7 +31,7 @@ static bool _skaterift_script_board_maker_unlock( ent_script_event *event ) struct board_maker_unlock_waiter *waiter = event->userdata; if( waiter->changed ) { - ent_list_set_visible( event->world, event->entity_list, waiter->unlocked ); + _ent_list_set_visible( event->entity_list, waiter->unlocked ); waiter->changed = 0; } } diff --git a/src/scripts/heaven.c b/src/scripts/heaven.c index 150dca9..d811769 100644 --- a/src/scripts/heaven.c +++ b/src/scripts/heaven.c @@ -1,3 +1,4 @@ +#if 0 static bool _skaterift_script_intro( ent_script_event *event ) { static const cs_subtitle EN[] = { @@ -24,82 +25,6 @@ static bool _skaterift_script_intro( ent_script_event *event ) if( viewed ) gate->flags &= ~((u32)k_ent_gate_locked); else gate->flags |= (u32)k_ent_gate_locked; } - - return 1; -} - -static void _skaterift_script_gino_send( ent_script_event *event, i32 which ) -{ - i32 count = 0; - for( u32 i=0; ientity_list->entity_ref_count; i ++ ) - { - u32 ref_index = event->entity_list->entity_ref_start + i; - file_entity_ref *ref = af_arritm( &event->world->file_entity_ref, ref_index ); - u32 type = mdl_entity_id_type( ref->entity_id ), - index = mdl_entity_id_id( ref->entity_id ); - - if( type == k_ent_marker ) - { - if( count == which ) - { - ent_marker *marker = af_arritm( &event->world->ent_marker, index ); - _npc_gino_goto( marker->transform.co, which+1 ); - break; - } - - count ++; - } - } -} - -static bool _skaterift_script_gino_intro( ent_script_event *event ) -{ - static const cs_subtitle EN0[] = - { - { "a1", KCOL_JESUS "Hello, I'm Gino!" }, - { "a2", KCOL_JESUS "Do you remember who you are?" }, - { "a3", KCOL_JESUS "Pick here." }, - { NULL, NULL }, - }, - EN1[] = - { - { "a1", KCOL_JESUS "Welcome to almost Heaven.." }, - { "a2", KCOL_JESUS "For some reason the entrance is blocked" }, - { "a3", KCOL_JESUS "You'll have to go back home for now" }, - { "a4", KCOL_JESUS "There are people waiting for you after all." }, - { NULL, NULL }, - }, - EN2[] = - { - { "a1", KCOL_JESUS "Might want to pick up one of these" }, - { "a2", KCOL_JESUS "See you at the center Island." }, - { NULL, NULL }, - }; - - if( event->type == k_escript_event_world_start ) - { - _npc_gino_speech( EN0 ); - _skaterift_script_gino_send( event, 0 ); - return 1; - } - - if( on_function_trigger( event, 0 ) ) - { - _npc_gino_speech( EN0 ); - _skaterift_script_gino_send( event, 0 ); - } - - if( on_function_trigger( event, 1 ) ) - { - _npc_gino_speech( EN1 ); - _skaterift_script_gino_send( event, 1 ); - } - - if( on_function_trigger( event, 2 ) ) - { - _npc_gino_speech( EN2 ); - _skaterift_script_gino_send( event, 2 ); - } - return 1; } +#endif diff --git a/src/scripts/hub.c b/src/scripts/hub.c index 24afdff..9c58b20 100644 --- a/src/scripts/hub.c +++ b/src/scripts/hub.c @@ -1,13 +1,62 @@ +struct script_hub +{ + ent_list *break_list; +}; + static bool _skaterift_script_hub( ent_script_event *event ) { + if( event->type == k_escript_event_allocate ) + { + struct script_event_allocate *event_info = event->info; + struct script_hub *script_hub = vg_linear_alloc( event_info->heap, sizeof(struct script_hub) ); + script_hub->break_list = NULL; + event_info->userdata = script_hub; + return 1; + } + + struct script_hub *script_hub = event->userdata; + + /* small text box pop up, the welcome thing. */ if( on_function_trigger( event, 0 ) ) { if( on_nugget_once( event, "hub_info_view" ) ) - { menu_open( k_menu_page_impromptu_guide ); + } + + struct + { + const char *ms, *nugget, *view_nugget, *list; + } + blocks[] = + { + { "metascenes/unlock_mtzero.ms", "unlock_mtzero", "unlock_mtzero_view", "mtzero:locked" }, + { "metascenes/unlock_city.ms", "unlock_city", "unlock_city_view", "city:locked" }, + { "metascenes/unlock_valley.ms", "unlock_valley", "unlock_valley_view", "valley:locked" }, + }; + + for( u32 i=0; ibreak_list = list; + } + else + _ent_list_set_visible( list, 0 ); + } } } - else if( event->type == k_escript_event_nugget_changed ) + + if( on_cutscene_marker( event, "$break" ) ) + _explode_template_boom( script_hub->break_list ); + + if( event->type == k_escript_event_nugget_changed ) { world_instance *world = &_world.main; @@ -34,24 +83,6 @@ static bool _skaterift_script_hub( ent_script_event *event ) if( AF_STR_EQ( &world->meta.af, prop->pstr_alias, "BERNADETTA" ) ) if( skaterift.achievements & 0x8 ) prop->flags &= ~0x1; - -#if 0 - if( AF_STR_EQ( &world->meta.af, prop->pstr_alias, "main_island_block" ) ) - if( unlock_mtzero ) - prop->flags |= k_prop_flag_hidden; - - if( AF_STR_EQ( &world->meta.af, prop->pstr_alias, "mtzero_block" ) ) - if( unlock_mtzero ) - prop->flags |= k_prop_flag_hidden; - - if( AF_STR_EQ( &world->meta.af, prop->pstr_alias, "city_block" ) ) - if( unlock_city ) - prop->flags |= k_prop_flag_hidden; - - if( AF_STR_EQ( &world->meta.af, prop->pstr_alias, "valley_block" ) ) - if( unlock_valley ) - prop->flags |= k_prop_flag_hidden; -#endif } u32 spawns_allowed = 0; @@ -77,141 +108,3 @@ static bool _skaterift_script_hub( ent_script_event *event ) return 0; } - -static void _hub_blocker_template( ent_script_event *event, const char *unlock, const char *guard ) -{ - u64 status; - if( on_nugget_changed( event, unlock, &status ) ) - { - if( status ) - { - if( on_nugget_once( event, guard ) ) - { - play_generic_cutscene( event ); - } - else - { - ent_list_set_visible( event->world, event->entity_list, 0 ); - } - } - } - - if( on_cutscene_marker( event, "$break" ) ) - { - _explode_template_boom( event ); - } - -} - -static bool _skaterift_script_unlock_mtzero( ent_script_event *event ) -{ - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/unlock_mtzero.ms", - .freeze_player = 1, - }; - generic_cutscene_wrapper( &cutscene, event ); - _hub_blocker_template( event, "unlock_mtzero", "unlock_mtzero_view" ); - return 1; -} - -static bool _skaterift_script_unlock_city( ent_script_event *event ) -{ - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/unlock_city.ms", - .freeze_player = 1, - }; - generic_cutscene_wrapper( &cutscene, event ); - _hub_blocker_template( event, "unlock_city", "unlock_city_view" ); - return 1; -} - -static bool _skaterift_script_unlock_valley( ent_script_event *event ) -{ - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/unlock_valley.ms", - .freeze_player = 1, - }; - generic_cutscene_wrapper( &cutscene, event ); - _hub_blocker_template( event, "unlock_valley", "unlock_valley_view" ); - return 1; -} - -static bool _skaterift_script_gino_hub( ent_script_event *event ) -{ - if( on_function_trigger( event, 0 ) ) - { - if( _skaterift_script_nugget_status( "unlock_mtzero" ) ) - { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "It's clear now" }, - { NULL, NULL }, - }; - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 0 ); - } - else - { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "Someone put boxes here.." }, - { "a2", KCOL_JESUS "Stuff to do at the volcano.." }, - { NULL, NULL }, - }; - - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 0 ); - } - } - - if( on_function_trigger( event, 1 ) ) - { - if( _skaterift_script_nugget_status( "unlock_city" ) ) - { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "Cool" }, - { NULL, NULL }, - }; - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 1 ); - } - else - { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "Again with the boxes!" }, - { "a2", KCOL_JESUS "Who is doing that?" }, - { NULL, NULL }, - }; - - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 1 ); - } - } - - if( on_function_trigger( event, 2 ) ) - { - if( _skaterift_script_nugget_status( "unlock_valley" ) ) - { - _npc_gino_speech( NULL ); - _skaterift_script_gino_send( event, 2 ); - } - else - { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "..." }, - { "a2", KCOL_JESUS "You know what to do..." }, - { NULL, NULL }, - }; - - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 2 ); - } - } - return 1; -} diff --git a/src/scripts/mtzero.c b/src/scripts/mtzero.c index 21ea897..06208ea 100644 --- a/src/scripts/mtzero.c +++ b/src/scripts/mtzero.c @@ -1,5 +1,6 @@ static bool _skaterift_script_ch2s1( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "j1", KCOL_JOHN "Eughhh boy" }, @@ -29,12 +30,13 @@ static bool _skaterift_script_ch2s1( ent_script_event *event ) { play_generic_cutscene( event ); } - +#endif return 1; } static bool _skaterift_script_ch2s2( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "m1", KCOL_MIKE "Haha!" }, @@ -61,11 +63,13 @@ static bool _skaterift_script_ch2s2( ent_script_event *event ) .subtitles = EN, }; optional_video_wrapper( &cutscene, "ch2s2_view", 0, event ); +#endif return 1; } static bool _skaterift_script_first_mtzero( ent_script_event *event ) { +#if 0 if( on_function_trigger( event, 6 ) ) { u64 status = _skaterift_script_nugget_status( "ch2s3_view" ); @@ -74,12 +78,13 @@ static bool _skaterift_script_first_mtzero( ent_script_event *event ) _skaterift_script_nugget_set( "ch2s3_view", 2 ); } } - +#endif return 1; } static bool _skaterift_script_ch2s3( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "m1", KCOL_MIKE "Holy! You actually bothered to do these?" }, @@ -171,12 +176,13 @@ static bool _skaterift_script_ch2s3( ent_script_event *event ) optional_video_wrapper( &cutscene, "ch2s3_view", 2, event ); /* TODO: Unlocking the blocker thing here, for the final challenge */ - +#endif return 1; } static bool _skaterift_script_ch2s4( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "j1", KCOL_JOHN "Oh my god.." }, @@ -202,11 +208,13 @@ static bool _skaterift_script_ch2s4( ent_script_event *event ) .subtitles = EN, }; optional_video_wrapper( &cutscene, "ch2s4_view", 2, event ); +#endif return 1; } static bool _skaterift_script_ch2s5_before( ent_script_event *event ) { +#if 0 u64 status; if( on_nugget_changed( event, "ch2s5_view", &status ) ) { @@ -223,12 +231,13 @@ static bool _skaterift_script_ch2s5_before( ent_script_event *event ) _skaterift_script_nugget_set( "ch2s5_view", 3 ); skaterift_load_world_command( 1, (const char *[]){ "reload" } ); } - +#endif return 1; } static bool _skaterift_script_ch2s5_after( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "m1", KCOL_MIKE "Hi mate, hows it goin?" }, @@ -261,12 +270,13 @@ static bool _skaterift_script_ch2s5_after( ent_script_event *event ) play_generic_cutscene( event ); } } - +#endif return 1; } static bool _skaterift_script_ch2s6( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "j1", KCOL_JOHN "Ello guys" }, @@ -300,11 +310,13 @@ static bool _skaterift_script_ch2s6( ent_script_event *event ) _skaterift_script_nugget_set( "unlock_city", 1 ); skaterift_load_world_command( 1, (const char *[]){ "sr002-local-mp_spawn" } ); } +#endif return 1; } static bool _skaterift_script_ch2e1( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { "j1", KCOL_JOHN "Hey bird I'm just working on some boards here." }, @@ -324,12 +336,13 @@ static bool _skaterift_script_ch2e1( ent_script_event *event ) if( cs_event == k_generic_cutscene_event_start ) _skaterift_script_nugget_set( "board_maker_unlock", 1 ); - +#endif return 1; } static bool _skaterift_script_battery_jump( ent_script_event *event ) { +#if 0 static const struct cs_subtitle EN[] = { { NULL, NULL }, }; @@ -359,6 +372,6 @@ static bool _skaterift_script_battery_jump( ent_script_event *event ) if( status == 1 ) ent_list_set_visible( event->world, event->entity_list, 0 ); } - +#endif return 1; } diff --git a/src/scripts/tutorial_island.c b/src/scripts/tutorial_island.c index c0b9bcb..91bbdca 100644 --- a/src/scripts/tutorial_island.c +++ b/src/scripts/tutorial_island.c @@ -1,53 +1,75 @@ -static bool _skaterift_script_tutorial_island( ent_script_event *event ) +struct script_volcano { - static const struct cs_subtitle EN[] = { - { "john_1", KCOL_JOHN "Well, here we are. Home." }, - { "john_2", KCOL_JOHN "I mean, halfway home." }, - { "john_3", KCOL_JOHN "Obviously you've forgotten quite a bit, so we'll stop off here" }, - { "john_4", KCOL_JOHN "and I'll teach you some stuff again" }, - { NULL, NULL }, - }; - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/ch1s2.ms", - .freeze_player = 1, - .subtitles = EN, - }; - generic_cutscene_wrapper( &cutscene, event ); + ent_list *break_list; + bool docks_wait; + f32 stopped_timer; +}; - if( on_nugget_once( event, "ch1s2_view" ) ) +static bool _skaterift_script_tutorial_island( ent_script_event *event ) +{ + if( event->type == k_escript_event_allocate ) { - play_generic_cutscene( event ); + struct script_event_allocate *event_info = event->info; + struct script_volcano *script_volcano = vg_linear_alloc( event_info->heap, sizeof(struct script_volcano) ); + script_volcano->break_list = NULL; + script_volcano->docks_wait = 0; + script_volcano->stopped_timer = 0.0f; + event_info->userdata = script_volcano; + return 1; } - return 1; -} + struct script_volcano *script_volcano = event->userdata; -static bool _skaterift_script_unlock_docks( ent_script_event *event ) -{ - static const struct generic_cutscene cutscene = + if( on_cutscene_marker( event, "$break" ) ) + _explode_template_boom( script_volcano->break_list ); + + /* intro movie */ + if( on_nugget_once( event, "ch1s2_view" ) ) { - .metascene_path = "metascenes/unlock_docks.ms", - .freeze_player = 1, - }; - generic_cutscene_wrapper( &cutscene, event ); + static const struct cs_subtitle EN[] = { + { "john_1", KCOL_JOHN "Well, here we are. Home." }, + { "john_2", KCOL_JOHN "I mean, halfway home." }, + { "john_3", KCOL_JOHN "Obviously you've forgotten quite a bit, so we'll stop off here" }, + { "john_4", KCOL_JOHN "and I'll teach you some stuff again" }, + { NULL, NULL }, + }; + _cutscene_load_and_play( "metascenes/ch1s2.ms", EN, 1 ); + } + /* all tasks completed (called from the region entity) */ if( on_function_trigger( event, 2 ) ) { - _skaterift_script_nugget_set( "ch1s6a_view", 2 ); + ent_list *list = _ent_list_get_aliased( "docks:locked" ); if( on_nugget_once( event, "unlock_docks_view" ) ) { - play_generic_cutscene( event ); + vg_low( "waiting for stopped...\n" ); + _skaterift_script_nugget_set( "ch1s6a_view", 2 ); + script_volcano->docks_wait = 1; } else - { - ent_list_set_visible( event->world, event->entity_list, 0 ); - } + _ent_list_set_visible( list, 0 ); } - if( on_cutscene_marker( event, "$break" ) ) + if( event->type == k_escript_event_update ) { - _explode_template_boom( event ); + if( script_volcano->docks_wait ) + { + if( localplayer.subsystem == k_player_subsystem_walk ) + { + if( v3_length2( localplayer.rb.v ) < 1.0f ) + { + script_volcano->stopped_timer += vg.time_frame_delta; + if( script_volcano->stopped_timer > 3.0f ) + { + script_volcano->docks_wait = 0; + _cutscene_load_and_play( "metascenes/unlock_docks.ms", NULL, 1 ); + script_volcano->break_list = _ent_list_get_aliased( "docks:locked" ); + } + } + else + script_volcano->stopped_timer = 0.0f; + } + } } return 1; @@ -55,182 +77,172 @@ static bool _skaterift_script_unlock_docks( ent_script_event *event ) static bool _skaterift_script_ch1s3( ent_script_event *event ) { - static const struct cs_subtitle EN[] = { - { "john_1", KCOL_JOHN "Alright so, fliptricks." }, - { "john_2", KCOL_JOHN "We spent ages practicing these before" }, - { "john_3", KCOL_JOHN "Shouldn't take you long to get it again" }, - { "john_4", KCOL_JOHN "see if you can get a tre-flip down there" }, - { NULL, NULL }, - }; - static const struct generic_cutscene cutscene = + if( on_function_trigger( event, 1 ) ) { - .metascene_path = "metascenes/ch1s3.ms", - .freeze_player = 1, - .subtitles = EN, - }; - challenge_video_wrapper( &cutscene, "ch1s3_view", event ); - return 1; -} + if( on_nugget_once( event, "ch1s3_view" ) ) + { + static const struct cs_subtitle EN[] = { + { "john_1", KCOL_JOHN "Alright so, fliptricks." }, + { "john_2", KCOL_JOHN "We spent ages practicing these before" }, + { "john_3", KCOL_JOHN "Shouldn't take you long to get it again" }, + { "john_4", KCOL_JOHN "see if you can get a tre-flip down there" }, + { NULL, NULL }, + }; + _cutscene_load_and_play( "metascenes/ch1s3.ms", EN, 1 ); + } + } -static bool _skaterift_script_ch1s3b( ent_script_event *event ) -{ - static const struct cs_subtitle EN[] = { - { "john_1", KCOL_JOHN "That is it mate!" }, - { "john_2", KCOL_JOHN "You have still got it!" }, - { NULL, NULL }, - }; - static const struct generic_cutscene cutscene = + if( on_function_trigger( event, 2 ) ) { - .metascene_path = "metascenes/ch1s3b.ms", - .freeze_player = 0, - .subtitles = EN, - }; - challenge_video_wrapper( &cutscene, "ch1s3b_view", event ); + if( on_nugget_once( event, "ch1s3b_view" ) ) + { + static const struct cs_subtitle EN[] = { + { "john_1", KCOL_JOHN "That is it mate!" }, + { "john_2", KCOL_JOHN "You have still got it!" }, + { NULL, NULL }, + }; + _cutscene_load_and_play( "metascenes/ch1s3b.ms", EN, 1 ); + } + } u64 viewed; if( on_nugget_changed( event, "ch1s3b_view", &viewed ) ) - ent_list_set_visible( event->world, event->entity_list, !viewed ); + _ent_list_set_visible( event->entity_list, !viewed ); return 1; } static bool _skaterift_script_ch1s4( ent_script_event *event ) { - static const struct cs_subtitle EN[] = { - { "john_1", KCOL_JOHN "Remember these courses we were setting up?" }, - { "john_2", KCOL_JOHN "Nah?" }, - { "john_3", KCOL_JOHN "Alright well uh, to jog your memory.." }, - { "john_4", KCOL_JOHN "Get yourself down through the gates as quick as possible" }, - { "john_5", KCOL_JOHN "Thats it." }, - { "john_6", KCOL_JOHN "Give it a shot mate" }, - { NULL, NULL }, - }; - static const struct generic_cutscene cutscene = + if( on_function_trigger( event, 0 ) ) { - .metascene_path = "metascenes/ch1s4.ms", - .freeze_player = 1, - .subtitles = EN, - }; - optional_video_wrapper( &cutscene, "ch1s4_view", 0, event ); + if( on_nugget_once( event, "ch1s4_view" ) ) + { + static const struct cs_subtitle EN[] = { + { "john_1", KCOL_JOHN "Remember these courses we were setting up?" }, + { "john_2", KCOL_JOHN "Nah?" }, + { "john_3", KCOL_JOHN "Alright well uh, to jog your memory.." }, + { "john_4", KCOL_JOHN "Get yourself down through the gates as quick as possible" }, + { "john_5", KCOL_JOHN "Thats it." }, + { "john_6", KCOL_JOHN "Give it a shot mate" }, + { NULL, NULL }, + }; + _cutscene_load_and_play( "metascenes/ch1s4.ms", EN, 1 ); + } + } + + u64 status; + if( on_nugget_changed( event, "ch1s4_view", &status ) ) + _ent_list_set_visible( event->entity_list, status == 0 ); + return 1; } static bool _skaterift_script_ch1s5( ent_script_event *event ) { - static const struct cs_subtitle EN[] = { - -/* 50ch| set cc=70 |################################################| */ -{ "j1", KCOL_JOHN "Alright, well then" }, -{ "j2", KCOL_JOHN "You're gonna need to play close attention to\n" - "this part" }, - -{ "j3", KCOL_JOHN "because its difficult.." }, -{ "j4", KCOL_JOHN "It's gonna take some practice until it clicks" }, -{ "j5", KCOL_JOHN "Right as you like, go across the transition \n" - "of the ramp," }, - -{ "j6", KCOL_JOHN "Right here," }, -{ "j7", KCOL_JOHN "you need to pump to gain some momentum." }, -{ "j8", KCOL_JOHN "What I mean right, watch" }, -{ "j9", KCOL_JOHN "just as I'm going into the base of the ramp" }, -{ "j10",KCOL_JOHN "I'm storing up some energy here by crouching down" }, -{ "j11",KCOL_JOHN "Right as I go across this point" }, -{ "j12",KCOL_JOHN "I'm almost jumping back up, adding some uwpwards\n" - "momentum" }, - -{ "j13",KCOL_JOHN "Then as the board comes up to this angle.." }, -{ "j14",KCOL_JOHN "that upwards momentum is transferred \n" - "into my speed" }, - -{ "j15",KCOL_JOHN "Same principle works, same way in the \n" - "other direction" }, - -{ "j16",KCOL_JOHN "Now, like I'm saying" }, -{ "j17",KCOL_JOHN "this might take you a little bit until it clicks" }, - -{ "j18",KCOL_JOHN "But once it does you'll feel it. You'll know!" }, - -{ "j19",KCOL_JOHN "And I uhh, set a target for you" }, -{ "j20",KCOL_JOHN "right up there.." }, -{ "j21",KCOL_JOHN "Thats how we'll know you're back on form." }, - -{ "j22",KCOL_JOHN "Come see me at the docks once you've got it." }, - -{ NULL, NULL }, - }; - - static const struct generic_cutscene cutscene = + if( on_function_trigger( event, 0 ) ) { - .metascene_path = "metascenes/ch1s5.ms", - .freeze_player = 1, - .subtitles = EN, - }; - challenge_video_wrapper( &cutscene, "ch1s5_view", event ); + if( on_nugget_once( event, "ch1s5_view" ) ) + { + static const struct cs_subtitle EN[] = { + /* 50ch| set cc=70 |################################################| */ + { "j1", KCOL_JOHN "Alright, well then" }, + { "j2", KCOL_JOHN "You're gonna need to play close attention to\n" + "this part" }, + + { "j3", KCOL_JOHN "because its difficult.." }, + { "j4", KCOL_JOHN "It's gonna take some practice until it clicks" }, + { "j5", KCOL_JOHN "Right as you like, go across the transition \n" + "of the ramp," }, + + { "j6", KCOL_JOHN "Right here," }, + { "j7", KCOL_JOHN "you need to pump to gain some momentum." }, + { "j8", KCOL_JOHN "What I mean right, watch" }, + { "j9", KCOL_JOHN "just as I'm going into the base of the ramp" }, + { "j10",KCOL_JOHN "I'm storing up some energy here by crouching down" }, + { "j11",KCOL_JOHN "Right as I go across this point" }, + { "j12",KCOL_JOHN "I'm almost jumping back up, adding some uwpwards\n" + "momentum" }, + + { "j13",KCOL_JOHN "Then as the board comes up to this angle.." }, + { "j14",KCOL_JOHN "that upwards momentum is transferred \n" + "into my speed" }, + + { "j15",KCOL_JOHN "Same principle works, same way in the \n" + "other direction" }, + + { "j16",KCOL_JOHN "Now, like I'm saying" }, + { "j17",KCOL_JOHN "this might take you a little bit until it clicks" }, + + { "j18",KCOL_JOHN "But once it does you'll feel it. You'll know!" }, + + { "j19",KCOL_JOHN "And I uhh, set a target for you" }, + { "j20",KCOL_JOHN "right up there.." }, + { "j21",KCOL_JOHN "Thats how we'll know you're back on form." }, + + { "j22",KCOL_JOHN "Come see me at the docks once you've got it." }, + + { NULL, NULL }, + }; + _cutscene_load_and_play( "metascenes/ch1s5.ms", EN, 1 ); + } + } return 1; } -static bool _skaterift_script_ch1s6a( ent_script_event *event ) +struct script_ch1s6a_waiter { - static const struct cs_subtitle EN[] = { - { "j1", KCOL_JOHN "Eyyy! Looks like you're ready again.." }, - { "j2", KCOL_JOHN "Didn't take long" }, - { "j3", KCOL_JOHN "Just a short ferry ride back over to Mt.Zero now." }, - { "j4", KCOL_JOHN "Oh right, Mt.Zero.. You really don't remember anything do you?" }, - { "j5", KCOL_JOHN "Its where we live." }, - { "j7", KCOL_JOHN "Yknow it's where the woodshop is," }, - { "j8", KCOL_JOHN "It's where we skate, where Mike is," }, - { "j9", KCOL_JOHN "yknow, its our home!" }, - - { NULL, NULL }, - }; - static const struct generic_cutscene cutscene = - { - .metascene_path = "metascenes/ch1s6a.ms", - .freeze_player = 1, - .subtitles = EN, - }; - enum generic_cutscene_event cs_event = optional_video_wrapper( &cutscene, "ch1s6a_view", 2, event ); + bool go; +}; - if( cs_event == k_generic_cutscene_event_start ) - { - _skaterift_script_nugget_set( "unlock_mtzero", 1 ); - } - - if( cs_event == k_generic_cutscene_event_end ) +static bool _skaterift_script_ch1s6a( ent_script_event *event ) +{ + if( event->type == k_escript_event_allocate ) { - skaterift_load_world_command( 1, (const char *[]){ "sr002-local-dev_hub" } ); + struct script_event_allocate *event_info = event->info; + struct script_ch1s6a_waiter *waiter = vg_linear_alloc( event_info->heap, sizeof(struct script_ch1s6a_waiter) ); + waiter->go = 0; + event_info->userdata = waiter; + return 1; } - return 1; -} + struct script_ch1s6a_waiter *waiter = event->userdata; + u64 status; + if( on_nugget_changed( event, "ch1s6a_view", &status ) ) + _ent_list_set_visible( event->entity_list, status == 2 ); -static bool _skaterift_script_gino_volc( ent_script_event *event ) -{ if( on_function_trigger( event, 0 ) ) { - if( _skaterift_script_nugget_status( "unlock_docks_view" ) ) + if( on_nugget_once( event, "ch1s6a_view" ) ) { - static const cs_subtitle EN[] = - { - { "a1", KCOL_JESUS "Off to mt.zero at last!" }, - { NULL, NULL }, + _skaterift_script_nugget_set( "unlock_mtzero", 1 ); + + static const struct cs_subtitle EN[] = { + { "j1", KCOL_JOHN "Eyyy! Looks like you're ready again.." }, + { "j2", KCOL_JOHN "Didn't take long" }, + { "j3", KCOL_JOHN "Just a short ferry ride back over to Mt.Zero now." }, + { "j4", KCOL_JOHN "Oh right, Mt.Zero.. You really don't remember anything do you?" }, + { "j5", KCOL_JOHN "Its where we live." }, + { "j7", KCOL_JOHN "Yknow it's where the woodshop is," }, + { "j8", KCOL_JOHN "It's where we skate, where Mike is," }, + { "j9", KCOL_JOHN "yknow, its our home!" }, + + { NULL, NULL }, }; - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 0 ); + _cutscene_load_and_play( "metascenes/ch1s6a.ms", EN, 1 ); + waiter->go = 1; } - else + } + + if( event->type == k_escript_event_update ) + { + if( waiter->go ) { - static const cs_subtitle EN[] = + if( _cutscene.state == k_cutscene_state_none ) { - { "a1", KCOL_JESUS "This leads down to the docks" }, - { "a2", KCOL_JESUS "JC won't let us leave until we did his tasks" }, - { NULL, NULL }, - }; - - _npc_gino_speech( EN ); - _skaterift_script_gino_send( event, 0 ); + skaterift_load_world_command( 1, (const char *[]){ "sr002-local-dev_hub" } ); + } } } - return 1; } diff --git a/src/skaterift.c b/src/skaterift.c index 884e23f..b78e323 100644 --- a/src/skaterift.c +++ b/src/skaterift.c @@ -57,7 +57,8 @@ #include "replay2.h" #include "user_profile.h" #include "ent_route.h" -#include "npc_gino.h" +#include "ent_npc.h" +#include "ent_list.h" struct skaterift_globals skaterift = { @@ -129,7 +130,7 @@ static void game_load_co( vg_coroutine *co ) vg_loader_step( ent_tornado_init, NULL ); vg_loader_step( skaterift_load_player_content, NULL ); vg_loader_step( _replay2_init, NULL ); - vg_loader_step( _npc_gino_init, NULL ); + vg_loader_step( _ent_npc_init, NULL ); vg_loader_set_user_information( "Compiling shaders" ); vg_bake_shaders(); @@ -658,7 +659,8 @@ void vg_framebuffer_resize( int w, int h ) #include "compass.c" #include "replay2.c" #include "user_profile.c" -#include "npc_gino.c" +#include "ent_npc.c" +#include "ent_list.c" //TODO //#include "vg/submodules/hashmap.c/hashmap.c" diff --git a/src/skaterift_script.c b/src/skaterift_script.c index 8cc804a..5c37ec5 100644 --- a/src/skaterift_script.c +++ b/src/skaterift_script.c @@ -435,68 +435,7 @@ static bool _skaterift_script_test( enum escript_event ev, const char *inf ) extern m4x3f *_TEMP_VAR; -static bool _skaterift_script_bind_player(void) -{ - _cutscene.player_binding = _cutscene_get_first_model_instance( "models/ch_none" ); - - if( !_cutscene.player_binding ) - { - vg_error( "Failed to find models/ch_none in scene!" ); - return 0; - } - - _cutscene.player_binding->disable_render = 1; - return 1; -} - -static void ent_list_set_visible( world_instance *world, ent_list *list, bool visible ) -{ - for( u32 i=0; ientity_ref_count; i ++ ) - { - u32 ref_index = list->entity_ref_start + i; - - file_entity_ref *ref = af_arritm( &world->file_entity_ref, ref_index ); - - u32 type = mdl_entity_id_type( ref->entity_id ), - index = mdl_entity_id_id( ref->entity_id ); - - if( type == k_ent_objective ) - { - ent_objective *objective = af_arritm( &world->ent_objective, index ); - - if( visible ) objective->flags &= ~((u32)k_ent_objective_hidden); - else objective->flags |= k_ent_objective_hidden; - } - else if( type == k_ent_prop ) - { - ent_prop *prop = af_arritm( &world->ent_prop, index ); - - if( visible ) prop->flags &= ~((u32)k_prop_flag_hidden); - else prop->flags |= k_prop_flag_hidden; - } - else if( type == k_ent_challenge ) - { - ent_challenge *challenge = af_arritm( &world->ent_challenge, index ); - - if( visible ) challenge->flags &= ~((u32)k_ent_challenge_locked); - else challenge->flags |= (u32)k_ent_challenge_locked; - } - else if( type == k_ent_volume ) - { - ent_volume *volume = af_arritm( &world->ent_volume, index ); - - if( visible ) volume->flags &= ~((u32)k_ent_volume_flag_disabled); - else volume->flags |= (u32)k_ent_volume_flag_disabled; - } - else if( type == k_ent_marker ) - { - ent_marker *marker = af_arritm( &world->ent_marker, index ); - if( visible ) marker->flags &= ~((u32)k_ent_marker_flag_hidden); - else marker->flags |= (u32)k_ent_marker_flag_hidden; - } - } -} - +#if 0 enum generic_cutscene_event generic_cutscene_wrapper( const struct generic_cutscene *cutscene_template, ent_script_event *event ) { @@ -522,9 +461,6 @@ enum generic_cutscene_event generic_cutscene_wrapper( const struct generic_cutsc { generic->state = k_generic_cutscene_state_init; vg_info( "generic_cutscene:state = initializing\n" ); - - if( generic->freeze_player ) - localplayer.immobile = 1; } } @@ -563,8 +499,6 @@ enum generic_cutscene_event generic_cutscene_wrapper( const struct generic_cutsc vg_info( "generic_template:state = end\n" ); _cutscene_unload(); - if( generic->freeze_player ) - localplayer.immobile = 0; return k_generic_cutscene_event_end; } @@ -582,22 +516,15 @@ void play_generic_cutscene( ent_script_event *event ) struct generic_cutscene *generic = event->userdata; generic->state = k_generic_cutscene_state_wake; } +#endif bool on_cutscene_marker( ent_script_event *event, const char *marker ) { if( event->type != k_escript_event_allocate ) - { - struct generic_cutscene *generic = event->userdata; - - if( generic->state == k_generic_cutscene_state_playing ) - { + if( _cutscene.state == k_cutscene_state_playing ) if( _cutscene.marker_this_frame ) - { if( vg_str_eq( marker, _cutscene.marker_this_frame ) ) return 1; - } - } - } return 0; } @@ -650,6 +577,7 @@ bool on_nugget_once( ent_script_event *event, const char *nugget_alias ) return 0; } +#if 0 enum generic_cutscene_event optional_video_wrapper( const struct generic_cutscene *cutscene_template, const char *nugget_alias, u64 nugget_visible_value, @@ -690,6 +618,7 @@ enum generic_cutscene_event challenge_video_wrapper( const struct generic_cutsce return cs_event; } +#endif #include "scripts/generic.c" #include "scripts/blocker_break.c" @@ -709,21 +638,15 @@ struct ent_script_table_entry _ent_script_table[] = { "board_maker_unlock", _skaterift_script_board_maker_unlock }, { "board_maker", _skaterift_script_board_maker }, - { "intro", _skaterift_script_intro }, - { "gino.intro", _skaterift_script_gino_intro }, - { "gino.hub", _skaterift_script_gino_hub }, - { "gino.volc", _skaterift_script_gino_volc }, + //{ "intro", _skaterift_script_intro }, { "hub", _skaterift_script_hub }, { "tutorial_island", _skaterift_script_tutorial_island }, { "ch1s3", _skaterift_script_ch1s3 }, - { "ch1s3b", _skaterift_script_ch1s3b }, { "ch1s4", _skaterift_script_ch1s4 }, { "ch1s5", _skaterift_script_ch1s5 }, { "ch1s6a", _skaterift_script_ch1s6a }, - { "unlock_docks", _skaterift_script_unlock_docks }, - { "unlock_mtzero", _skaterift_script_unlock_mtzero }, { "ch2s1", _skaterift_script_ch2s1 }, { "ch2s2", _skaterift_script_ch2s2 }, { "first_mtzero", _skaterift_script_first_mtzero }, @@ -735,17 +658,13 @@ struct ent_script_table_entry _ent_script_table[] = { "ch2s6", _skaterift_script_ch2s6 }, { "ch2e1", _skaterift_script_ch2e1 }, - { "unlock_city", _skaterift_script_unlock_city }, { "ch3s1", _skaterift_script_ch3s1 }, { "ch3s2", _skaterift_script_ch3s2 }, { "ch3s3", _skaterift_script_ch3s3 }, - { "unlock_valley", _skaterift_script_unlock_valley }, - { NULL } }; - /* -------------------------------------------------------------------------------------------------------------------- * save data */ diff --git a/src/skaterift_script.h b/src/skaterift_script.h index 5d1d7fd..8cbad90 100644 --- a/src/skaterift_script.h +++ b/src/skaterift_script.h @@ -8,6 +8,7 @@ void _skaterift_script_load_savedata( vg_msg *sav ); u64 _skaterift_script_nugget_status( const char *nugget_alias ); void _skaterift_script_nugget_set( const char *nugget_alias, u64 value ); +#if 0 struct generic_cutscene { enum generic_cutscene_state @@ -35,3 +36,4 @@ enum generic_cutscene_event enum generic_cutscene_event generic_cutscene_wrapper( const struct generic_cutscene *cutscene_template, ent_script_event *event ); void play_generic_cutscene( ent_script_event *event ); +#endif diff --git a/src/world.c b/src/world.c index ba492ae..c94fd56 100644 --- a/src/world.c +++ b/src/world.c @@ -40,7 +40,7 @@ void world_update( world_instance *world, v3f pos ) { ent_script_update( world ); ent_route_preupdate(); - _npc_gino_preupdate(); + _ent_npc_preupdate(); world_routes_update_timer_texts( world ); world_routes_update( world ); ent_traffic_update( world, pos ); @@ -55,7 +55,6 @@ void world_gui( ui_context *ctx, world_instance *world ) { ent_skateshop_gui( ctx ); _ent_challenge_ui( ctx ); - _npc_gino_imgui( ctx ); } bool world_set_event( enum world_event event ) diff --git a/src/world.h b/src/world.h index 776edf9..066309d 100644 --- a/src/world.h +++ b/src/world.h @@ -177,6 +177,7 @@ struct world_instance ent_region, ent_glider, ent_list, + ent_npc, file_entity_ref, ent_script; @@ -269,7 +270,6 @@ struct world_static k_world_event_route_leaderboard, k_world_event_interact, k_world_event_board_maker, - k_world_event_gino, k_world_event_max } event; diff --git a/src/world_load.c b/src/world_load.c index d2c75b3..b25e859 100644 --- a/src/world_load.c +++ b/src/world_load.c @@ -115,6 +115,7 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vo AF_LOAD_ARRAY_STRUCT( af, &world->ent_list, ent_list, heap ); AF_LOAD_ARRAY_STRUCT( af, &world->file_entity_ref, file_entity_ref, heap ); AF_LOAD_ARRAY_STRUCT( af, &world->ent_script, ent_script, heap ); + AF_LOAD_ARRAY_STRUCT( af, &world->ent_npc, ent_npc, heap ); } array_file_ptr infos; @@ -486,7 +487,7 @@ void skaterift_load_world_start( addon_id addon_id, bool preview ) _world.event = k_world_event_none; player__clear_world_dependent_variables(); relink_all_remote_player_worlds(); - _npc_gino_reset(); + _ent_npc_reset(); vg_loader_set_user_information( "Saving current world" ); } else diff --git a/src/world_render.c b/src/world_render.c index 27c499e..5986151 100644 --- a/src/world_render.c +++ b/src/world_render.c @@ -1060,7 +1060,7 @@ static void render_other_entities( world_instance *world, vg_camera *cam ) } cutscene_render( world, cam ); - _npc_gino_render( cam ); + _ent_npc_render( cam ); } void render_world( world_instance *world, vg_camera *cam, diff --git a/src/world_volumes.c b/src/world_volumes.c index 160c325..6d7d859 100644 --- a/src/world_volumes.c +++ b/src/world_volumes.c @@ -160,17 +160,28 @@ next_volume:; if( _world.event == k_world_event_interact ) { - if( button_down( k_srbind_maccept ) ) + ent_volume *volume = _world_volumes.active_volume_interact; + if( volume->flags & k_ent_volume_flag_disabled ) + { + /* might get turned off by another system eg scripts */ + if( world_clear_event( k_world_event_interact ) ) + { + _world_volumes.active_volume_interact = NULL; + gui_helper_reset( k_gui_helper_mode_clear ); + } + } + else if( button_down( k_srbind_maccept ) ) { - ent_volume *volume = _world_volumes.active_volume_interact; if( volume->target ) { srinput.state = k_input_state_resume; - - if( world_clear_event( k_world_event_interact ) ) + if( !(volume->flags & k_ent_volume_flag_repeatable) ) { - _world_volumes.active_volume_interact = NULL; - gui_helper_reset( k_gui_helper_mode_clear ); + if( world_clear_event( k_world_event_interact ) ) + { + _world_volumes.active_volume_interact = NULL; + gui_helper_reset( k_gui_helper_mode_clear ); + } } ent_call call; -- 2.25.1