dindi dende dondo
authorhgn <hgodden00@gmail.com>
Sun, 25 May 2025 16:36:18 +0000 (17:36 +0100)
committerhgn <hgodden00@gmail.com>
Sun, 25 May 2025 16:36:18 +0000 (17:36 +0100)
62 files changed:
content_skaterift/maps/dev_hub/main.mdl
content_skaterift/maps/dev_tutorial/main.mdl
content_skaterift/maps/mp_mtzero/before.mdl
content_skaterift/maps/mp_mtzero/main.mdl
content_skaterift/maps/mp_spawn/main.mdl
content_skaterift/metascenes/battery_intro.ms [new file with mode: 0644]
content_skaterift/metascenes/ch1s2.ms
content_skaterift/metascenes/ch1s3.ms [new file with mode: 0644]
content_skaterift/metascenes/ch1s3b.ms [new file with mode: 0644]
content_skaterift/metascenes/ch1s4.ms [new file with mode: 0644]
content_skaterift/metascenes/ch1s6a.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2e1.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s1.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s2.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s3a.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s4.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s4a.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s5.ms [new file with mode: 0644]
content_skaterift/metascenes/ch2s6.ms [new file with mode: 0644]
content_skaterift/metascenes/ch3s1.ms [new file with mode: 0644]
content_skaterift/metascenes/ch3s2.ms [new file with mode: 0644]
content_skaterift/metascenes/ch3s3.ms [new file with mode: 0644]
content_skaterift/metascenes/unlock_city.ms [new file with mode: 0644]
content_skaterift/metascenes/unlock_mtzero.ms [new file with mode: 0644]
content_skaterift/metascenes/unlock_valley.ms [new file with mode: 0644]
skaterift_blender/sr_main.py
skaterift_blender/sr_mdl.py
src/atom.c [new file with mode: 0644]
src/atom.h [new file with mode: 0644]
src/ent_atom.c [new file with mode: 0644]
src/ent_atom.h [new file with mode: 0644]
src/ent_challenge.c
src/ent_challenge.h
src/ent_cutscene.c [new file with mode: 0644]
src/ent_cutscene.h [new file with mode: 0644]
src/ent_glider.c
src/ent_list.c
src/ent_list.h
src/ent_npc.h
src/ent_objective.c
src/ent_region.c
src/ent_script.c
src/ent_script.h
src/ent_skateshop.c
src/entity.h
src/menu.c
src/metascene.c
src/metascene.h
src/save.c
src/scripts/board_maker.c [new file with mode: 0644]
src/scripts/cutscene.c
src/scripts/generic.c
src/scripts/tutorial_island.c
src/skaterift.c
src/skaterift_script.c
src/skaterift_script.h
src/world.h
src/world_entity.c
src/world_load.c
src/world_render.c
src/world_routes.c
src/world_volumes.c

index 42fbf25f18d44d98acf367f4a55b3266825c722b..72946d4db1c8f8e2ee872a27b6b5f852204210db 100644 (file)
Binary files a/content_skaterift/maps/dev_hub/main.mdl and b/content_skaterift/maps/dev_hub/main.mdl differ
index d7beaab2ae1d29dfcada7e99639ad04af88f3863..adb1b874d177d782d41b638d38357d32bdeaaeb9 100644 (file)
Binary files a/content_skaterift/maps/dev_tutorial/main.mdl and b/content_skaterift/maps/dev_tutorial/main.mdl differ
index a7d093739877ce7778c24e58724a531be7169979..ed66d46ab8206cc6483529c09b1aa5f915b9c47b 100644 (file)
Binary files a/content_skaterift/maps/mp_mtzero/before.mdl and b/content_skaterift/maps/mp_mtzero/before.mdl differ
index 6aeedf0bbc65b09010b498d747e8a37ff9081966..2d4686c459de687363182f1f844a4140df6ab68b 100644 (file)
Binary files a/content_skaterift/maps/mp_mtzero/main.mdl and b/content_skaterift/maps/mp_mtzero/main.mdl differ
index 940b7d6003359f760eb0bf5b78bdf1dfd96d3132..d8d1473aa358ce448bbd8a713ae8b7f87018c996 100644 (file)
Binary files a/content_skaterift/maps/mp_spawn/main.mdl and b/content_skaterift/maps/mp_spawn/main.mdl differ
diff --git a/content_skaterift/metascenes/battery_intro.ms b/content_skaterift/metascenes/battery_intro.ms
new file mode 100644 (file)
index 0000000..3160502
Binary files /dev/null and b/content_skaterift/metascenes/battery_intro.ms differ
index 905d9452c30f023ec8c76eae81125221fa64a194..bca19c320739d954be969f5ceb96588a4e258eba 100644 (file)
Binary files a/content_skaterift/metascenes/ch1s2.ms and b/content_skaterift/metascenes/ch1s2.ms differ
diff --git a/content_skaterift/metascenes/ch1s3.ms b/content_skaterift/metascenes/ch1s3.ms
new file mode 100644 (file)
index 0000000..6703c1f
Binary files /dev/null and b/content_skaterift/metascenes/ch1s3.ms differ
diff --git a/content_skaterift/metascenes/ch1s3b.ms b/content_skaterift/metascenes/ch1s3b.ms
new file mode 100644 (file)
index 0000000..3825fa3
Binary files /dev/null and b/content_skaterift/metascenes/ch1s3b.ms differ
diff --git a/content_skaterift/metascenes/ch1s4.ms b/content_skaterift/metascenes/ch1s4.ms
new file mode 100644 (file)
index 0000000..5e9d08b
Binary files /dev/null and b/content_skaterift/metascenes/ch1s4.ms differ
diff --git a/content_skaterift/metascenes/ch1s6a.ms b/content_skaterift/metascenes/ch1s6a.ms
new file mode 100644 (file)
index 0000000..7664757
Binary files /dev/null and b/content_skaterift/metascenes/ch1s6a.ms differ
diff --git a/content_skaterift/metascenes/ch2e1.ms b/content_skaterift/metascenes/ch2e1.ms
new file mode 100644 (file)
index 0000000..6a6ea27
Binary files /dev/null and b/content_skaterift/metascenes/ch2e1.ms differ
diff --git a/content_skaterift/metascenes/ch2s1.ms b/content_skaterift/metascenes/ch2s1.ms
new file mode 100644 (file)
index 0000000..41e7849
Binary files /dev/null and b/content_skaterift/metascenes/ch2s1.ms differ
diff --git a/content_skaterift/metascenes/ch2s2.ms b/content_skaterift/metascenes/ch2s2.ms
new file mode 100644 (file)
index 0000000..d26e40a
Binary files /dev/null and b/content_skaterift/metascenes/ch2s2.ms differ
diff --git a/content_skaterift/metascenes/ch2s3a.ms b/content_skaterift/metascenes/ch2s3a.ms
new file mode 100644 (file)
index 0000000..89867e0
Binary files /dev/null and b/content_skaterift/metascenes/ch2s3a.ms differ
diff --git a/content_skaterift/metascenes/ch2s4.ms b/content_skaterift/metascenes/ch2s4.ms
new file mode 100644 (file)
index 0000000..34aef21
Binary files /dev/null and b/content_skaterift/metascenes/ch2s4.ms differ
diff --git a/content_skaterift/metascenes/ch2s4a.ms b/content_skaterift/metascenes/ch2s4a.ms
new file mode 100644 (file)
index 0000000..e428f7c
Binary files /dev/null and b/content_skaterift/metascenes/ch2s4a.ms differ
diff --git a/content_skaterift/metascenes/ch2s5.ms b/content_skaterift/metascenes/ch2s5.ms
new file mode 100644 (file)
index 0000000..3ad2cb0
Binary files /dev/null and b/content_skaterift/metascenes/ch2s5.ms differ
diff --git a/content_skaterift/metascenes/ch2s6.ms b/content_skaterift/metascenes/ch2s6.ms
new file mode 100644 (file)
index 0000000..9808e08
Binary files /dev/null and b/content_skaterift/metascenes/ch2s6.ms differ
diff --git a/content_skaterift/metascenes/ch3s1.ms b/content_skaterift/metascenes/ch3s1.ms
new file mode 100644 (file)
index 0000000..f770e80
Binary files /dev/null and b/content_skaterift/metascenes/ch3s1.ms differ
diff --git a/content_skaterift/metascenes/ch3s2.ms b/content_skaterift/metascenes/ch3s2.ms
new file mode 100644 (file)
index 0000000..6769287
Binary files /dev/null and b/content_skaterift/metascenes/ch3s2.ms differ
diff --git a/content_skaterift/metascenes/ch3s3.ms b/content_skaterift/metascenes/ch3s3.ms
new file mode 100644 (file)
index 0000000..431c73b
Binary files /dev/null and b/content_skaterift/metascenes/ch3s3.ms differ
diff --git a/content_skaterift/metascenes/unlock_city.ms b/content_skaterift/metascenes/unlock_city.ms
new file mode 100644 (file)
index 0000000..dfb2238
Binary files /dev/null and b/content_skaterift/metascenes/unlock_city.ms differ
diff --git a/content_skaterift/metascenes/unlock_mtzero.ms b/content_skaterift/metascenes/unlock_mtzero.ms
new file mode 100644 (file)
index 0000000..22bd2bd
Binary files /dev/null and b/content_skaterift/metascenes/unlock_mtzero.ms differ
diff --git a/content_skaterift/metascenes/unlock_valley.ms b/content_skaterift/metascenes/unlock_valley.ms
new file mode 100644 (file)
index 0000000..f892fb8
Binary files /dev/null and b/content_skaterift/metascenes/unlock_valley.ms differ
index 33461958b219dbba611ddd22b265bc61ec4148da..ba854e56f7b8538fb0750ffcf4ee542a1545107b 100644 (file)
@@ -40,7 +40,8 @@ sr_entity_list = [
    ('ent_npc',          'npc',            '', 27 ),
    # reserved 28.. armature
    ('ent_script',       'Script',         '', 29 ),
-   ('ent_cutscene',     'Cutscene',       '', 30 ),
+   ('ent_atom',         'Atom',           '', 30 ),
+   ('ent_cutscene',     'Cutscene',       '', 31 ),
 ]
 
 MDL_VERSION_NR = 109
@@ -283,6 +284,7 @@ class ent_list(Structure):
    _fields_ = [("entity_ref_start",c_uint16),("entity_ref_count",c_uint16),
                ("alias_type",c_uint8),("none0",c_uint8),("none1",c_uint8),("none2",c_uint8),
                ("pstr_alias",c_uint32) ]
+   sr_functions = { 'visible': 0x01 }
 #}
 
 # used in ent_list
@@ -339,6 +341,23 @@ class ent_script(Structure):
                ("flags",c_uint32)]
 #}
 
+class ent_atom(Structure):
+#{
+   _fields_ = [("pstr_alias",c_uint32),
+               ("flags",c_uint32)]
+   sr_functions = { 'set': 0x1, 'pass_equal': 0x1, 'pass_greater': 0x1, 'set_or': 0x1, 'set_and': 0x1 }
+   sr_events = [ 'changed', 'true', 'false' ]
+#}
+
+class ent_cutscene(Structure):
+#{
+   _fields_ = [("pstr_path",c_uint32),
+               ("flags",c_uint32)]
+
+   sr_functions = { 'play': 0x00 }
+   sr_events = [ 'start', 'end' ]
+#}
+
 class ent_water(Structure):
 #{
    _fields_ = [("transform",mdl_transform),
@@ -570,17 +589,7 @@ class ent_prop(Structure):
 
 def sr_filter_ent_type( obj, ent_types ):
 #{
-   # if obj == bpy.context.active_object: return False
-
-   for c0 in obj.users_collection:#{
-      for c1 in bpy.context.active_object.users_collection:#{
-         if c0 == c1:#{
-            return (ent_types == None) or (obj_ent_type( obj ) in ent_types)
-         #}
-      #}
-   #}
-
-   return False
+   return (ent_types == None) or (obj_ent_type( obj ) in ent_types)
 #}
 
 def v4_dot( a, b ):#{
@@ -2193,6 +2202,19 @@ class SR_OBJECT_ENT_SCRIPT(bpy.types.PropertyGroup):
    #         poll=lambda self,obj: sr_filter_ent_type(obj,['ent_list']))
 #}
 
+class SR_OBJECT_ENT_ATOM(bpy.types.PropertyGroup):
+#{
+   alias: bpy.props.StringProperty( name="Alias" )
+   mundial: bpy.props.BoolProperty( name="Global" )
+   scrap: bpy.props.BoolProperty( name="Scrap" )
+#}
+
+class SR_OBJECT_ENT_CUTSCENE( bpy.types.PropertyGroup ):
+#{
+   path: bpy.props.StringProperty( name="Path" )
+   freeze_player: bpy.props.BoolProperty( name="Freeze Player" )
+#}
+
 class SR_OBJECT_ENT_LOGIC(bpy.types.PropertyGroup):
 #{
    tipo: bpy.props.EnumProperty( name='Type',\
@@ -2376,6 +2398,8 @@ class SR_OBJECT_PROPERTIES(bpy.types.PropertyGroup):
    ent_npc: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_NPC)
    ent_script: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_SCRIPT)
    ent_logic: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_LOGIC)
+   ent_atom: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_ATOM)
+   ent_cutscene: bpy.props.CollectionProperty(type=SR_OBJECT_ENT_CUTSCENE)
 
    ent_type: bpy.props.EnumProperty(
       name="Type",
@@ -3465,6 +3489,22 @@ def cv_draw_pixel():
             blf.draw(0, F"'{data.script_alias}'" )
             blf.color(0,1.0,1.0,1.0,1.0)
          #}
+         if ent_type == 'ent_atom':
+         #{
+            data = obj.SR_data.ent_atom[0]
+            blf.color(0,0.6,0.9,0.3,1.0)
+            blf.position(0,co[0],co[1]-16,0)
+            blf.draw(0, F"'{data.alias}'" )
+            blf.color(0,1.0,1.0,1.0,1.0)
+         #}
+         if ent_type == 'ent_cutscene':
+         #{
+            data = obj.SR_data.ent_cutscene[0]
+            blf.color(0,0.6,0.9,0.3,1.0)
+            blf.position(0,co[0],co[1]-16,0)
+            blf.draw(0, F"'{data.path}'" )
+            blf.color(0,1.0,1.0,1.0,1.0)
+         #}
       #}
    #}
 #}
@@ -3499,6 +3539,7 @@ classes = [ SR_INTERFACE, SR_MATERIAL_PANEL, SR_MARKER_PANEL, SR_ENTITY_PANEL, \
             SR_OBJECT_ENT_LIST_ENTRY, SR_UL_ENT_LIST, SR_OBJECT_ENT_LIST, \
             SR_OT_ENT_LIST_NEW_ITEM, SR_OT_ENT_LIST_DEL_ITEM,\
             SR_OBJECT_ENT_GLIDER, SR_OBJECT_ENT_NPC, SR_OBJECT_ENT_SCRIPT, SR_OBJECT_ENT_LOGIC, \
+            SR_OBJECT_ENT_ATOM, SR_OBJECT_ENT_CUTSCENE, \
             \
             SR_OBJECT_PROPERTIES, SR_LIGHT_PROPERTIES, SR_BONE_PROPERTIES, 
             SR_MESH_PROPERTIES, SR_MATERIAL_PROPERTIES, SR_MARKER_PROPERTIES \
index 75db2213d8d00ea618bf64c1c720ab886d8d9bf9..dfa767167d86f01a1c50c392acd06dab5180597c 100644 (file)
@@ -945,9 +945,30 @@ def _mdl_compiler_compile_entities():
             script = ent_script()
             script.pstr_script_name = _af_pack_string( obj_data.script_alias )
             #script.entity_list_id = sr_entity_id( obj_data.entity_list )
-            script.falgs = obj_data.flags
+            script.flags = obj_data.flags
             sr_ent_push( script )
          #}
+         elif ent_type == 'ent_atom':#{
+            obj_data = obj.SR_data.ent_atom[0]
+            atom = ent_atom()
+            if not obj_data.scrap:
+               atom.pstr_alias = _af_pack_string( obj_data.alias )
+            atom.flags = 0x00
+            if obj_data.mundial:
+               atom.flags |= 0x1
+            if obj_data.scrap:
+               atom.flags |= 0x2
+            sr_ent_push( atom )
+         #}
+         elif ent_type == 'ent_cutscene':#{
+            obj_data = obj.SR_data.ent_cutscene[0]
+            cs = ent_cutscene()
+            cs.pstr_path = _af_pack_string( obj_data.path )
+            cs.flags = 0x00
+            if obj_data.freeze_player:
+               cs.flags |= 0x1
+            sr_ent_push( cs )
+         #}
          elif ent_type == 'ent_cubemap':
          #{
             cubemap = ent_cubemap()
diff --git a/src/atom.c b/src/atom.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/atom.h b/src/atom.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/ent_atom.c b/src/ent_atom.c
new file mode 100644 (file)
index 0000000..24a8494
--- /dev/null
@@ -0,0 +1,255 @@
+#include "ent_atom.h"
+
+struct _atom
+{
+   struct atom_list
+   {
+      atom atoms[32];
+      u32 count;
+   }
+   lists[k_atom_list_max];
+}
+_atom;
+
+const char *_ent_atom_name( u32 atom_entity_id )
+{
+   world_instance *world = &_world.main;
+   ent_atom *atom = af_arritm( &world->ent_atom, mdl_entity_id_id( atom_entity_id ) );
+
+   if( atom->flags & k_ent_atom_scrap )
+      return "<anonymous>";
+   else
+      return af_str( &world->meta.af, atom->pstr_alias );
+}
+
+i32 _ent_atom_get( u32 atom_entity_id )
+{
+   VG_ASSERT( mdl_entity_id_type(atom_entity_id) == k_ent_atom );
+   world_instance *world = &_world.main;
+   ent_atom *atom = af_arritm( &world->ent_atom, mdl_entity_id_id( atom_entity_id ) );
+
+   if( atom->flags & k_ent_atom_scrap )
+      return atom->scrap_value;
+   else
+   {
+      const char *alias = af_str( &world->meta.af, atom->pstr_alias );
+      return _atom_get( (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world, alias );
+   }
+}
+
+void _ent_atom_set( u32 atom_entity_id, i32 value )
+{
+   VG_ASSERT( mdl_entity_id_type(atom_entity_id) == k_ent_atom );
+   world_instance *world = &_world.main;
+   ent_atom *atom = af_arritm( &world->ent_atom, mdl_entity_id_id( atom_entity_id ) );
+
+   if( atom->flags & k_ent_atom_scrap )
+   {
+      atom->scrap_value = value;
+      // Scraps are on their own, only needs to broadcast these to itself and no one else.
+      _world_raise_event( atom_entity_id, "changed" );
+      _world_raise_event( atom_entity_id, value? "true": "false" );
+   }
+   else
+   {
+      enum e_atom_list list = (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world;
+      const char *alias = af_str( &world->meta.af, atom->pstr_alias );
+      _atom_set( list, alias, value );
+      _atom_notify( list, alias );
+   }
+}
+
+entity_event_result _ent_atom_event( ent_event *event )
+{
+   world_instance *world = &_world.main;
+   bool pass = 0, fail = 0;
+
+   if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "pass_equal" ) )
+   {
+      if( event->flags & k_ent_event_data_const_i32 )
+      {
+         pass = _ent_atom_get( event->recieve_entity_id ) == (u64)event->data.const_i32;
+         fail = !pass;
+      }
+      else return k_entity_event_result_invalid;
+   }
+   else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "pass_greater" ) )
+   {
+      if( event->flags & k_ent_event_data_const_i32 )
+      {
+         pass = _ent_atom_get( event->recieve_entity_id ) > (u64)event->data.const_i32;
+         fail = !pass;
+      }
+      else return k_entity_event_result_invalid;
+   }
+   else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set" ) )
+   {
+      if( event->flags & k_ent_event_data_const_i32 )
+      {
+         _ent_atom_set( event->recieve_entity_id, event->data.const_i32 );
+         vg_info( KBLU "Value of atom '%s' is now %d\n", _ent_atom_name( event->recieve_entity_id ), event->data.const_i32 );
+      }
+      else return k_entity_event_result_invalid;
+   }
+   else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set_or" ) )
+   {
+      if( event->flags & k_ent_event_data_const_i32 )
+      {
+         i32 new = _ent_atom_get( event->recieve_entity_id ) | event->data.const_i32;
+         _ent_atom_set( event->recieve_entity_id, new );
+         vg_info( KBLU "Value of atom '%s' is now %d\n", _ent_atom_name( event->recieve_entity_id ), new );
+      }
+      else return k_entity_event_result_invalid;
+   }
+   else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "set_and" ) )
+   {
+      if( event->flags & k_ent_event_data_const_i32 )
+      {
+         i32 new = _ent_atom_get( event->recieve_entity_id ) | event->data.const_i32;
+         _ent_atom_set( event->recieve_entity_id, new );
+         vg_info( KBLU "Value of atom '%s' is now %d\n", _ent_atom_name( event->recieve_entity_id ), new );
+      }
+      else return k_entity_event_result_invalid;
+   }
+   else return k_entity_event_result_unhandled;
+
+   if( pass ) _world_raise_event( event->recieve_entity_id, "pass" );
+   if( fail ) _world_raise_event( event->recieve_entity_id, "fail" );
+   return k_entity_event_result_OK;
+}
+
+void serialize_atoms( enum e_atom_list list, vg_msg *msg )
+{
+   for( u32 i=0; i<_atom.lists[list].count; i ++ )
+   {
+      atom *a = &_atom.lists[list].atoms[i];
+      vg_msg_wkvnum( msg, a->alias, k_vg_msg_i32, 1, &a->status );
+   }
+}
+
+static atom *_atom_internal( enum e_atom_list list, const char *alias )
+{
+   struct atom_list *l = &_atom.lists[list];
+   for( u32 i=0; i<l->count; i ++ )
+   {
+      atom *a = &l->atoms[i];
+      if( !strcmp( a->alias, alias ) )
+         return a;
+   }
+   return NULL;
+}
+
+i32 _atom_get( enum e_atom_list list, const char *alias )
+{
+   atom *a = _atom_internal( list, alias );
+   if( a ) return a->status;
+   else    return 0;
+}
+
+void _atom_notify( enum e_atom_list list, const char *alias )
+{
+   i32 value = _atom_get( list, alias );
+
+   world_instance *world = &_world.main;
+   for( u32 i=0; i<af_arrcount( &world->ent_atom ); i ++ )
+   {
+      ent_atom *atom = af_arritm( &world->ent_atom, i );
+      if( af_str_eq( &world->meta.af, atom->pstr_alias, alias, vg_strdjb2(alias)) )
+      {
+         _world_raise_event( mdl_entity_id( k_ent_atom, i ), "changed" );
+         _world_raise_event( mdl_entity_id( k_ent_atom, i ), value? "true": "false" );
+      }
+   }
+}
+
+void _atom_set( enum e_atom_list list, const char *alias, i32 value )
+{
+   atom *a = _atom_internal( list, alias );
+   if( !a )
+   {
+      struct atom_list *l = &_atom.lists[list];
+      if( l->count == VG_ARRAY_LEN( l->atoms ) )
+      {
+         vg_error( "Too many atoms in list %d! READS WILL BE 0!\n", list );
+         return;
+      }
+
+      a = &l->atoms[ l->count ++ ];
+      a->status = 0;
+      vg_strncpy( alias, a->alias, sizeof(a->alias), k_strncpy_overflow_fatal );
+   }
+
+   a->status = value;
+}
+
+void _atom_list_clear( enum e_atom_list list )
+{
+   _atom.lists[ list ].count = 0;
+}
+
+static int _ent_atom_ccmd( int argc, const char *argv[] )
+{
+   if( argc < 2 ) 
+   {
+      vg_error( "Usage: atom <scope> <alias> <optional set-value>\n" );
+      return 0;
+   }
+
+   world_instance *world = &_world.main;
+   enum e_atom_list list = k_atom_list_max;
+
+        if( !strcmp( argv[0], "world" ) ) list = k_atom_list_world;
+   else if( !strcmp( argv[0], "global" ) ) list = k_atom_list_global;
+   else 
+   {
+      vg_error( "No atom list '%s'\n", argv[0] );
+      return 0;
+   }
+
+   if( !strcmp( argv[1], "list" ) )
+   {
+      struct atom_list *l = &_atom.lists[ list ];
+      for( u32 i=0; i<l->count; i ++ )
+      {
+         atom *a = &l->atoms[i];
+         vg_info( "%s: %d\n", a->alias, a->status );
+      }
+   }
+
+   if( !strcmp( argv[1], "set" ) )
+   {
+      if( argc==4 ) 
+      {
+         _atom_set( list, argv[2], atoi( argv[3] ) );
+         _atom_notify( list, argv[2] );
+      }
+      else
+         vg_error( "atom <scope> set <name> <value\n" );
+   }
+   
+   return 1;
+}
+
+static void _ent_atom_ccmd_poll( int argc, const char *argv[] )
+{
+   const char *term = argv[argc-1];
+   world_instance *world = &_world.main;
+
+   if( argc == 1 )
+   {
+      console_suggest_score_text( "world", term, 0 );
+      console_suggest_score_text( "global", term, 0 );
+   }
+
+   if( argc == 2 )
+   {
+      console_suggest_score_text( "list", term, 0 );
+      console_suggest_score_text( "set", term, 0 );
+   }
+}
+
+void _ent_atom_init(void)
+{
+   vg_console_reg_cmd( "atom", _ent_atom_ccmd, _ent_atom_ccmd_poll );
+}
+
diff --git a/src/ent_atom.h b/src/ent_atom.h
new file mode 100644 (file)
index 0000000..2860997
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once
+
+enum e_atom_list
+{
+   k_atom_list_global,
+   k_atom_list_world,
+   k_atom_list_max
+};
+
+typedef struct atom atom;
+struct atom
+{
+   char alias[48];
+   i32 status;
+};
+
+void serialize_atoms( enum e_atom_list list, vg_msg *msg );
+
+void _atom_list_clear( enum e_atom_list list );
+i32 _atom_get( enum e_atom_list list, const char *alias );
+void _atom_set( enum e_atom_list list, const char *alias, i32 value );
+void _atom_notify( enum e_atom_list list, const char *alias );
+void _atom_notify_list( enum e_atom_list list );
+
+entity_event_result _ent_atom_event( ent_event *event );
+void _ent_atom_init(void);
index 02bbae26c8d4e683ddbeba3dc9f0b05cb4c85b2d..8dbaa996459c43341a8ca22f78c04fe38c65d9f8 100644 (file)
@@ -21,6 +21,7 @@ void _ent_challenge_clear( ent_challenge *challenge )
 void _ent_challenge_win(void)
 {
    _world_raise_event( _world.active_challenge_id, "complete" );
+   _world_raise_event( _world.active_challenge_id, "true" );
 
    world_instance *world = &_world.main;
    ent_challenge *challenge = af_arritm( &world->ent_challenge, mdl_entity_id_id( _world.active_challenge_id ) );
@@ -28,7 +29,6 @@ void _ent_challenge_win(void)
    challenge->status = 1;
    ent_region_re_eval( world );
 
-#if 0
    struct ent_script_event event;
    struct script_event_completion_changed inf = {
       .entity_id = _world.active_challenge_id,
@@ -37,7 +37,6 @@ void _ent_challenge_win(void)
    event.type = k_escript_event_completion_changed;
    event.info = &inf;
    ent_script_propogate_event( world, &event );
-#endif
 
    if( world_clear_event( k_world_event_challenge ) )
    {
@@ -161,6 +160,7 @@ void ent_challenge_update(void)
          menu.disable_open = 0;
 
          _world_raise_event( _world.active_challenge_id, "activate" );
+         _restart_active_challenge();
       }
       else if( button_down( k_srbind_mback ) )
       {
@@ -306,3 +306,87 @@ void _ent_challenge_ui( ui_context *ctx )
       ctx->font = &vgf_default_small;
    }
 }
+
+static int _skaterift_challenge_ccmd( int argc, const char *argv[] )
+{
+   if( argc < 1 ) 
+   {
+      vg_error( "Usage: challenge <index/'all'> <optional set-value>\n" );
+      return 0;
+   }
+
+   bool all = 0;
+   if( !strcmp( argv[0], "all" ) ) 
+      all = 1;
+
+   world_instance *world = &_world.main;
+
+   u32 index = 0;
+   for( u32 i=0; i<af_arrcount( &world->ent_challenge ); i ++ )
+   {
+      ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+      const char *alias = af_str( &world->meta.af, challenge->pstr_alias );
+      
+      if( all || (atoi( argv[0] ) == index) )
+      {
+         if( argc==2 )
+         {
+            challenge->status = atoi( argv[1] );
+            ent_region_re_eval( world );
+            
+            struct ent_script_event event;
+            struct script_event_completion_changed inf = {
+               .entity_id = mdl_entity_id( k_ent_challenge, i ),
+               .completion_flags = 0
+            };
+            event.type = k_escript_event_completion_changed;
+            event.info = &inf;
+            ent_script_propogate_event( world, &event );
+         }
+         else
+            vg_info( "[challenge %u '%s'] %u\n", index, alias, challenge->status );
+      }
+
+      index ++;
+   }
+   for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+   {
+      ent_route *route = af_arritm( &world->ent_route, i );
+      const char *alias = af_str( &world->meta.af, route->pstr_name );
+
+      if( all || (atoi( argv[0] ) == index) )
+      {
+         if( argc==2 )
+         {
+            route->flags &= ~((u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver));
+
+            if( !strcmp( argv[1], "silver" ) )
+               route->flags |= (u32)(k_ent_route_flag_achieve_silver);
+            if( !strcmp( argv[1], "gold" ) )
+               route->flags |= (u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver);
+            ent_region_re_eval( world );
+
+            struct ent_script_event event;
+            struct script_event_completion_changed inf = {
+               .entity_id = mdl_entity_id( k_ent_route, i ),
+               .completion_flags = route->flags
+            };
+            event.type = k_escript_event_completion_changed;
+            event.info = &inf;
+            ent_script_propogate_event( world, &event );
+         }
+         else
+            vg_info( "[route %u '%s'] %s%s\n", index, alias,
+                        (route->flags & k_ent_route_flag_achieve_silver? "SILVER": "_____"),
+                        (route->flags & k_ent_route_flag_achieve_gold?   "_GOLD":  "_____" ) );
+      }
+
+      index ++;
+   }
+   return 1;
+}
+
+void _ent_challenge_init(void)
+{
+   vg_console_reg_cmd( "challenge", _skaterift_challenge_ccmd, NULL );
+}
index 4c4b6fdb1e7eeadfd8722ad149960d958e17f015..e449e6f1ef680d61fa795a7f313fb9fb73049c37 100644 (file)
@@ -6,3 +6,4 @@ void _ent_challenge_ui( ui_context *ctx );
 void _restart_active_challenge(void);
 void _ent_challenge_complete( ent_challenge *challenge );
 void _ent_challenge_win(void);
+void _ent_challenge_init(void);
diff --git a/src/ent_cutscene.c b/src/ent_cutscene.c
new file mode 100644 (file)
index 0000000..eb95116
--- /dev/null
@@ -0,0 +1,16 @@
+#include "ent_cutscene.h"
+
+entity_event_result _ent_cutscene_event( ent_event *event )
+{
+   world_instance *world = &_world.main;
+   ent_cutscene *cs = af_arritm( &world->ent_cutscene, mdl_entity_id_id( event->recieve_entity_id ) );
+
+        if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "play" ) )
+   {
+      const char *path = af_str( &world->meta.af, cs->pstr_path );
+      _cutscene_load_and_play( path, (cs->flags & k_ent_cutscene_freeze_player), event->recieve_entity_id );
+
+      return k_entity_event_result_OK;
+   }
+   else return k_entity_event_result_unhandled;
+}
diff --git a/src/ent_cutscene.h b/src/ent_cutscene.h
new file mode 100644 (file)
index 0000000..13e6ce9
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+entity_event_result _ent_cutscene_event( ent_event *event );
index 60e599a9422b63e46c692114f091d22d03dd0b7d..0a4a6e492cd2f706d19ac0144c02cff3f9c81a8a 100644 (file)
@@ -20,9 +20,8 @@ entity_event_result ent_glider_event( ent_event *event )
    }
    else if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "equip" ) )
    {
-      if( glider->flags & 0x1 )
+      if( !(glider->flags & k_ent_glider_flag_locked) )
          player_glide_equip_glider();
-
       return k_entity_event_result_OK;
    }
    else 
index e2f47013fe154143b6b655d3ba3c8cbc83af38dd..6e2ca24ec0d370586c61606f568d869415f933b9 100644 (file)
@@ -87,8 +87,8 @@ void _ent_list_set_visible( ent_list *list, bool visible )
       else if( iter.type == k_ent_glider )
       {
          ent_glider *glider = af_arritm( &world->ent_glider, iter.index );
-         if( visible ) glider->flags |= 0x1;
-         else          glider->flags &= ~((u32)0x1);
+         if( visible ) glider->flags &= ~((u32)0x1);
+         else          glider->flags |= 0x1;
       }
    }
 }
@@ -118,27 +118,21 @@ bool _ent_list_check_completed( ent_list *list )
    return 1;
 }
 
-void _ent_list_set_as_targets( ent_list *list, bool yes )
+entity_event_result _ent_list_world_event( ent_event *event )
 {
-#if 0
    world_instance *world = &_world.main;
-   struct ent_list_iter iter;
-   _ent_list_iter_start( &iter, list, 0 );
+   ent_list *list = af_arritm( &world->ent_list, mdl_entity_id_id( event->recieve_entity_id ) );
 
-   while( _ent_list_iter( &iter ) )
+   if( AF_STR_EQ( &world->meta.af, event->pstr_recieve_event, "visible" ) )
    {
-      if( iter.type == k_ent_challenge )
+      // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you)
+      if( event->flags == k_ent_event_data_const_i32 )
       {
-         ent_challenge *challenge = af_arritm( &world->ent_challenge, iter.index );
-         if( yes ) challenge->flags |=   (u32)k_ent_challenge_target;
-         else      challenge->flags &= ~((u32)k_ent_challenge_target);
-      }
-      else if( iter.type == k_ent_route )
-      {
-         ent_route *route = af_arritm( &world->ent_route, iter.index );
-         if( yes ) route->flags |=   (u32)k_ent_route_target;
-         else      route->flags &= ~((u32)k_ent_route_target);
+         _ent_list_set_visible( list, event->data.const_i32 );
+         return k_entity_event_result_OK;
       }
+      else
+         return k_entity_event_result_invalid;
    }
-#endif
+   else return k_entity_event_result_unhandled;
 }
index 3ab9e74b549976e866c93acf756b369dcb288f25..808d08d9f593c9e9c938e6da94f59f5c8761b93f 100644 (file)
@@ -12,3 +12,6 @@ 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 );
+entity_event_result _ent_list_world_event( ent_event *event );
+bool _ent_list_check_completed( ent_list *list );
+void _ent_list_set_as_targets( ent_list *list, bool yes );
index 32065cd42adaf9088ff7eb6acfd400c34170b3db..4b607b6eb293d8287c76b6ed21e93d885db60a3f 100644 (file)
@@ -1,5 +1,11 @@
 #pragma once
 
+#define KCOL_JOHN KNRM
+#define KCOL_MIKE KBLU
+#define KCOL_PRES KYEL
+#define KCOL_FBI  KGRN
+#define KCOL_JESUS KMAG
+
 enum npc
 {
    k_npc_none = 0,
index afc3fccffb1890b56a2322d5e21d8cda9cde8b05..2372e9ddc8981d391633eb2eb783d6d218886da7 100644 (file)
@@ -176,5 +176,6 @@ entity_event_result ent_objective_event( ent_event *event )
       else
          return k_entity_event_result_invalid;
    }
+   else
       return k_entity_event_result_unhandled;
 }
index aa1a906c7872c48ce615a5257ab3270b95b204c0..04c1bb2a6d6c5318dbe07f58f9b53258ba8ae6fd 100644 (file)
@@ -107,6 +107,11 @@ void ent_region_re_eval( world_instance *world )
 
          region->flags = combined;
          world_total &= combined;
+
+         if( region->flags & k_ent_route_flag_achieve_silver )
+            _world_raise_event( mdl_entity_id( k_ent_region, j ), "silver" );
+         if( region->flags & k_ent_route_flag_achieve_gold )
+            _world_raise_event( mdl_entity_id( k_ent_region, j ), "gold" );
       }
    }
 
index 2e2a67c4c3ee31337011bbe68b204913de81530f..c21f24bc38ba028d40c77c1ae3309fd95226cd06 100644 (file)
@@ -6,17 +6,23 @@ struct
 }
 _ent_script;
 
-static void ent_script_event_init( ent_script_event *event, world_instance *world, u32 script_index )
+#include "scripts/explode.c"
+#include "scripts/tutorial_island.c"
+#include "scripts/board_maker.c"
+
+struct ent_script_table_entry _ent_script_table[] =
 {
-   event->userdata = _ent_script.userdata_array[ script_index ];
-   event->world = world;
+   { "explode", _skaterift_script_explode },
+   { "volc_main", _skaterift_script_volc },
+   { "board_maker", _skaterift_script_board_maker },
+   { NULL }
+};
 
+static void ent_script_event_init( ent_script_event *event, world_instance *world, u32 script_index )
+{
    ent_script *script = af_arritm( &world->ent_script, script_index );
-   if( script->entity_list_id )
-      event->entity_list = af_arritm( &world->ent_list, mdl_entity_id_id( script->entity_list_id ) );
-   else
-      event->entity_list = NULL;
-
+   event->userdata = _ent_script.userdata_array[ script_index ];
+   event->script_entity_id = mdl_entity_id( k_ent_script, script_index );
    event->script_alias = _ent_script_table[ script->script_id ].alias;
 }
 
@@ -85,18 +91,20 @@ void ent_script_update( world_instance *world )
    ent_script_propogate_event( world, &event );
 }
 
+#if 0
 void ent_script_start( world_instance *world )
 {
-   /* internal start event */
+   /* init before world start */
+   for( u32 i=0; i<af_arrcount( &world->ent_script ); i ++ )
+      _world_raise_event( mdl_entity_id( k_ent_script, i ), "init" );
+
+   /* real world start event */
    struct ent_script_event event;
    event.type = k_escript_event_world_start;
    event.info = NULL;
    ent_script_propogate_event( world, &event );
-
-   /* external start event */
-   for( u32 i=0; i<af_arrcount( &world->ent_script ); i ++ )
-      _world_raise_event( mdl_entity_id( k_ent_script, i ), "start" );
 }
+#endif
 
 entity_event_result _ent_script_world_event( ent_event *event )
 {
index 3e4457ac95043797addcf762dc10de9abb856c2a..4cb63ef3a87250cbea67731e00b6b0039fd55f54 100644 (file)
@@ -17,19 +17,11 @@ struct script_event_atom_changed
    u64 value;
 };
 
-#if 0
-struct script_event_call
-{
-   i32 function_id;
-};
-
-
 struct script_event_completion_changed
 {
    u32 entity_id;
    u32 completion_flags;
 };
-#endif
 
 typedef struct ent_script_event ent_script_event;
 struct ent_script_event
@@ -39,16 +31,18 @@ struct ent_script_event
       k_escript_event_world_event,
       k_escript_event_allocate,
       k_escript_event_update,
+#if 0
       k_escript_event_world_start,
       k_escript_event_atom_changed,
+#endif
+      k_escript_event_completion_changed
    }
    type;
    void *info;
    
    void *userdata;
-   ent_list *entity_list;
-   world_instance *world;
    const char *script_alias;
+   u32 script_entity_id;
 };
 
 struct ent_script_table_entry
index df786287561f439576951b0c7a32e1423e11c47c..0497c700e254cea01f6f4258803148959ef9e9ec 100644 (file)
@@ -163,11 +163,14 @@ void ent_skateshop_update(void)
 
       if( button_down( k_srbind_mback ) )
       {
-         _skateshop.open = 0;
-         gui_helper_reset( k_gui_helper_mode_clear );
-         skateshop_playermod( 0 );
-         srinput.state = k_input_state_resume;
-         return;
+         if( world_clear_event( k_world_event_shop ) )
+         {
+            _skateshop.open = 0;
+            gui_helper_reset( k_gui_helper_mode_clear );
+            skateshop_playermod( 0 );
+            srinput.state = k_input_state_resume;
+            return;
+         }
       }
 
       /* override camera positioning
@@ -262,9 +265,12 @@ void ent_skateshop_update(void)
 
          if( button_down( k_srbind_maccept ) )
          {
-            gui_helper_reset( k_gui_helper_mode_clear );
-            skateshop_playermod( 0 );
-            _skateshop.open = 0;
+            if( world_clear_event( k_world_event_shop ) )
+            {
+               gui_helper_reset( k_gui_helper_mode_clear );
+               skateshop_playermod( 0 );
+               _skateshop.open = 0;
+            }
          }
       }
       else if( shop->type == k_skateshop_type_server )
@@ -644,10 +650,13 @@ void ent_skateshop_gui( ui_context *ctx )
             }
             else if( shop->type == k_skateshop_type_charshop )
             {
-               _skateshop.open = 0;
-               gui_helper_reset( k_gui_helper_mode_clear );
-               skateshop_playermod( 0 );
-               srinput.state = k_input_state_resume;
+               if( world_clear_event( k_world_event_shop ) )
+               {
+                  _skateshop.open = 0;
+                  gui_helper_reset( k_gui_helper_mode_clear );
+                  skateshop_playermod( 0 );
+                  srinput.state = k_input_state_resume;
+               }
             }
          }
 
index 40aecb430d03b3f1c203adf4c251855c5eba976d..c1c7c3c2590f5fbf8161fc875ca68cd06d9ccdb7 100644 (file)
@@ -72,6 +72,8 @@ enum entity_alias{
    k_ent_npc         = 27,
    k_ent_armature    = 28,
    k_ent_script      = 29, 
+   k_ent_atom        = 30,
+   k_ent_cutscene    = 31,
    k_ent_max
 };
 
@@ -105,7 +107,9 @@ const char *_entity_alias_str[] =
    [k_ent_glider] = "ent_glider",
    [k_ent_npc] = "ent_npc",
    [k_ent_armature] = "mdl_armature",
-   [k_ent_script] = "ent_script"
+   [k_ent_script] = "ent_script",
+   [k_ent_atom] = "ent_atom",
+   [k_ent_cutscene] = "ent_cutscene"
 };
 
 static inline u32 mdl_entity_id_type( u32 entity_id )
@@ -616,6 +620,36 @@ struct ent_script
    u32 flags;
 };
 
+enum ent_atom_flag
+{
+   k_ent_atom_global = 0x1,
+   k_ent_atom_scrap  = 0x2
+};
+
+typedef struct ent_atom ent_atom;
+struct ent_atom
+{
+   union
+   {
+      u32 pstr_alias;
+      i32 scrap_value;
+   };
+
+   u32 flags;
+};
+
+enum ent_cutscene_flag
+{
+   k_ent_cutscene_freeze_player = 0x1,
+};
+
+typedef struct ent_cutscene ent_cutscene;
+struct ent_cutscene
+{
+   u32 pstr_path,
+       flags;
+};
+
 enum ent_objective_filter{
    k_ent_objective_filter_none            = 0x00000000,
    k_ent_objective_filter_trick_shuvit    = 0x00000001,
@@ -724,6 +758,10 @@ struct ent_region
    u32 deleted01[2];
 };
 
+enum ent_glider_flag
+{
+   k_ent_glider_flag_locked = 0x1
+};
 struct ent_glider 
 {
    mdl_transform transform;
index 67e1db742a4323cbec8d941e204e220b21bd16bd..524af944832564f0d9a26570df08938efb23774b 100644 (file)
@@ -11,6 +11,7 @@
 #include "control_overlay.h"
 #include "network.h"
 #include "shaders/model_menu.h"
+#include "ent_atom.h"
 
 struct global_menu menu = { .skip_starter = 0, .prof_row = -1 };
 
@@ -387,7 +388,7 @@ void menu_update_world_list(void)
    if( world_map.superworld_list_selected == k_superworld_infinite ) world_map.selected_superworld_locked = 1;
    if( world_map.superworld_list_selected == k_superworld_venus_moon )
    {
-      world_map.selected_superworld_locked = !_skaterift_atom_status( "unlock_venus" );
+      world_map.selected_superworld_locked = !_atom_get( k_atom_list_global, "unlock_venus" );
    }
 
    if( world_map.selected_superworld_locked )
@@ -428,11 +429,11 @@ void menu_update_world_list(void)
          addon_reg *reg = addon_details( addon_id );
          bool unlocked = 1;
          if( reg->flags & ADDON_REG_MTZERO )
-            unlocked = _skaterift_atom_status( "unlock_mtzero" )?1:0;
+            unlocked = _atom_get( k_atom_list_global, "unlock_mtzero" )?1:0;
          if( reg->flags & ADDON_REG_CITY )
-            unlocked = _skaterift_atom_status( "unlock_city" )?1:0;
+            unlocked = _atom_get( k_atom_list_global, "unlock_city" )?1:0;
          if( reg->flags & ADDON_REG_VALLEY )
-            unlocked = _skaterift_atom_status( "unlock_valley" )?1:0;
+            unlocked = _atom_get( k_atom_list_global, "unlock_valley" )?1:0;
 
          menu.world_list_entries[ menu.world_list_display_count ] = unlocked? addon_id: 0;
 
index 8aacd47b1704a6434116088fa1c61fc034ce96f7..991dfa9655cf10b796e54f9dfd0ea92b6939a226 100644 (file)
@@ -49,6 +49,7 @@ void _cutscene_unload(void)
    for( u32 i=0; i<_cutscene.unique_refs; i ++ )
       mdl_sync_std_unload( &_cutscene.refs[i].mdl );
 
+   _cutscene.unique_refs = 0;
    _cutscene.active_camera = NULL;
    _cutscene.strip = 0;
    _cutscene.time = 0.0f;
@@ -283,12 +284,12 @@ static void cutscene_load_thread( vg_async_task *task )
    vg_async_call( &vg.main_tasks, sync_cutscene_loaded, NULL );
 }
 
-void _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity )
+bool _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity )
 {
    if( _cutscene.state != k_cutscene_state_none )
    {
       vg_error( "Tried to play cutscene '%s' while already playing one.\n", path );
-      return;
+      return 0;
    }
 
    _cutscene.raiser_entity = raiser_entity;
@@ -307,6 +308,7 @@ void _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_e
    struct cutscene_load_info *info = (void *)task->data;
    strcpy( info->path, path );
    vg_async_task_dispatch( task, cutscene_load_thread );
+   return 1;
 }
 
 /*
@@ -460,6 +462,20 @@ ent_camera *_cutscene_active_camera(void)
 
 void cutscene_update( f32 delta )
 {
+   if( _cutscene.state == k_cutscene_state_unloading )
+   {
+      if( !vg_audio_flagged_stopped( AUDIO_FLAG_CUTSCENE ) )
+         return;
+
+      vg_allocator_free( _cutscene.arena );
+      _cutscene.arena = NULL;
+      _cutscene.state = k_cutscene_state_none;
+      _cutscene.marker_this_frame = NULL;
+      _cutscene.subtitle = NULL;
+      _cutscene.raiser_entity = 0;
+      return;
+   }
+
    if( _cutscene.state == k_cutscene_state_ready )
    {
       _cutscene.player_binding = _cutscene_get_first_model_instance( "models/ch_none" );
@@ -489,20 +505,7 @@ void cutscene_update( f32 delta )
          }
       }
       vg_audio_unlock();
-   }
-
-   if( _cutscene.state == k_cutscene_state_unloading )
-   {
-      if( !vg_audio_flagged_stopped( AUDIO_FLAG_CUTSCENE ) )
-         return;
-
-      vg_allocator_free( _cutscene.arena );
-      _cutscene.arena = NULL;
-      _cutscene.state = k_cutscene_state_none;
-      _cutscene.marker_this_frame = NULL;
-      _cutscene.subtitle = NULL;
-      _cutscene.raiser_entity = 0;
-      return;
+      _world_raise_event( _cutscene.raiser_entity, "start" );
    }
 
    if( _cutscene.state != k_cutscene_state_playing )
index 0b157b62e206f5ea6fc292102422bf2e857fcee2..fd2ef6d43587c3d30bb1861b11c81d079750b5a2 100644 (file)
@@ -217,7 +217,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_load_and_play( const char *path, bool freeze_player, u32 raiser_entity );
+bool _cutscene_load_and_play( const char *path, bool freeze_player, u32 raiser_entity );
 void _cutscene_unload(void);
 void cutscene_update( f32 delta );
 ent_camera *_cutscene_active_camera(void);
index 5ae6efd590ec3b7d5ba4ae8df0ec2aac4e3e7270..357f0cb3ed81bc8008ac711efb4393367e071a3d 100644 (file)
@@ -107,10 +107,9 @@ static void skaterift_populate_main_savedata( savedata_file *file )
    }
    vg_msg_end_frame( &sav );
 
-   /* script / story information */
-   vg_msg_frame( &sav, "story" );
+   vg_msg_frame( &sav, "atoms" );
    {
-      _skaterift_script_write_savedata( &sav );
+      serialize_atoms( k_atom_list_global, &sav );
    }
    vg_msg_end_frame( &sav );
 
@@ -138,8 +137,13 @@ static void skaterift_populate_world_savedata( savedata_file *file )
 
    vg_msg_frame( &sav, "player" );
    {
-      vg_msg_wkvnum( &sav, "position", k_vg_msg_float|k_vg_msg_32b, 3, 
-                     localplayer.rb.co );
+      vg_msg_wkvnum( &sav, "position", k_vg_msg_float|k_vg_msg_32b, 3, localplayer.rb.co );
+   }
+   vg_msg_end_frame( &sav );
+
+   vg_msg_frame( &sav, "atoms" );
+   {
+      serialize_atoms( k_atom_list_world, &sav );
    }
    vg_msg_end_frame( &sav );
 
@@ -165,10 +169,12 @@ void skaterift_write_all_savedata( bool async )
    }
    else
       group = alloca( save_data_size );
-   group->file_count = 2;
+   group->file_count = 1;
 
    skaterift_populate_main_savedata( &group->files[0] );
-   skaterift_populate_world_savedata( &group->files[1] );
+
+   if( (_world.loader_state == k_world_loader_done) || (_world.loader_state == k_world_loader_saving_current) )
+      skaterift_populate_world_savedata( &group->files[ group->file_count ++ ] );
 
    if( async )
       vg_async_task_dispatch( task, savedata_group_write_task );
@@ -258,9 +264,16 @@ void skaterift_load_mainsave(void)
 
    kvsav.cur = orig;
 
-   if( vg_msg_seekframe( &kvsav, "story" ) )
+   if( vg_msg_seekframe( &kvsav, "atoms" ) )
    {
-      _skaterift_script_load_savedata( &kvsav );
+      vg_msg_cmd cmd;
+      while( vg_msg_next( &kvsav, &cmd ) )
+      {
+         if( cmd.code == k_vg_msg_endframe ) break;
+         i32 value = 0;
+         vg_msg_cast( cmd.value, cmd.code, &value, k_vg_msg_i32 );
+         _atom_set( k_atom_list_global, cmd.key, value );
+      }
    }
    else
    {
diff --git a/src/scripts/board_maker.c b/src/scripts/board_maker.c
new file mode 100644 (file)
index 0000000..03dbf3e
--- /dev/null
@@ -0,0 +1,40 @@
+static bool _skaterift_script_board_maker( ent_script_event *event )
+{
+   if( event->type == k_escript_event_world_event )
+   {
+      struct script_event_world_io *inf = event->info;
+      world_instance *world = &_world.main;
+      if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "open" ) ) 
+      {
+         // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you)
+         if( inf->event->flags & k_ent_event_data_const_entity_id )
+         {
+            u32 list_id = inf->event->data.const_entity_id;
+            if( mdl_entity_id_type( list_id ) != k_ent_list )
+            {
+               vg_error( "board maker called with not a list\n" );
+               return 0;
+            }
+            ent_list *list = af_arritm( &world->ent_list, mdl_entity_id_id(list_id) );
+
+            if( world_set_event( k_world_event_board_maker ) )
+            {
+               struct ent_list_iter iter;
+               _ent_list_iter_start( &iter, list, k_ent_marker );
+               while( _ent_list_iter( &iter ) )
+               {
+                  ent_marker *marker = af_arritm( &world->ent_marker, iter.index );
+                  const char *alias = af_str( &world->meta.af, marker->pstr_alias );
+
+                  if( !strcmp( alias, "$board_position" ) )
+                     v3_copy( marker->transform.co, _board_maker.origin );
+                  else if( !strcmp( alias, "$camera_position" ) )
+                     v3_copy( marker->transform.co, _board_maker.camera_pos );
+               }
+               _board_maker_open();
+            }
+         }
+      }
+   }
+   return 1;
+}
index 62dc14b7442e517cef87ce9ccf91a89e104332f3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,46 +0,0 @@
-struct script_cutscene
-{
-   const char *path;
-   bool immobilize;
-};
-
-static bool _skaterift_script_cutscene( ent_script_event *event )
-{
-   if( event->type == k_escript_event_allocate )
-   {
-      struct script_event_allocate *event_info = event->info;
-      struct script_cutscene *cs = vg_linear_alloc( event_info->heap, sizeof(struct script_cutscene) );
-      cs->path = NULL;
-      cs->immobilize = 1;
-      event_info->userdata = cs;
-      return 1;
-   }
-
-   struct script_cutscene *cs = event->userdata;
-
-   if( event->type == k_escript_event_world_event )
-   {
-      struct script_event_world_io *inf = event->info;
-      world_instance *world = &_world.main;
-
-           if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "play" ) )
-      {
-         _cutscene_load_and_play( cs->path, cs->immobilize, inf->event->recieve_entity_id );
-      }
-      else if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "immobilize" ) ) 
-      {
-         // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you)
-         if( inf->event->flags == k_ent_event_data_const_i32 )
-            cs->immobilize = inf->event->data.const_i32;
-         else vg_error( "a300\n" );
-      }
-      else if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "path" ) ) 
-      {
-         if( inf->event->flags == k_ent_event_data_const_string )
-            cs->path = af_str( &world->meta.af, inf->event->data.const_pstr );
-         else vg_error( "a300\n" );
-      }
-   }
-   
-   return 1;
-}
index 9b5bf4736f9b320daec7cdc93ebd8b375f162d04..db0e0c57eed2c97cdd092675b5242d79574a5a0d 100644 (file)
@@ -7,6 +7,7 @@ struct board_maker_unlock_waiter
 
 static bool _skaterift_script_board_maker_unlock( ent_script_event *event )
 {
+#if 0
    if( event->type == k_escript_event_allocate )
    {
       struct script_event_allocate *event_info = event->info;
@@ -36,10 +37,11 @@ static bool _skaterift_script_board_maker_unlock( ent_script_event *event )
          }
       }
    }
-
+#endif
    return 1;
 }
 
+#if 0
 static bool _skaterift_script_board_maker( ent_script_event *event )
 {
    if( on_function_trigger( event, 0 ) )
@@ -63,3 +65,4 @@ static bool _skaterift_script_board_maker( ent_script_event *event )
    }
    return 1;
 }
+#endif
index 740fcf6af43dc610c04874bd8d3cbc668b7cb0d0..0ee86337e66ed81c31ded02643a12ff26caedb06 100644 (file)
 struct script_volcano
 {
-   ent_list *break_list;
    bool docks_wait;
    f32 stopped_timer;
 };
 
-static bool _skaterift_script_tutorial_island( ent_script_event *event )
+static bool _skaterift_script_volc( ent_script_event *event )
 {
-#if 0
-   if( on_advancement(event) )
-   {
-      ent_list *region0_challenges = _ent_list_get_aliased( "region0" );
-      bool region0_is_target = 0;
-
-      u64 progress = _skaterift_atom_status( "story" );
-      if( progress == _skaterift_atom_enum_index( "story", "volc" ) )
-      {
-         if( _ent_list_check_completed( region0_challenges ) )
-            region0_is_target = 0;
-         else
-            region0_is_target = 1;
-      }
-
-      _ent_list_set_as_targets( region0_challenges, region0_is_target );
-   }
-
    if( event->type == k_escript_event_allocate )
    {
       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;
+      struct script_volcano *v = vg_linear_alloc( event_info->heap, sizeof(struct script_volcano) );
+      v->docks_wait = 0;
+      v->stopped_timer = 0.0f;
+      event_info->userdata = v;
       return 1;
    }
+   struct script_volcano *v = event->userdata;
 
-   struct script_volcano *script_volcano = event->userdata;
-
-   if( on_completion_changed(event) )
+   if( event->type == k_escript_event_world_event )
    {
-      u64 progress = _skaterift_atom_status( "story" );
-      if( progress == _skaterift_atom_enum_index( "story", "volc" ) )
-      {
-         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 );
-         _skaterift_atom_set_enum( "story", "volc:tutorial" );
-      }
-      else if( progress == _skaterift_atom_enum_index( "story", "volc:tutorial" ) )
-      {
-         if( _ent_list_check_completed( _ent_list_get_aliased( "region0" ) ) )
-         {
-            _skaterift_atom_set_enum( "story", "volc:leaving" );
-            vg_low( "waiting for stopped...\n" );
-            script_volcano->docks_wait = 1;
-         }
-      }
-      else if( progress == _skaterift_atom_enum_index( "story", "volc:leaving" ) )
+      struct script_event_world_io *inf = event->info;
+      world_instance *world = &_world.main;
+
+           if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "unlock_docks" ) )
       {
-         _ent_list_set_visible( _ent_list_get_aliased( "docks:locked" ), 0 );
+         v->docks_wait = 1;
       }
    }
 
    /* waiting for player to stop to blow up the docks */
    if( event->type == k_escript_event_update )
    {
-      if( script_volcano->docks_wait )
+      if( v->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 )
+               v->stopped_timer += vg.time_frame_delta;
+               if( v->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" );
+                  v->docks_wait = 0;
+                  _atom_set( k_atom_list_world, "unlock_docks", 1 );
+                  _atom_notify( k_atom_list_world, "unlock_docks" );
                }
             }
             else
-               script_volcano->stopped_timer = 0.0f;
+               v->stopped_timer = 0.0f;
          }
       }
    }
 
-   if( on_cutscene_marker( event, "$break" ) )
-      _explode_template_boom( script_volcano->break_list );
-#endif
-
-   return 1;
-}
-
-static bool _skaterift_script_ch1s3( ent_script_event *event )
-{
-#if 0
-   if( on_function_trigger( event, 1 ) )
-   {
-      if( on_atom_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 );
-         _ent_npc_set_in_cutscene( k_npc_jc, 1 );
-      }
-   }
-
-   if( on_function_trigger( event, 2 ) )
-   {
-      if( on_atom_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 );
-         _ent_npc_set_in_cutscene( k_npc_jc, 1 );
-      }
-   }
-
-   u64 progress;
-   if( on_atom_changed( event, "story", &progress ) )
-   {
-      bool visible = progress == _skaterift_atom_enum_index( "story", "volc:tutorial" );
-      _ent_list_set_visible( event->entity_list, visible );
-   }
-
-   u64 viewed;
-   if( on_atom_changed( event, "ch1s3_view", &viewed ) )
-      _ent_list_set_visible( event->entity_list, !viewed );
-#endif
-   return 1;
-}
-
-static bool _skaterift_script_ch1s4( ent_script_event *event )
-{
-#if 0
-   if( on_function_trigger( event, 0 ) )
-   {
-      if( on_atom_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_atom_changed( event, "ch1s4_view", &status ) )
-      _ent_list_set_visible( event->entity_list, status == 0 );
-#endif
-
-   return 1;
-}
-
-static bool _skaterift_script_ch1s5( ent_script_event *event )
-{
-#if 0
-   if( on_function_trigger( event, 0 ) )
-   {
-      if( on_atom_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 );
-      }
-   }
-#endif
-   return 1;
-}
-
-static bool _skaterift_script_ch1s6a( ent_script_event *event )
-{
-#if 0
-   u64 progress;
-   if( on_atom_changed( event, "story", &progress ) )
-   {
-      bool visible = progress == _skaterift_atom_enum_index( "story", "volc:leaving" );
-      _ent_list_set_visible( event->entity_list, visible );
-   }
-
-   if( on_function_trigger( event, 0 ) )
-   {
-      _skaterift_atom_set_enum( "story", "mz" );
-      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 },
-      };
-      _cutscene_load_and_play( "metascenes/ch1s6a.ms", EN, 1 );
-   }
-
-   if( on_cutscene_marker( event, "$ch1s6a_end" ) )
-      skaterift_load_world_command( 1, (const char *[]){ "sr002-local-dev_hub" } );
-#endif
-      
    return 1;
 }
index fea4120d2e291c9e8816520fe178084fa7665a8e..40568cf2b45b9947b7363cc1ea0361227bf4a9ae 100644 (file)
@@ -59,6 +59,7 @@
 #include "ent_route.h"
 #include "ent_npc.h"
 #include "ent_list.h"
+#include "ent_atom.h"
 
 struct skaterift_globals skaterift = 
 { 
@@ -105,7 +106,6 @@ static void game_load_co( vg_coroutine *co )
 
       vg_loader_step( network_init, network_end );
 
-      _skaterift_script_init();
       vg_loader_set_user_information( "Initializing subsystems" );
       vg_console_reg_cmd( "load_world", skaterift_load_world_command, NULL );
       vg_console_reg_var( "immobile", &localplayer.immobile, k_var_dtype_i32, 0 );
@@ -131,6 +131,8 @@ static void game_load_co( vg_coroutine *co )
       vg_loader_step( skaterift_load_player_content, NULL );
       vg_loader_step( _replay2_init, NULL );
       vg_loader_step( _ent_npc_init, NULL );
+      vg_loader_step( _ent_atom_init, NULL );
+      vg_loader_step( _ent_challenge_init, NULL );
 
       vg_loader_set_user_information( "Compiling shaders" );
       vg_bake_shaders();
@@ -653,6 +655,8 @@ void vg_framebuffer_resize( int w, int h )
 #include "user_profile.c"
 #include "ent_npc.c"
 #include "ent_list.c"
+#include "ent_cutscene.c"
+#include "ent_atom.c"
 
 //TODO
 //#include "vg/submodules/hashmap.c/hashmap.c"
index a585bda0ab613457b1c6f507a727ae2121654925..4b22e1cafe4ba3d6fb23fed3a52f73d0580e19d7 100644 (file)
@@ -1,8 +1,4 @@
-#define KCOL_JOHN KNRM
-#define KCOL_MIKE KBLU
-#define KCOL_PRES KYEL
-#define KCOL_FBI  KGRN
-#define KCOL_JESUS KMAG
+#if 0
 
 #include "ent_script.h"
 
@@ -57,6 +53,7 @@ struct script_save_atom
 _skaterift_script_savedata[] = 
 {
    { "story", k_atom_type_enum, _script_linear_story },
+   { "unlock_docks_view" },
 
    { "unlock_valley_view" },
    { "unlock_mtzero_view" },
@@ -67,6 +64,7 @@ _skaterift_script_savedata[] =
 
    { "ch1s3_view" },
    { "ch1s3b_view" },
+   { "ch1s4_view" },
    { "ch1s5_view" },
 
 #if 0
@@ -176,6 +174,7 @@ void _skaterift_atom_set( const char *atom_alias, u64 value )
 
    atom->status = value;
 
+#if 0
    struct script_event_atom_changed info;
    info.alias = atom_alias;
    info.value = value;
@@ -183,6 +182,7 @@ void _skaterift_atom_set( const char *atom_alias, u64 value )
    event.type = k_escript_event_atom_changed;
    event.info = &info;
    ent_script_propogate_event( &_world.main, &event );
+#endif
 }
 
 void _skaterift_atom_set_enum( const char *atom_alias, const char *value )
@@ -284,20 +284,6 @@ bool on_atom_once( ent_script_event *event, const char *atom_alias )
 
    return 0;
 }
-
-bool on_advancement( ent_script_event *event )
-{
-   if( event->type == k_escript_event_completion_changed )
-      return 1; 
-   if( event->type == k_escript_event_world_start) 
-      return 1;
-
-   u64 _0;
-   if( on_atom_changed( event, "story", &_0 ) )
-      return 1;
-
-   return 0;
-}
 #endif
 
 #include "scripts/generic.c"
@@ -313,78 +299,6 @@ bool on_advancement( ent_script_event *event )
 #include "scripts/cutscene.c"
 #include "scripts/explode.c"
 
-static bool _skaterift_atom_script( ent_script_event *event )
-{
-   if( event->type == k_escript_event_world_event )
-   {
-      struct script_event_world_io *inf = event->info;
-      world_instance *world = &_world.main;
-
-           if( AF_STR_EQ( &world->meta.af, inf->event->pstr_recieve_event, "pass_once" ) )
-      {
-         // TODO: Make this dynamiclly fetched from a handler for the entity itself. (or not, fuck you)
-         if( inf->event->flags & k_ent_event_data_const_string )
-         {
-            const char *alias = af_str( &world->meta.af, inf->event->data.const_pstr );
-            if( _skaterift_atom_status( alias ) != 1 )
-            {
-               _skaterift_atom_set( alias, 1 );
-               _world_raise_event( inf->event->recieve_entity_id, "pass" );
-            }
-            else 
-               _world_raise_event( inf->event->recieve_entity_id, "fail" );
-         }
-      }
-   }
-   
-   return 1;
-}
-
-/* --------------------------------------------------------------------------------------------------------------------
- *   function aliasing
- */
-
-struct ent_script_table_entry _ent_script_table[] =
-{
-   { "cutscene", _skaterift_script_cutscene },
-   { "explode", _skaterift_script_explode },
-   { "atom", _skaterift_atom_script },
-#if 0
-   { "hub", _skaterift_script_hub },
-   { "board_maker_unlock", _skaterift_script_board_maker_unlock },
-   { "board_maker", _skaterift_script_board_maker },
-
-   //{ "intro", _skaterift_script_intro },
-
-   { "tutorial_island", _skaterift_script_tutorial_island },
-   { "ch1s3", _skaterift_script_ch1s3 },
-   { "ch1s4", _skaterift_script_ch1s4 },
-   { "ch1s5", _skaterift_script_ch1s5 },
-   { "ch1s6a", _skaterift_script_ch1s6a },
-
-   { "mtzero", _skaterift_script_mtzero },
-   { "mtzero_after", _skaterift_script_mtzero_after },
-   { "ch2s2", _skaterift_script_ch2s2 },
-   { "ch2s3", _skaterift_script_ch2s3 },
-   { "battery_jump", _skaterift_script_battery_jump },
-   { "ch2s5_before", _skaterift_script_ch2s5_before },
-   { "ch2s5_after", _skaterift_script_ch2s5_after },
-   { "ch2s6", _skaterift_script_ch2s6 },
-   { "ch2e1", _skaterift_script_ch2e1 },
-
-   { "city", _skaterift_script_city },
-   { "ch3s2", _skaterift_script_ch3s2 },
-   { "ch3s3", _skaterift_script_ch3s3 },
-
-   { "valley", _skaterift_script_valley },
-   { "ch4s2", _skaterift_script_ch4s2 },
-   { "ch4s1", _skaterift_script_ch4s1 },
-#endif
-
-   { NULL }
-};
-
-
 /* console eventts
  * ------------------------------------------------------------------------------------------------------------- */
 
@@ -396,12 +310,14 @@ static int _skaterift_script_ccmd( int argc, const char *argv[] )
       return 0;
    }
 
+   bool all = 0;
+   if( !strcmp( argv[1], "all" ) ) 
+      all = 1;
+
+   world_instance *world = &_world.main;
+
    if( !strcmp( argv[0], "atom" ) ) 
    {
-      bool all = 0;
-      if( !strcmp( argv[1], "all" ) ) 
-         all = 1;
-
       for( u32 i=0; i<VG_ARRAY_LEN( _skaterift_script_savedata ); i ++ )
       {
          struct script_save_atom *atom = &_skaterift_script_savedata[i];
@@ -428,6 +344,73 @@ static int _skaterift_script_ccmd( int argc, const char *argv[] )
 
       return 1;
    }
+   else if( !strcmp( argv[0], "challenge" ) )
+   {
+      u32 index = 0;
+      for( u32 i=0; i<af_arrcount( &world->ent_challenge ); i ++ )
+      {
+         ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+         const char *alias = af_str( &world->meta.af, challenge->pstr_alias );
+         
+         if( all || (atoi( argv[1] ) == index) )
+         {
+            if( argc==3 )
+            {
+               challenge->status = atoi( argv[2] );
+               ent_region_re_eval( world );
+               
+               struct ent_script_event event;
+               struct script_event_completion_changed inf = {
+                  .entity_id = mdl_entity_id( k_ent_challenge, i ),
+                  .completion_flags = 0
+               };
+               event.type = k_escript_event_completion_changed;
+               event.info = &inf;
+               ent_script_propogate_event( world, &event );
+            }
+            else
+               vg_info( "[challenge %u '%s'] %u\n", index, alias, challenge->status );
+         }
+
+         index ++;
+      }
+      for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+      {
+         ent_route *route = af_arritm( &world->ent_route, i );
+         const char *alias = af_str( &world->meta.af, route->pstr_name );
+
+         if( all || (atoi( argv[1] ) == index) )
+         {
+            if( argc==3 )
+            {
+               route->flags &= ~((u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver));
+
+               if( !strcmp( argv[2], "silver" ) )
+                  route->flags |= (u32)(k_ent_route_flag_achieve_silver);
+
+               if( !strcmp( argv[2], "gold" ) )
+                  route->flags |= (u32)(k_ent_route_flag_achieve_gold|k_ent_route_flag_achieve_silver);
+               ent_region_re_eval( world );
+
+               struct ent_script_event event;
+               struct script_event_completion_changed inf = {
+                  .entity_id = mdl_entity_id( k_ent_route, i ),
+                  .completion_flags = route->flags
+               };
+               event.type = k_escript_event_completion_changed;
+               event.info = &inf;
+               ent_script_propogate_event( world, &event );
+            }
+            else
+               vg_info( "[route %u '%s'] %s%s\n", index, alias,
+                           (route->flags & k_ent_route_flag_achieve_silver? "SILVER": "_____"),
+                           (route->flags & k_ent_route_flag_achieve_gold?   "_GOLD": "_____" ) );
+         }
+
+         index ++;
+      }
+      return 1;
+   }
    else if( !strcmp( argv[0], "trigger" ) )
    {
       if( !strcmp( argv[1], "start" ) )
@@ -451,11 +434,13 @@ static int _skaterift_script_ccmd( int argc, const char *argv[] )
 static void _skaterift_script_ccmd_poll( int argc, const char *argv[] )
 {
    const char *term = argv[argc-1];
+   world_instance *world = &_world.main;
 
    if( argc == 1 )
    {
       console_suggest_score_text( "atom", term, 0 );
       console_suggest_score_text( "trigger", term, 0 );
+      console_suggest_score_text( "challenge", term, 0 );
    }
    else if( argc == 2 )
    {
@@ -472,6 +457,22 @@ static void _skaterift_script_ccmd_poll( int argc, const char *argv[] )
       {
          console_suggest_score_text( "start", term, 0 );
       }
+      else if( !strcmp( argv[0], "challenge" ) )
+      {
+         // CANT DO THIS WHILE WE DONT HAVE STRING ESCAPING IN THE CONSOLE
+#if 0
+         for( u32 i=0; i<af_arrcount( &world->ent_challenge ); i ++ )
+         {
+            ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+            console_suggest_score_text( af_str( &world->meta.af, challenge->pstr_alias ), term, 0 );
+         }
+         for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+         {
+            ent_route *route = af_arritm( &world->ent_route, i );
+            console_suggest_score_text( af_str( &world->meta.af, route->pstr_name ), term, 0 );
+         }
+#endif
+      }
    }
    else if( argc == 3 )
    {
@@ -491,6 +492,23 @@ static void _skaterift_script_ccmd_poll( int argc, const char *argv[] )
             }
          }
       }
+      else if( !strcmp( argv[0], "challenge" ) )
+      {
+         // CANT DO THIS WHILE WE DONT HAVE STRING ESCAPING IN THE CONSOLE
+#if 0
+         for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+         {
+            ent_route *route = af_arritm( &world->ent_route, i );
+            const char *alias = af_str( &world->meta.af, route->pstr_name );
+            if( !strcmp( argv[1], alias ) )
+            {
+               console_suggest_score_text( "silver", term, 0 );
+               console_suggest_score_text( "gold", term, 0 );
+               break;
+            }
+         }
+#endif
+      }
    }
 }
 
@@ -498,3 +516,6 @@ void _skaterift_script_init(void)
 {
    vg_console_reg_cmd( "script", _skaterift_script_ccmd, _skaterift_script_ccmd_poll );
 }
+
+
+#endif
index 2cb58f9756b3dff09a5f8b08f659459307c97026..e4332d140b25ce0df81f8ec6ce540edb029a3024 100644 (file)
@@ -1,4 +1,5 @@
 #pragma once
+#if 0
 #include "ent_script.h"
 #define ATOM_MAX 0xfffffffffffffffflu
 
@@ -17,3 +18,4 @@ bool on_cutscene_marker( ent_script_event *event, const char *marker );
 bool on_function_trigger( ent_script_event *event, i32 function_id );
 bool on_atom_once( ent_script_event *event, const char *atom_alias );
 bool on_advancement( ent_script_event *event );
+#endif
index d1d9017b9eda4654f8a270ad4d35910545f756d9..7a7228b505406c3486abb00cb20e7ecd5902f4a4 100644 (file)
@@ -58,7 +58,6 @@ static i32   k_debug_light_indices   = 0,
 struct world_instance 
 {
    bool complete;
-
    addon_id addon_id;
    void *heap;
 
@@ -180,7 +179,9 @@ struct world_instance
                  ent_npc,
                  file_entity_ref,
                  ent_event,
-                 ent_script;
+                 ent_script, 
+                 ent_atom,
+                 ent_cutscene;
    
    GLuint *nonlocal_gates_cubemaps;
    u32 nonlocal_gate_count;
index 927e29cf277fae5788832612670257e545990b64..a37a6c6659dfd6aa3cf764312e3b9f5018c1f753 100644 (file)
@@ -14,6 +14,8 @@
 #include "ent_glider.h"
 #include "ent_region.h"
 #include "ent_camera.h"
+#include "ent_atom.h"
+#include "ent_cutscene.h"
 #include "input.h"
 #include "player_walk.h"
 
@@ -27,6 +29,8 @@ bh_system bh_system_entity_list =
    .cast_ray = NULL
 };
 
+static void _event_trigger( ent_event *event );
+
 void world_gen_entities_init( world_instance *world )
 {
    /* lights */
@@ -596,6 +600,13 @@ void world_entity_start( world_instance *world, vg_msg *sav )
 {
    vg_info( "Start instance %p\n", world );
 
+   for( u32 i=0; i<af_arrcount( &world->ent_event ); i ++ )
+   {
+      ent_event *event = af_arritm( &world->ent_event, i );
+      if( AF_STR_EQ( &world->meta.af, event->pstr_source_event, "init" ) )
+         _event_trigger( event );
+   }
+
    world->probabilities[ k_probability_curve_constant ] = 1.0f;
    for( u32 i=0; i<af_arrcount(&world->ent_audio); i++ )
    {
@@ -647,8 +658,44 @@ void world_entity_start( world_instance *world, vg_msg *sav )
       }
    }
 
+   vg_msg_cursor orig = sav->cur;
+   if( vg_msg_seekframe( sav, "atoms" ) )
+   {
+      vg_msg_cmd cmd;
+      while( vg_msg_next( sav, &cmd ) )
+      {
+         if( cmd.code == k_vg_msg_endframe ) break;
+         i32 value = 0;
+         vg_msg_cast( cmd.value, cmd.code, &value, k_vg_msg_i32 );
+         _atom_set( k_atom_list_world, cmd.key, value );
+      }
+   }
+
    ent_region_re_eval( world );
-   ent_script_start( world );
+
+   /* true/false initializers 
+    * ----------------------------------------------------------------------------------- */
+   for( u32 i=0; i<af_arrcount( &world->ent_atom ); i ++ )
+   {
+      ent_atom *atom = af_arritm( &world->ent_atom, i );
+      i32 value;
+      if( atom->flags & k_ent_atom_scrap )
+         value = atom->scrap_value;
+      else
+      {
+         enum e_atom_list list = (atom->flags & k_ent_atom_global)? k_atom_list_global: k_atom_list_world;
+         value = _atom_get( list, af_str( &world->meta.af, atom->pstr_alias ) );
+      }
+      _world_raise_event( mdl_entity_id( k_ent_atom, i ), "changed" );
+      _world_raise_event( mdl_entity_id( k_ent_atom, i ), value? "true": "false" );
+   }
+   for( u32 i=0; i<af_arrcount(&world->ent_challenge); i++ )
+   {
+      ent_challenge *challenge = af_arritm( &world->ent_challenge, i );
+      _world_raise_event( mdl_entity_id( k_ent_challenge, i ), challenge->status? "true": "false" );
+   }
+
+   sav->cur = orig;
 }
 
 void world_entity_serialize( world_instance *world, vg_msg *sav )
@@ -692,7 +739,18 @@ void _world_raise_event( u32 caller, const char *event_alias )
    world_instance *world = &_world.main;
    u32 event_alias_hash = vg_strdjb2( event_alias );
 
-   if( mdl_entity_id_type( caller ) != k_ent_volume )
+   bool log = 1;
+
+   if( mdl_entity_id_type( caller ) == k_ent_volume )
+   {
+      if( !strcmp( event_alias, "stay" ) ||
+          !strcmp( event_alias, "particle") )
+      {
+         log = 0;
+      }
+   }
+
+   if( log )
       vg_low( "%x raises [src_event '%s']\n", caller, event_alias );
 
    for( u32 i=0; i<af_arrcount( &world->ent_event ); i ++ )
@@ -702,75 +760,83 @@ void _world_raise_event( u32 caller, const char *event_alias )
          continue;
 
       if( af_str_eq( &world->meta.af, event->pstr_source_event, event_alias, event_alias_hash ) )
-      {
-         u32 type = mdl_entity_id_type( event->recieve_entity_id ),
-             index = mdl_entity_id_id( event->recieve_entity_id );
+         _event_trigger( event );
+   }
+}
 
-         entity_event_result (*table[])( ent_event *event ) = 
-         {
-            [k_ent_audio]     = ent_audio_event,
-            [k_ent_skateshop] = ent_skateshop_event,
-            [k_ent_objective] = ent_objective_event,
-            [k_ent_ccmd]      = ent_ccmd_event,
-            [k_ent_gate]      = ent_gate_event,
-            [k_ent_challenge] = ent_challenge_event,
-            [k_ent_route]     = ent_route_event,
-            [k_ent_region]    = ent_region_event,
-            [k_ent_glider]    = ent_glider_event,
-            [k_ent_water]     = ent_water_event,
-            [k_ent_npc]       = ent_npc_event,
-            [k_ent_script]    = _ent_script_world_event,
-         };
-
-         if( type >= VG_ARRAY_LEN(table) )
-         {
-            vg_error( "call to entity type: %u is out of range\n", type );
-            return;
-         }
+static void _event_trigger( ent_event *event )
+{
+   world_instance *world = &_world.main;
+   u32 type = mdl_entity_id_type( event->recieve_entity_id ),
+       index = mdl_entity_id_id( event->recieve_entity_id );
+
+   entity_event_result (*table[])( ent_event *event ) = 
+   {
+      [k_ent_audio]     = ent_audio_event,
+      [k_ent_skateshop] = ent_skateshop_event,
+      [k_ent_objective] = ent_objective_event,
+      [k_ent_ccmd]      = ent_ccmd_event,
+      [k_ent_gate]      = ent_gate_event,
+      [k_ent_challenge] = ent_challenge_event,
+      [k_ent_route]     = ent_route_event,
+      [k_ent_region]    = ent_region_event,
+      [k_ent_glider]    = ent_glider_event,
+      [k_ent_water]     = ent_water_event,
+      [k_ent_npc]       = ent_npc_event,
+      [k_ent_script]    = _ent_script_world_event,
+      [k_ent_list]      = _ent_list_world_event,
+      [k_ent_cutscene]  = _ent_cutscene_event,
+      [k_ent_atom]      = _ent_atom_event,
+   };
 
-         if( !table[type] )
-         {
-            vg_error( "Entity type %u does not have a call handler, but was called anyway\n", type );
-            return;
-         }
+   if( type >= VG_ARRAY_LEN(table) )
+   {
+      vg_error( "call to entity type: %u is out of range\n", type );
+      return;
+   }
 
-         if( event->flags & k_ent_event_data_const_string )
-         {
-            vg_info( "[event '%s'] %x -> %x ('%s') with '%s'\n", 
-                     af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
-                     event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
-                     af_str( &world->meta.af, event->data.const_pstr ) );
-         }
-         else if( event->flags & k_ent_event_data_const_i32 )
-         {
-            vg_info( "[event '%s'] %x -> %x ('%s') with %d\n", 
-                     af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
-                     event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
-                     event->data.const_i32 );
-         }
-         else if( event->flags & k_ent_event_data_const_f32 )
-         {
-            vg_info( "[event '%s'] %x -> %x ('%s') with %ff\n", 
-                     af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
-                     event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
-                     event->data.const_f32 );
-         }
-         else if( event->flags & k_ent_event_data_const_f32 )
-         {
-            vg_info( "[event '%s'] %x -> %x ('%s') void\n", 
-                     af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
-                     event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ));
-         }
+   if( !table[type] )
+   {
+      vg_error( "Entity type %u does not have a call handler, but was called anyway\n", type );
+      return;
+   }
+
+   if( event->flags & k_ent_event_data_const_string )
+   {
+      vg_info( "[event '%s'] %x -> %x ('%s') with '%s'\n", 
+               af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
+               event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
+               af_str( &world->meta.af, event->data.const_pstr ) );
+   }
+   else if( event->flags & k_ent_event_data_const_i32 )
+   {
+      vg_info( "[event '%s'] %x -> %x ('%s') with %d\n", 
+               af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
+               event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
+               event->data.const_i32 );
+   }
+   else if( event->flags & k_ent_event_data_const_f32 )
+   {
+      vg_info( "[event '%s'] %x -> %x ('%s') with %ff\n", 
+               af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
+               event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ), 
+               event->data.const_f32 );
+   }
+   else if( event->flags & k_ent_event_data_const_f32 )
+   {
+      vg_info( "[event '%s'] %x -> %x ('%s') void\n", 
+               af_str( &world->meta.af, event->pstr_source_event ), event->source_entity_id,
+               event->recieve_entity_id, af_str( &world->meta.af, event->pstr_recieve_event ));
+   }
 
-         enum entity_event_result res = table[type]( event );
+   enum entity_event_result res = table[type]( event );
 
-         if( res == k_entity_event_result_unhandled )
-         {
-            vg_warn( "Call to entity %x#%x was unhandled (no event '%s').\n", type, index, 
-                     af_str( &world->meta.af, event->pstr_recieve_event ) );
-         }
-         else if( res == k_entity_event_result_invalid )
-            vg_warn( "Call to entity %x#%x invalid.\n", type, index );
-      }
+   if( res == k_entity_event_result_unhandled )
+   {
+      vg_warn( "Call to entity %x#%x was unhandled (no event '%s').\n", type, index, 
+               af_str( &world->meta.af, event->pstr_recieve_event ) );
    }
+   else if( res == k_entity_event_result_invalid )
+      vg_warn( "Call to entity %x#%x invalid.\n", type, index );
 }
+
index 9eb7434b0f8cc2ace5b07c2aede3b35274049d0f..a8aa6e172cd6903c92bdcc68afe43809b0c20a23 100644 (file)
@@ -10,6 +10,7 @@
 #include "vg/vg_loader.h"
 #include "vg/vg_io.h"
 #include <string.h>
+#include "ent_atom.h"
 
 /* 
  * load the .mdl file located in path as a world instance
@@ -115,6 +116,8 @@ static void world_instance_load_mdl( world_instance *world, const char *path, vo
       AF_LOAD_ARRAY_STRUCT( af, &world->ent_script, ent_script, heap );
       AF_LOAD_ARRAY_STRUCT( af, &world->ent_event,     ent_event, heap );
       AF_LOAD_ARRAY_STRUCT( af, &world->ent_npc,       ent_npc, heap );
+      AF_LOAD_ARRAY_STRUCT( af, &world->ent_atom,      ent_atom, heap );
+      AF_LOAD_ARRAY_STRUCT( af, &world->ent_cutscene,  ent_cutscene, heap );
    }
 
    array_file_ptr infos;
@@ -414,6 +417,12 @@ void world_switcher_update(void)
    {
       if( !vg_audio_flagged_stopped( AUDIO_FLAG_WORLD|AUDIO_FLAG_CUTSCENE ) )
          return;
+
+      if( _cutscene.state != k_cutscene_state_none )
+      {
+         cutscene_update( 0.0f );
+         return;
+      }
       
       world_instance_free_graphics_data( &_world.main );
       _world.main.complete = 0;
@@ -430,6 +439,7 @@ void world_switcher_update(void)
       vg_str folder_str;
       vg_strnull( &folder_str, info->path, sizeof(info->path) );
       info->OK = addon_get_content_folder( _world.load_addon, &folder_str );
+      _atom_list_clear( k_atom_list_world );
       vg_async_task_dispatch( task, skaterift_world_load_t1 );
    }
 
@@ -508,10 +518,9 @@ void skaterift_load_world_start( addon_id addon_id, bool preview )
    }
    else
    {
-      if( _cutscene.state != k_cutscene_state_none )
-      {
+      if( (_cutscene.state != k_cutscene_state_none) && (_cutscene.state != k_cutscene_state_unloading) )
          _cutscene_unload();
-      }
+
       vg_audio_fadeout_flagged_audio( AUDIO_FLAG_WORLD, 1.0f );
    }
 
@@ -529,7 +538,7 @@ void _world_loader_set_addon( addon_id addon_id )
    addon_reg *reg = addon_details(addon_id);
    if( reg->flags & ADDON_REG_MTZERO )
    {
-      u64 status = _skaterift_atom_status( "ch2s5_view" );
+      i32 status = _atom_get( k_atom_list_global, "mtzero_part2" );
       
       /* we've seen the cutscene already (1), or about to play it on world load (3).
        * both of those statuses mean we load 'main'. */
index 5bd61c420c2430ef37407a01a86a9b35ce9d8a35..24429e34e87aefd8b943cee03fbd4e534de302f7 100644 (file)
@@ -1055,8 +1055,7 @@ static void render_other_entities( world_instance *world, vg_camera *cam )
    for( u32 j=0; j<glider_count; j ++ )
    {
       ent_glider *glider = af_arritm( &world->ent_glider, glider_list[j] );
-
-      if( !(glider->flags & 0x1) )
+      if( glider->flags & k_ent_glider_flag_locked )
          continue;
 
       m4x3f mdl;
index 2d4ccc4673f95980fa6345fd469e65f904134930..cc784f2315fc2ee51e6eb4a61da22bca2f6641eb 100644 (file)
@@ -122,7 +122,6 @@ static void world_routes_time_lap( u32 route_index )
       if( clean ) route->flags |= k_ent_route_flag_achieve_gold;
       ent_region_re_eval( world );
 
-#if 0
       struct ent_script_event event;
       struct script_event_completion_changed inf = {
          .entity_id = mdl_entity_id( k_ent_route, route_index ),
@@ -131,7 +130,6 @@ static void world_routes_time_lap( u32 route_index )
       event.type = k_escript_event_completion_changed;
       event.info = &inf;
       ent_script_propogate_event( world, &event );
-#endif
 
       /* for steam achievements. */
       if( route->anon.official_track_id != 0xffffffff )
index c6b3dd2fc6b2b269dec94b98a04f89d661a231b0..256c4fb70e0f544da14a6330e92aa29d64f175f0 100644 (file)
@@ -117,6 +117,7 @@ void world_volumes_update( world_instance *world, v3f pos )
              (fabsf(local[1]) <= 1.0f) &&
              (fabsf(local[2]) <= 1.0f) )
          {
+            bool enter = 1;
             if( volume->flags & k_ent_volume_flag_interact )
             {
                if( localplayer.subsystem == k_player_subsystem_walk )
@@ -133,9 +134,14 @@ void world_volumes_update( world_instance *world, v3f pos )
                      }
                   }
                }
+               else enter = 0;
+            }
+
+            if( enter )
+            {
+               _world_raise_event( id, "enter" );
+               _world.active_trigger_volumes[ _world.active_trigger_volume_count ++ ] = index;
             }
-            _world_raise_event( id, "enter" );
-            _world.active_trigger_volumes[ _world.active_trigger_volume_count ++ ] = index;
          }
          else
             vg_line_boxf_transformed( volume->to_world, cube, 0xffcccccc );