logic
authorhgn <hgodden00@gmail.com>
Sun, 12 Mar 2023 07:53:04 +0000 (07:53 +0000)
committerhgn <hgodden00@gmail.com>
Sun, 12 Mar 2023 07:53:04 +0000 (07:53 +0000)
15 files changed:
.gitignore
audio.h
blender_export.py
common.h
maps_src/mp_gridmap.mdl
maps_src/mp_home.mdl
maps_src/mp_mtzero.mdl
model.h
player_skate.c
player_skate.h
skaterift.c
sound_src/skate_hpf.ogg [new file with mode: 0644]
world.h
world_gen.h
world_logic_bricks.h [new file with mode: 0644]

index dd3c3994fdd1b491b9b93a6406795f12eef9b597..a9cf8bd9e890709ee466585f21a042544efd8545 100755 (executable)
@@ -15,3 +15,9 @@ compile_commands.json
 
 sound_src/rtj3_01_down.ogg
 sound_src/song.ogg
+sound_src/rtj3_02_talktome.ogg
+sound_src/rtj3_02_talktome.ogg.reapeaks
+sound_src/song1.ogg
+sound_src/memes.ogg
+sound_src/memes.ogg.reapeaks
+sound_src/delta.ogg
diff --git a/audio.h b/audio.h
index 5caa759e01fdc7b00182f025eb36d03950520e5d..f70edf5bd783f5fdfe3c9c75d998fb6c3ee63d38 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -16,7 +16,7 @@ VG_STATIC int   k_audio_debug_soundscape = 0;
 
 audio_clip audio_board[] =
 {
-   { .path="sound/skate.ogg" },
+   { .path="sound/skate_hpf.ogg" },
    { .path="sound/wheel.ogg" },
    { .path="sound/slide.ogg" },
    { .path="sound/reverb.ogg" },
@@ -101,6 +101,7 @@ audio_clip audio_gate_ambient = {
 .path = "sound/gate_ambient.ogg"
 };
 
+#if 0
 audio_player ambient_player =
 {
    .name = "Ambience"
@@ -110,6 +111,7 @@ audio_player audio_rewind_player =
 {
    .name = "Rewind"
 };
+#endif
 
 audio_clip audio_rewind[] = {
 { .path = "sound/rewind_start.ogg" },
@@ -124,6 +126,12 @@ audio_clip audio_ui[] = {
    { .path = "sound/ui_ding.ogg" },
 };
 
+audio_clip audio_music[] = {
+   { .path = "sound/song.ogg", .flags = AUDIO_FLAG_VORBIS },
+   { .path = "sound/skate.ogg", .flags = AUDIO_FLAG_VORBIS },
+};
+
+#if 0
 audio_player ambient_sprites[4] =
 {
    { .name = "Ambient Sprites 0" },
@@ -166,9 +174,11 @@ audio_player audio_player_gate =
 {
    .name = "Gate"
 };
+#endif
 
 VG_STATIC void audio_init(void)
 {
+#if 0
    audio_player_init( &audio_player0 );
    audio_player_init( &audio_player1 );
    audio_player_init( &audio_player2 );
@@ -182,6 +192,7 @@ VG_STATIC void audio_init(void)
    audio_player_init( &ambient_sprites[3] );
    audio_player_init( &audio_player_extra );
    audio_player_init( &audio_rewind_player );
+#endif
 
    audio_clip_loadn( audio_board, vg_list_size(audio_board), NULL );
    audio_clip_loadn( audio_ambience, vg_list_size(audio_ambience), NULL );
@@ -189,6 +200,8 @@ VG_STATIC void audio_init(void)
    audio_clip_loadn( &audio_gate_pass, 1, NULL );
    audio_clip_loadn( &audio_gate_lap, 1, NULL );
    audio_clip_loadn( &audio_gate_ambient, 1, NULL );
+   audio_clip_loadn( audio_music, vg_list_size(audio_music), NULL );
+
    audio_clip_loadn( audio_jumps, vg_list_size(audio_jumps), NULL );
    audio_clip_loadn( audio_lands, vg_list_size(audio_lands), NULL );
    audio_clip_loadn( audio_water, vg_list_size(audio_water), NULL );
@@ -201,6 +214,7 @@ VG_STATIC void audio_init(void)
    audio_clip_loadn( audio_rewind, vg_list_size(audio_rewind), NULL );
    audio_clip_loadn( audio_ui, vg_list_size(audio_ui), NULL );
 
+#if 0
    audio_lock();
    u32 flags = AUDIO_FLAG_LOOP|AUDIO_FLAG_SPACIAL_3D;
 
@@ -215,6 +229,7 @@ VG_STATIC void audio_init(void)
    audio_player_set_flags( &ambient_sprites[1], AUDIO_FLAG_SPACIAL_3D );
    audio_player_set_flags( &ambient_sprites[2], AUDIO_FLAG_SPACIAL_3D );
    audio_player_set_flags( &ambient_sprites[3], AUDIO_FLAG_SPACIAL_3D );
+
    audio_player_set_vol( &ambient_player, 1.0f );
    audio_player_set_vol( &audio_player_gate, 0.0f );
    audio_player_set_vol( &audio_player_extra, 1.0f );
@@ -230,6 +245,7 @@ VG_STATIC void audio_init(void)
    audio_player_playclip( &audio_player_gate, &audio_gate_ambient );
 
    audio_unlock();
+#endif
 
    vg_var_push( (struct vg_var){
       .name = "aud_debug_soundscape",
@@ -246,6 +262,38 @@ VG_STATIC void audio_init(void)
       .opt_f32 = { .clamp = 0 },
       .persistent = 1
    });
+
+   audio_lock();
+   audio_set_lfo_wave( 0, k_lfo_polynomial_bipolar, 80.0f );
+   audio_set_lfo_frequency( 0, 20.0f );
+   audio_unlock();
+}
+
+VG_STATIC void audio_update(void)
+{
+#if 0
+   static u32 flapflop = 0x00;
+   static audio_channel *channel = NULL;
+
+   u32 next = floorf( vg.time / 0.1f );
+
+   if( flapflop != next )
+   {
+      flapflop = next;
+
+      audio_lock();
+      channel = audio_channel_crossfade( channel, 
+                                         &audio_music[ next & 0x1 ], 0.05f,
+                                         AUDIO_FLAG_LOOP|AUDIO_FLAG_SPACIAL_3D 
+            );
+      channel = audio_channel_set_spacial( channel,
+                                           (v3f){ -22.3f, 60.1f, -52.7f },
+                                           50.0f );
+
+      audio_channel_sidechain_lfo( channel, 0, 1.0f );
+      audio_unlock();
+   }
+#endif
 }
 
 VG_STATIC void audio_free(void)
index 3e4704ea466fa1e6d8d97eb3a4f44b6bb0dee6f2..1291cff66b4e1158f6597cddd9bff1b2a1606690 100644 (file)
@@ -663,8 +663,10 @@ class classtype_trigger(Structure):
       global cv_view_verts, cv_view_colours
       cv_draw_ucube( obj.matrix_world, [0,1,0,1] )
 
+      white = (1,1,1,1)
+
       if obj.cv_data.target:
-         cv_draw_arrow( obj.location, obj.cv_data.target.location, [1,1,1,1] )
+         cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
    #}
 
    @staticmethod
@@ -698,7 +700,337 @@ class classtype_logic_achievement(Structure):
    #}
 #}
 
-# Classtype 102
+class union_128bit_data(Union):
+#{
+   _pack_ = 1
+   _fields_ = [("f32",c_float),
+               ("u32",c_uint32),
+               ("i32",c_int32),
+               ("v4f",c_float*4)]
+#}
+
+# Class type 105
+#
+#  Purpose:
+#
+class classtype_logic_wire(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("next",c_uint32),
+               ("function",c_uint32),
+               ("data",union_128bit_data),
+               ("data_type",c_uint32),
+               ("enabled",c_uint32)]
+
+   function_enum = [('0',"pass along",""),
+                    ('1',"enable",""),
+                    ('2',"disable",""),
+                    ('3',"","")]
+
+   def encode_obj(_,node,node_def):
+   #{
+      node.classtype = 105
+
+      obj = node_def['obj']
+
+      if obj.cv_data.target:  _.next = obj.cv_data.target.cv_data.uid
+
+      _.data_type = obj.cv_data.intp1
+      _.function = int(obj.cv_data.function)
+      _.enabled = obj.cv_data.bp0
+
+      if _.data_type == 1:                  # an integer
+         _.data.i32 = obj.cv_data.intp
+      elif _.data_type == 2:                # a number
+         _.data.f32 = obj.cv_data.fltp
+      elif _.data_type == 3:                # a target
+         if obj.cv_data.target2:
+            _.data.u32 = obj.cv_data.target2.cv_data.uid
+      elif _.data_type == 4:                # a string
+         _.data.u32 = encoder_process_pstr( obj.cv_data.strp )
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.prop( obj.cv_data, "bp0", text="Start disabled" )
+      box = layout.box()
+      box.label( text="Target" )
+      box.prop( obj.cv_data, "target", text="connection" )
+
+      row = box.row()
+      if not obj.cv_data.target:
+         row.enabled=False
+      row.prop( obj.cv_data, "function", text="function" )
+
+      box = layout.box()
+      box.label( text="Data packet" )
+      box.prop( obj.cv_data, "intp1", text="type" )
+
+      if obj.cv_data.intp1 == 1:
+         box.prop( obj.cv_data, "intp", text="Signed Integer" )
+      elif obj.cv_data.intp1 == 2:
+         box.prop( obj.cv_data, "fltp", text="Float" )
+      elif obj.cv_data.intp1 == 3:
+         box.prop( obj.cv_data, "target2", text="Object reference" )
+      elif obj.cv_data.intp1 == 4:
+         box.prop( obj.cv_data, "strp", text="String" )
+      else:
+      #{
+         row = box.row()
+         row.enabled=False
+         row.label( text="this wire will not impart any data" )
+      #}
+   #}
+
+   @staticmethod
+   def draw_scene_helpers( obj ):
+   #{
+      global cv_view_verts, cv_view_colours
+
+      white = (1,1,1,1)
+      purple = (0.5,0.2,1,1)
+
+      if obj.cv_data.target:
+         cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
+      if (obj.cv_data.target2) and (obj.cv_data.intp1 == 3):
+         cv_draw_arrow( obj.cv_data.target2.location, obj.location,purple, 0.7 )
+   #}
+
+   @staticmethod
+   def get_targeted_methods( scene, context ):
+   #{
+      obj = context.object
+      invalid = [('0',"","")]
+
+      if obj.cv_data.target:
+      #{
+         classtype = obj.cv_data.target.cv_data.classtype
+         if classtype == 'classtype_none' or classtype not in globals():
+         #{
+            return invalid
+         #}
+         else:
+         #{
+            cl = globals()[ classtype ]
+            if getattr( cl, "function_enum", None ):
+            #{
+               return cl.function_enum
+            #}
+            else:
+            #{
+               return invalid
+            #}
+         #}
+      #}
+      else:
+      #{
+         return invalid
+      #}
+   #}
+#}
+
+# Class type 108
+#
+#  Purpose:
+#
+class classtype_particle_box(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("target",c_uint32),
+               ("rate",c_float)]
+
+   function_enum = [('0',"set rate",""),
+                    ('1',"",""),
+                    ('2',"",""),
+                    ('3',"","")]
+
+   def encode_obj(_, node,node_def ):
+   #{
+      node.classtype = 108
+
+      obj = node_def['obj']
+
+      _.rate = obj.cv_data.fltp
+      if obj.cv_data.target:
+         _.target = obj.cv_data.target.cv_data.uid
+   #}
+
+   @staticmethod
+   def draw_scene_helpers( obj ):
+   #{
+      global cv_view_verts, cv_view_colours
+      cv_draw_ucube( obj.matrix_world, [1,0.8,0,1] )
+
+      white = (1,1,1,1)
+      if obj.cv_data.target:
+         cv_draw_arrow( obj.location, obj.cv_data.target.location, white, 0.7 )
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.prop( obj.cv_data, "target", text="Triggers" )
+      layout.prop( obj.cv_data, "fltp", text="count per second" )
+   #}
+#}
+
+# Class type 109
+#
+#  Purpose:
+#
+class classtype_signal_splitter(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("next",c_uint32*4)]
+
+   function_enum = [('0',"pass along",""),
+                    ('1',"",""),
+                    ('2',"",""),
+                    ('3',"","")]
+
+   def encode_obj(_,node,node_def):
+   #{
+      node.classtype = 109
+
+      obj = node_def['obj']
+
+      if obj.cv_data.target:   _.next[0] = obj.cv_data.target.cv_data.uid
+      if obj.cv_data.target1:  _.next[1] = obj.cv_data.target1.cv_data.uid
+      if obj.cv_data.target2:  _.next[2] = obj.cv_data.target2.cv_data.uid
+      if obj.cv_data.target3:  _.next[3] = obj.cv_data.target3.cv_data.uid
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.label( text="The split signals will run in order" )
+      layout.prop( obj.cv_data, "target", text="#0" )
+      layout.prop( obj.cv_data, "target1", text="#1" )
+      layout.prop( obj.cv_data, "target2", text="#2" )
+      layout.prop( obj.cv_data, "target3", text="#3" )
+   #}
+
+   @staticmethod
+   def draw_scene_helpers( obj ):
+   #{
+      global cv_view_verts, cv_view_colours
+
+      c0 = (1,0.5,0.2,1)
+      c1 = (0.8,1,0.1,1)
+      c2 = (0.3,0.9,0.4,1)
+      c3 = (0.1,0.4,1.0,1)
+
+      if obj.cv_data.target:
+         cv_draw_arrow( obj.location, obj.cv_data.target.location, c0, 0.7 )
+      if obj.cv_data.target1:
+         cv_draw_arrow( obj.location, obj.cv_data.target1.location, c1, 0.7 )
+      if obj.cv_data.target2:
+         cv_draw_arrow( obj.location, obj.cv_data.target2.location, c2, 0.7 )
+      if obj.cv_data.target3:
+         cv_draw_arrow( obj.location, obj.cv_data.target3.location, c3, 0.7 )
+   #}
+#}
+
+# Class type 106
+#
+#  Purpose:
+#
+class classtype_soundscape(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("max_instances",c_uint32),
+               ("allow_transitions",c_uint32),
+               ("transition_duration",c_float),
+               ("label",c_uint32)]
+
+   function_enum = [('0',"play",""),
+                    ('1',"set position",""),
+                    ('2',"",""),
+                    ('3',"","")]
+
+   def encode_obj(_,node,node_def):
+   #{
+      node.classtype = 106
+
+      obj = node_def['obj']
+
+      _.max_instances = obj.cv_data.intp
+      _.allow_transitions = obj.cv_data.bp0
+      _.transition_duration = obj.cv_data.fltp
+      _.label = encoder_process_pstr( obj.cv_data.strp )
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.prop( obj.cv_data, "intp", text="max instances" )
+      layout.prop( obj.cv_data, "strp", text="label" )
+
+      box = layout.box()
+      box.label( text="If its a 3d sound, where can it spawn?" )
+      box.prop( obj.cv_data, "bp1", text="Only in water" )
+      box.prop( obj.cv_data, "bp2", text="Only on grass" )
+      box.prop( obj.cv_data, "bp3", text="Only on wood" )
+
+      box = layout.box()
+      box.prop( obj.cv_data, "bp0", text="allow transitions" )
+
+      row = box.row()
+      if not obj.cv_data.bp0:
+         row.enabled=False
+      row.prop( obj.cv_data, "fltp", text="transition duration" )
+   #}
+#}
+
+class classtype_logic_chances(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("targets",c_uint32*2),
+               ("p",c_float)]
+
+   function_enum = [('0',"pass along",""),
+                    ('1',"set ratio",""),
+                    ('2',"",""),
+                    ('3',"","")]
+
+   def encode_obj(_,node,node_def):
+   #{
+      node.classtype = 107
+
+      obj = node_def['obj']
+
+      if obj.cv_data.target:  _.targets[0] = obj.cv_data.target.cv_data.uid
+      if obj.cv_data.target1: _.targets[1] = obj.cv_data.target1.cv_data.uid
+      
+      _.p = obj.cv_data.fltp
+   #}
+
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      box = layout.box()
+      box.prop( obj.cv_data, "target", text="red" )
+      box.prop( obj.cv_data, "target1", text="black" )
+      box.prop( obj.cv_data, "fltp", text="p(red)" )
+   #}
+
+   @staticmethod
+   def draw_scene_helpers( obj ):
+   #{
+      global cv_view_verts, cv_view_colours
+
+      red = (1,0,0,1)
+      black = (0,0,0,1)
+
+      if obj.cv_data.target:
+         cv_draw_arrow( obj.location, obj.cv_data.target.location, red, 0.7 )
+      if obj.cv_data.target1:
+         cv_draw_arrow( obj.location, obj.cv_data.target1.location, black, 0.7 )
+   #}
+#}
+
+# Classtype 102 [ DEPRECATED ]
 #
 #  Purpose: sends a signal to another entity
 #
@@ -756,7 +1088,72 @@ class classtype_logic_relay(Structure):
 #   volume: not used if has 3D flag
 #    flags: 
 #           AUDIO_FLAG_LOOP        0x1
-#           AUDIO_FLAG_ONESHOT     0x2  (DONT USE THIS, it breaks semaphores)
+#           AUDIO_FLAG_SPACIAL_3D  0x4  (Probably what you want)
+#           AUDIO_FLAG_AUTO_START  0x8  (Play when the world starts)
+#           ......
+#           the rest are just internal flags, only use the above 3.
+#
+class classtype_audio(Structure):
+#{
+   _pack_ = 1
+   _fields_ = [("pstr_file",c_uint32),
+               ("flags",c_uint32),
+               ("volume",c_float)]
+
+   def encode_obj(_, node,node_def ):
+   #{
+      node.classtype = 14
+
+      obj = node_def['obj']
+
+      _.pstr_file = encoder_process_pstr( obj.cv_data.strp )
+
+      flags = 0x00
+      if obj.cv_data.bp0: flags |= 0x1
+      if obj.cv_data.bp1: flags |= 0x4
+      if obj.cv_data.bp2: flags |= 0x8
+
+      if obj.cv_data.audio_format == 'stereo':
+         flags |= 0x200
+      if obj.cv_data.audio_format == 'remain compressed':
+         flags |= 0x400
+
+      _.flags = flags
+      _.volume = obj.cv_data.fltp
+   #}
+   
+   @staticmethod
+   def editor_interface( layout, obj ):
+   #{
+      layout.prop( obj.cv_data, "strp", text = "File (.ogg)" )
+
+      layout.prop( obj.cv_data, "bp0", text = "Looping" )
+      layout.prop( obj.cv_data, "bp1", text = "3D Audio" )
+      layout.prop( obj.cv_data, "bp2", text = "Auto Start" )
+      layout.prop( obj.cv_data, "audio_format" )
+
+      layout.prop( obj.cv_data, "fltp", text = "Volume (0-1)" )
+   #}
+
+   @staticmethod
+   def draw_scene_helpers( obj ):
+   #{
+      global cv_view_verts, cv_view_colours
+
+      cv_draw_sphere( obj.location, obj.scale[0], [1,1,0,1] )
+   #}
+#}
+
+# Classtype 14
+#
+#  Purpose: Plays some audio (44100hz .ogg vorbis only)
+#           NOTE: There is a 32mb limit on the audio buffer, world audio is
+#                 decompressed and stored in signed 16 bit integers (2 bytes)
+#                 per sample.
+#
+#   volume: not used if has 3D flag
+#    flags: 
+#           AUDIO_FLAG_LOOP        0x1
 #           AUDIO_FLAG_SPACIAL_3D  0x4  (Probably what you want)
 #           AUDIO_FLAG_AUTO_START  0x8  (Play when the world starts)
 #           ......
@@ -2247,7 +2644,7 @@ def cv_draw_ucube( transform, colour ):
       v1 = vs[l[1]]
       cv_view_verts += [(v0[0],v0[1],v0[2])]
       cv_view_verts += [(v1[0],v1[1],v1[2])]
-      cv_view_colours += [(0,1,0,1),(0,1,0,1)]
+      cv_view_colours += [colour, colour]
    #}
    cv_draw_lines()
 #}
@@ -2301,7 +2698,7 @@ def cv_tangent_basis( n, tx, ty ):
 
 # Draw coloured arrow
 #
-def cv_draw_arrow( p0, p1, c0 ):
+def cv_draw_arrow( p0, p1, c0, size=0.15 ):
 #{
    global cv_view_verts, cv_view_colours
 
@@ -2313,7 +2710,7 @@ def cv_draw_arrow( p0, p1, c0 ):
    ty = Vector((1,0,0))
    cv_tangent_basis( n, tx, ty )
    
-   cv_view_verts += [p0,p1, midpt+(tx-n)*0.15,midpt, midpt+(-tx-n)*0.15,midpt ]
+   cv_view_verts += [p0,p1, midpt+(tx-n)*size,midpt, midpt+(-tx-n)*size,midpt ]
    cv_view_colours += [c0,c0,c0,c0,c0,c0]
    cv_draw_lines()
 #}
@@ -2689,6 +3086,7 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup):
 
    strp: bpy.props.StringProperty( name="strp" )
    intp: bpy.props.IntProperty( name="intp" )
+   intp1: bpy.props.IntProperty( name="intp1" )
    fltp: bpy.props.FloatProperty( name="fltp" )
    bp0: bpy.props.BoolProperty( name="bp0" )
    bp1: bpy.props.BoolProperty( name="bp1" )
@@ -2707,6 +3105,11 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup):
    colour: bpy.props.FloatVectorProperty( name="colour",subtype='COLOR',\
                                           min=0.0,max=1.0)
 
+   function: bpy.props.EnumProperty(
+      name="Function",
+      items= classtype_logic_wire.get_targeted_methods
+   )
+
    classtype: bpy.props.EnumProperty(
       name="Format", 
       items = [
@@ -2720,6 +3123,11 @@ class CV_OBJ_SETTINGS(bpy.types.PropertyGroup):
       ('classtype_trigger',"classtype_trigger","",100),
       ('classtype_logic_achievement',"classtype_logic_achievement","",101),
       ('classtype_logic_relay',"classtype_logic_relay","",102),
+      ('classtype_logic_wire',"classtype_logic_wire","",105),
+      ('classtype_soundscape',"classtype_soundscape","",106),
+      ('classtype_logic_chances',"classtype_logic_chances","",107),
+      ('classtype_particle_box',"classtype_particle_box","",108),
+      ('classtype_signal_splitter',"classtype_signal_splitter","",109),
       ('classtype_spawn_link',"classtype_spawn_link","",150),
       ('classtype_nonlocal_gate', "classtype_nonlocal_gate", "", 300)
       ])
index 19b5a6fa5d84130b030ec431864fb0a911270aaa..be210a5d49ff89046aafe263a7475857b163d9a8 100644 (file)
--- a/common.h
+++ b/common.h
@@ -119,6 +119,7 @@ VG_STATIC int   k_debug_light_indices = 0,
                 k_light_preview = 0;
 
 VG_STATIC int freecam = 0;
+VG_STATIC int debug_logic_bricks = 0;
 VG_STATIC int walk_grid_iterations = 1;
 VG_STATIC float fc_speed = 10.0f;
 VG_STATIC int cl_thirdperson = 0;
@@ -150,6 +151,7 @@ VG_STATIC void common_var_temp(void)
    VG_VAR_F32( k_walk_accel );
 
    VG_VAR_I32( freecam );
+   VG_VAR_F32_PERSISTENT( debug_logic_bricks );
    VG_VAR_I32( cl_thirdperson );
    VG_VAR_F32_PERSISTENT( fc_speed );
 
index 83930f58abfe4e01409e9308751878d5e2da1005..3b81176a7ba5b58df10af90442b1b116d8466856 100644 (file)
Binary files a/maps_src/mp_gridmap.mdl and b/maps_src/mp_gridmap.mdl differ
index b1360d8136cc661172238899aca05edc86660398..29c0ae5ac5722e3c2f3835026b1fdd70968ddd4d 100644 (file)
Binary files a/maps_src/mp_home.mdl and b/maps_src/mp_home.mdl differ
index 0c6120ef8807cc5a153a31c74ffb54fdc2d2e3ee..16998100aee47e87c050711e4c9d53678fe21f0d 100644 (file)
Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ
diff --git a/model.h b/model.h
index 4a310695f27784dda33164f7b7f494bcde36b87b..6134fc50dd9d9df836d09022fcfb8121d2bb63cd 100644 (file)
--- a/model.h
+++ b/model.h
@@ -42,6 +42,14 @@ enum classtype
    k_classtype_trigger              = 100,
    k_classtype_logic_achievement    = 101,
    k_classtype_logic_relay          = 102,
+   k_classtype_logic_script         = 103,
+
+   k_classtype_logic_wire           = 105,
+   k_classtype_soundscape           = 106,
+   k_classtype_logic_chances        = 107,
+   k_classtype_particle_box         = 108,
+   k_classtype_signal_splitter      = 109,
+
    k_classtype_world_light          = 200,
    k_classtype_nonlocal_gate        = 300
 };
@@ -254,6 +262,17 @@ struct classtype_trigger
    u32 target;
 };
 
+struct classtype_particle_box
+{
+   u32 target;
+   float rate;
+};
+
+struct classtype_signal_splitter
+{
+   u32 next[4];
+};
+
 struct classtype_logic_relay
 {
    u32 targets[4];
@@ -287,6 +306,51 @@ struct classtype_world_light
    float angle, range;
 };
 
+struct classtype_logic_wire
+{
+   u32 next,
+       function;
+
+   union mdl_128bit_union
+   {
+      float _f32;
+      u32   _u32;
+      i32   _i32;
+      v4f   _v4f;
+   }
+   data;
+
+   enum mdl_128bit_datatype
+   {
+      k_mdl_128bit_datatype_nothing = 0u,
+      k_mdl_128bit_datatype_integer = 1u,
+      k_mdl_128bit_datatype_number  = 2u,
+      k_mdl_128bit_datatype_target  = 3u,
+      k_mdl_128bit_datatype_string  = 4u,
+      k_mdl_128bit_datatype_vec2    = 5u,
+      k_mdl_128bit_datatype_vec3    = 6u,
+      k_mdl_128bit_datatype_vec4    = 7u
+   }
+   data_type;
+
+   u32 enabled;
+};
+
+struct classtype_soundscape
+{
+   u32 max_instances,
+       allow_transitions;
+
+   float transition_duration;
+   u32 label;
+};
+
+struct classtype_logic_chances
+{
+   u32 targets[2];
+   float p;
+};
+
 #pragma pack(pop)
 
 
index 5350b2eff84e185e0b8845e78e0d40de0d9c0861..744b5eb050ca27c7fb5c040c21cffb2843b0aabf 100644 (file)
@@ -2,6 +2,7 @@
 #define PLAYER_SKATE_C
 
 #include "player.h"
+#include "audio.h"
 
 VG_STATIC void player__skate_bind( player_instance *player )
 {
@@ -860,15 +861,9 @@ VG_STATIC void skate_apply_jump_model( player_instance *player )
       s->state.lift_frames ++;
 #endif
 
-      /* FIXME audio events */
-#if 0
       audio_lock();
-      audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
-      audio_player_set_position( &audio_player_extra, player.rb.co );
-      audio_player_set_vol( &audio_player_extra, 20.0f );
-      audio_player_playclip( &audio_player_extra, &audio_jumps[rand()%2] );
+      audio_oneshot_3d( &audio_jumps[rand()%2], player->rb.co, 40.0f, 1.0f );
       audio_unlock();
-#endif
    }
 }
 
@@ -1077,6 +1072,70 @@ VG_STATIC void player__skate_post_update( player_instance *player )
 #if 0
    vg_line_pt3( s->state.apex, 0.030f, 0xff0000ff );
 #endif
+
+   audio_lock();
+
+   float air   = s->state.activity == k_skate_activity_air? 1.0f: 0.0f,
+         speed = v3_length( player->rb.v ),
+         attn  = vg_minf( 1.0f, speed*0.1f ),
+         slide = vg_clampf( fabsf(s->state.slip), 0.0f, 1.0f ),
+
+         vol_main    = sqrtf( (1.0f-air)*attn*(1.0f-slide) * 0.4f ),
+         vol_air     = sqrtf(       air *attn * 0.5f ),
+         vol_slide   = sqrtf( (1.0f-air)*attn*slide * 0.25f );
+
+   const u32 flags = AUDIO_FLAG_SPACIAL_3D|AUDIO_FLAG_LOOP;
+   if( !s->aud_main )
+      s->aud_main = audio_request_channel( &audio_board[0], flags );
+
+   if( !s->aud_air )
+      s->aud_air = audio_request_channel( &audio_board[1], flags );
+
+   if( !s->aud_slide )
+      s->aud_slide = audio_request_channel( &audio_board[2], flags );
+
+
+   /* brrrrrrrrrrrt sound for tiles and stuff 
+    * --------------------------------------------------------*/
+   float sidechain_amt = 0.0f,
+         hz            = speed * 2.0f;
+
+   if( s->surface == k_surface_prop_tiles )
+      sidechain_amt = 1.0f;
+   else
+      sidechain_amt = 0.0f;
+
+   audio_set_lfo_frequency( 0, hz );
+   audio_set_lfo_wave( 0, k_lfo_polynomial_bipolar, 
+                        vg_lerpf( 250.0f, 80.0f, attn ) );
+
+   if( s->aud_main )
+   {
+      s->aud_main->colour = 0x00103efe;
+      audio_channel_set_spacial( s->aud_main, player->rb.co, 40.0f );
+      audio_channel_slope_volume( s->aud_main, 0.05f, vol_main );
+      audio_channel_sidechain_lfo( s->aud_main, 0, sidechain_amt );
+
+      float rate = 1.0f + (attn-0.5f)*0.2f;
+      audio_channel_set_sampling_rate( s->aud_main, rate );
+   }
+
+   if( s->aud_slide )
+   {
+      s->aud_slide->colour = 0x00103efe;
+      audio_channel_set_spacial( s->aud_slide, player->rb.co, 40.0f );
+      audio_channel_slope_volume( s->aud_slide, 0.05f, vol_slide );
+      audio_channel_sidechain_lfo( s->aud_slide, 0, sidechain_amt );
+   }
+
+   if( s->aud_air )
+   {
+      s->aud_air->colour = 0x00103efe;
+      audio_channel_set_spacial( s->aud_air, player->rb.co, 40.0f );
+      audio_channel_slope_volume( s->aud_air, 0.05f, vol_air );
+   }
+
+   audio_unlock();
 }
 
 /*
@@ -2214,6 +2273,17 @@ begin_collision:;
     * --------------------------------------------------------------------------
     */
 
+   s->surface = k_surface_prop_concrete;
+
+   for( int i=0; i<manifold_len; i++ )
+   {
+      rb_ct *ct = &manifold[i];
+      struct world_material *surface_mat = world_contact_material( world, ct );
+
+      if( surface_mat->info.surface_prop != k_surface_prop_concrete )
+         s->surface = surface_mat->info.surface_prop;
+   }
+
    for( int i=0; i<k_wheel_count; i++ )
    {
       m4x3f mtx;
@@ -2248,6 +2318,31 @@ begin_collision:;
       s->state_gate_storage = s->state;
       player__pass_gate( player, &hit );
    }
+
+   /* FIXME: Rate limit */
+   static int stick_frames = 0;
+
+   if( s->state.activity == k_skate_activity_ground )
+      stick_frames ++;
+   else
+      stick_frames = 0;
+
+
+   if( stick_frames == 4 )
+   {
+      audio_lock();
+      if( (fabsf(s->state.slip) > 0.75f) )
+      {
+         audio_oneshot_3d( &audio_lands[rand()%2+3], player->rb.co, 
+                           40.0f, 1.0f );
+      }
+      else
+      {
+         audio_oneshot_3d( &audio_lands[rand()%3], player->rb.co, 
+                           40.0f, 1.0f );
+      }
+      audio_unlock();
+   }
 }
 
 VG_STATIC void player__skate_im_gui( player_instance *player )
index 4c8bbd4afc83d93fdaf23e6226d41e2dce44fd21..867a23888eb751b501cf4ba432a724ea62bbb2ee 100644 (file)
@@ -104,6 +104,9 @@ struct player_skate
    v3f truckv0[2];
    v2f wobble;
 
+   audio_channel *aud_main, *aud_slide, *aud_air;
+   enum mdl_surface_prop surface, audio_surface;
+
    /*
     * Physics 
     * ----------------------------------------------------
index e0d8a316aad848bd3d22a220f354698cb0333330..ad01803a6d02ca2d76f2990b1ea5a064aff3b1fa 100644 (file)
@@ -299,6 +299,8 @@ VG_STATIC void vg_update(void)
 
       player__pre_update( &localplayer );
       world_update( get_active_world(), localplayer.rb.co );
+
+      audio_update();
    }
 }
 
@@ -334,8 +336,82 @@ VG_STATIC void vg_update_post(void)
 
       player__post_update( &localplayer );
 
+      
+      float inr3 = 0.57735027,
+            inr2 = 0.70710678118;
+
+      v3f sample_directions[] = {
+         { -1.0f,  0.0f,  0.0f },
+         {  1.0f,  0.0f,  0.0f },
+         {  0.0f,  0.0f,  1.0f },
+         {  0.0f,  0.0f, -1.0f },
+         {  0.0f,  1.0f,  0.0f },
+         {  0.0f, -1.0f,  0.0f },
+         { -inr3,  inr3,  inr3 },
+         {  inr3,  inr3,  inr3 },
+         { -inr3,  inr3, -inr3 },
+         {  inr3,  inr3, -inr3 },
+         { -inr2,  0.0f,  inr2 },
+         {  inr2,  0.0f,  inr2 },
+         { -inr2,  0.0f, -inr2 },
+         {  inr2,  0.0f, -inr2 },
+      };
+
+      static int si = 0;
+      static float distances[16];
+
+      ray_hit ray;
+      ray.dist = 5.0f;
+
+      v3f rc, rd, ro;
+      v3_copy( sample_directions[ si ], rd );
+      v3_add( localplayer.rb.co, (v3f){0.0f,1.5f,0.0f}, ro );
+      v3_copy( ro, rc );
+
+      float dist = 200.0f;
+
+      for( int i=0; i<10; i++ )
+      {
+         if( ray_world( get_active_world(), rc, rd, &ray ) )
+         {
+            dist = (float)i*5.0f + ray.dist;
+            break;
+         }
+         else
+         {
+            v3_muladds( rc, rd, ray.dist, rc );
+         }
+      }
+
+      distances[si] = dist;
+
+
+      for( int i=0; i<14; i++ )
+      {
+         if( distances[i] != 200.0f )
+         {
+            u32 colours[] = { VG__RED, VG__BLUE, VG__GREEN,
+                              VG__CYAN, VG__YELOW, VG__PINK,
+                              VG__WHITE };
+
+            u32 colour = colours[i%7];
+
+            v3f p1;
+            v3_muladds( ro, sample_directions[i], distances[i], p1 );
+            vg_line( ro, p1, colour );
+            vg_line_pt3( p1, 0.1f, colour );
+         }
+      }
+
+      si ++;
+      if( si >= 14 )
+         si = 0;
+
+
       /* FIXME: TEMP */
       audio_lock();
+      vg_dsp.echo_distances[si] = dist;
+
       v3f ears = { 1.0f,0.0f,0.0f };
       m3x3_mulv( main_camera.transform, ears, ears );
       v3_copy( ears, vg_audio.listener_ears );
diff --git a/sound_src/skate_hpf.ogg b/sound_src/skate_hpf.ogg
new file mode 100644 (file)
index 0000000..d7ba94b
Binary files /dev/null and b/sound_src/skate_hpf.ogg differ
diff --git a/world.h b/world.h
index 69def4c85875df63fa9bd9a9c0d207738b94daeb..4352b6e6031bd38f608b24061591e93e81ad72e1 100644 (file)
--- a/world.h
+++ b/world.h
@@ -170,17 +170,21 @@ struct world_instance
    struct world_audio_thing
    {
       v3f pos;
-      float volume;
+      float volume, range;
       u32 flags;
 
+#if 0
       audio_player player;
+#endif
+
       audio_clip temp_embedded_clip;
    }
    * audio_things;
    u32 audio_things_count;
 
+#if 0
    /*
-    * Relays
+    * Relays  [ DEPRECATED ]
     */
    struct logic_relay
    {
@@ -196,6 +200,34 @@ struct world_instance
    }
    * logic_relays;
    u32 relay_count;
+#endif
+
+   struct soundscape
+   {
+      /* locking */
+      audio_channel *channels[4];
+      
+      /* accessable without locking */
+      v3f spawn_position;
+
+      u32 usage_count;
+      u32 max_instances;
+      u32 allow_transitions;
+      float transition_duration;
+      const char *label;
+   }
+   * soundscapes;
+   u32 soundscape_count;
+
+   struct logic_brick_ref
+   {
+      mdl_node *node;
+      float usage;
+      u32 internal_id;  /* used for things like soundscapes where another
+                           allocation is made on top */
+   }
+   * logic_bricks;
+   u32 logic_brick_count;
 
    /*
     * Box trigger entities
@@ -203,8 +235,9 @@ struct world_instance
    struct trigger_zone
    {
       m4x3f transform, inv_transform;
-
-      struct relay_target target;
+      
+      u32 target_logic_brick;
+      enum classtype classtype;
    }
    * triggers;
    u32 trigger_count;
@@ -437,6 +470,7 @@ int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit );
 #include "world_sfd.h"
 #include "world_render.h"
 #include "world_water.h"
+#include "world_logic_bricks.h"
 #include "world_gen.h"
 #include "world_gate.h"
 
@@ -455,6 +489,7 @@ VG_STATIC int world_stop_sound( int argc, const char *argv[] )
     * Therefore it is safe to delete clip data after the players are
     * disconnected
     */
+#if 0
    audio_lock();
    for( int i=0; i<world->audio_things_count; i++ )
    {
@@ -467,6 +502,7 @@ VG_STATIC int world_stop_sound( int argc, const char *argv[] )
       }
    }
    audio_unlock();
+#endif
 
    return 0;
 }
@@ -571,6 +607,7 @@ VG_STATIC void world_audio_init(void)
 #endif
 }
 
+#if 0
 VG_STATIC void world_trigger_achievement( world_instance *world, u32 uid )
 {
    struct logic_achievement *ach = &world->logic_achievements[ uid ];
@@ -583,7 +620,9 @@ VG_STATIC void world_trigger_achievement( world_instance *world, u32 uid )
 
    ach->achieved = 1;
 }
+#endif
 
+#if 0
 VG_STATIC void world_run_relay( world_instance *world, 
                                 struct relay_target *rt );
 
@@ -596,7 +635,9 @@ VG_STATIC void world_trigger_relay( world_instance *world, u32 uid )
       world_run_relay( world, &relay->targets[i] );
    }
 }
+#endif
 
+#if 0
 VG_STATIC void world_trigger_audio( world_instance *world, u32 uid )
 {
    struct world_audio_thing *wat = &world->audio_things[ uid ];
@@ -606,7 +647,9 @@ VG_STATIC void world_trigger_audio( world_instance *world, u32 uid )
                           &wat->temp_embedded_clip );
    audio_unlock();
 }
+#endif
 
+#if 0
 VG_STATIC void world_run_relay( world_instance *world,
                                 struct relay_target *rt )
 {
@@ -619,7 +662,8 @@ VG_STATIC void world_run_relay( world_instance *world,
    {
       { k_classtype_logic_achievement, world_trigger_achievement },
       { k_classtype_logic_relay, world_trigger_relay },
-      { k_classtype_audio, world_trigger_audio }
+      { k_classtype_audio, world_trigger_audio },
+      { k_classtype_logic_wire, logic_bricks_trigger_brick }
    };
 
    for( int i=0; i<vg_list_size(entity_instructions); i++ )
@@ -635,6 +679,7 @@ VG_STATIC void world_run_relay( world_instance *world,
 
    vg_error( "Don't know how to trigger classtype %d\n", rt->classtype );
 }
+#endif
 
 VG_STATIC void world_update( world_instance *world, v3f pos )
 {
@@ -747,12 +792,41 @@ VG_STATIC void world_update( world_instance *world, v3f pos )
          }
       }
    }
+   
+   /* TODO: Bvh */
+
+   static float random_accum = 0.0f;
+   random_accum += vg.time_delta;
+
+   u32 random_ticks = 0;
+
+   while( random_accum > 0.1f )
+   {
+      random_accum -= 0.1f;
+      random_ticks ++;
+   }
 
    int in_trigger = 0;
    for( int i=0; i<world->trigger_count; i++ )
    {
       struct trigger_zone *zone = &world->triggers[i];
 
+      for( int j=0; j<random_ticks; j++ )
+      {
+         logic_packet packet;
+         packet.location = zone->target_logic_brick;
+         packet.function = 0;
+
+         packet.type = k_mdl_128bit_datatype_vec3;
+         packet.data._v4f[0] = vg_randf()*2.0f-1.0f;
+         packet.data._v4f[1] = vg_randf()*2.0f-1.0f;
+         packet.data._v4f[2] = vg_randf()*2.0f-1.0f;
+         m4x3_mulv( zone->transform, packet.data._v4f, packet.data._v4f );
+
+         logic_bricks_send_packet( world, &packet );
+         continue;
+      }
+
       v3f local;
       m4x3_mulv( zone->inv_transform, pos, local );
       
@@ -764,7 +838,14 @@ VG_STATIC void world_update( world_instance *world, v3f pos )
 
          if( !world_global.in_trigger )
          {
-            world_run_relay( world, &zone->target );
+            logic_packet packet;
+            packet.location = zone->target_logic_brick;
+            packet.function = 0;
+
+            packet.type = k_mdl_128bit_datatype_vec3;
+            v3_copy( pos, packet.data._v4f );
+
+            logic_bricks_send_packet( world, &packet );
          }
       }
 
@@ -795,6 +876,29 @@ VG_STATIC void world_update( world_instance *world, v3f pos )
 
    world_global.in_trigger = in_trigger;
    sfd_update();
+
+   if( debug_logic_bricks )
+      logic_bricks_debug( world );
+
+   /* process soundscape transactions */
+   audio_lock();
+   for( int i=0; i<world->soundscape_count; i++ )
+   {
+      struct soundscape *s = &world->soundscapes[i];
+      s->usage_count = 0;
+
+      for( int j=0; j<s->max_instances; j++ )
+      {
+         if( s->channels[j] )
+         {
+            if( audio_channel_finished(s->channels[j]) )
+               s->channels[j] = audio_relinquish_channel( s->channels[j] );
+            else
+               s->usage_count ++;
+         }
+      }
+   }
+   audio_unlock();
 }
 
 /* 
index 293784aa5365d496e3a375326300d2d242525de1..cbf47287f9d1de2881a4a60de7b0287119281e74 100644 (file)
@@ -151,7 +151,7 @@ VG_STATIC void world_ents_allocate( world_instance *world )
 
    struct countable
    {
-      enum   classtype ct;
+      enum   classtype ct, ct1;
       void **to_allocate;
       u32    item_size;
       int    count;
@@ -160,38 +160,54 @@ VG_STATIC void world_ents_allocate( world_instance *world )
    {
       { 
          k_classtype_spawn, 
+         k_classtype_none,
          (void*)&world->spawns,       
          sizeof(struct respawn_point) 
       },
       { 
          k_classtype_audio, 
+         k_classtype_none,
          (void*)&world->audio_things, 
          sizeof(struct world_audio_thing) 
       },
       {
          k_classtype_trigger,
+         k_classtype_particle_box,
          (void*)&world->triggers,
          sizeof(struct trigger_zone)
       },
+
+#if 0
       {
          k_classtype_logic_relay,
          (void*)&world->logic_relays,
          sizeof(struct logic_relay)
       },
+#endif
+
       {
          k_classtype_logic_achievement,
+         k_classtype_none,
          (void*)&world->logic_achievements,
          sizeof(struct logic_achievement)
       },
       {
          k_classtype_world_light,
+         k_classtype_none,
          (void*)&world->lights,
          sizeof(struct world_light)
       },
       {
          k_classtype_nonlocal_gate,
+         k_classtype_none,
          (void*)&world->nonlocal_gates,
          sizeof(struct nonlocal_gate)
+      },
+      {
+         k_classtype_soundscape,
+         k_classtype_none,
+         (void*)&world->soundscapes,
+         sizeof(struct soundscape)
       }
    };
 
@@ -204,7 +220,8 @@ VG_STATIC void world_ents_allocate( world_instance *world )
       
       for( int j=0; j<vg_list_size(entity_counts); j ++ )
       {
-         if( pnode->classtype == entity_counts[j].ct )
+         if( (pnode->classtype == entity_counts[j].ct) ||
+             (pnode->classtype == entity_counts[j].ct1) )
          {
             pnode->sub_uid = entity_counts[j].count;
             entity_counts[j].count ++;
@@ -220,7 +237,10 @@ VG_STATIC void world_ents_allocate( world_instance *world )
       u32 bufsize = counter->item_size*counter->count;
       *counter->to_allocate = vg_linear_alloc( world_global.generic_heap, 
                                                bufsize );
+      memset( *counter->to_allocate, 0, bufsize );
    }
+
+   logic_bricks_world_gen_allocate( world );
 }
 
 VG_STATIC void world_pct_spawn( world_instance *world, mdl_node *pnode )
@@ -255,48 +275,20 @@ VG_STATIC void world_pct_audio( world_instance *world, mdl_node *pnode )
 
    v3_copy( pnode->co, thing->pos );
    
-   if( aud->flags & AUDIO_FLAG_SPACIAL_3D )
-      thing->volume = aud->volume * pnode->s[0];
-   else
-      thing->volume = aud->volume;
+   thing->volume = aud->volume;
+   thing->range = pnode->s[0];
 
    thing->flags = aud->flags;
    thing->temp_embedded_clip.path = mdl_pstr( world->meta, aud->pstr_file );
    thing->temp_embedded_clip.flags = aud->flags;
 
    audio_clip_load( &thing->temp_embedded_clip, world_global.generic_heap );
-   thing->player.name = mdl_pstr( world->meta, pnode->pstr_name );
-   thing->player.enqued = 0;
 
    pnode->sub_uid = world->audio_things_count;
    world->audio_things_count ++;
 }
 
-VG_STATIC void world_pct_trigger( world_instance *world, mdl_node *pnode )
-{
-   struct trigger_zone *trigger = &world->triggers[ world->trigger_count ];
-   struct classtype_trigger *inf = mdl_get_entdata( world->meta, pnode );
-   
-   if( inf->target )
-   {
-      mdl_node *target_node = mdl_node_from_id( world->meta, inf->target );
-
-      trigger->target.sub_id = target_node->sub_uid;
-      trigger->target.classtype = target_node->classtype;
-   }
-   else
-   {
-      vg_warn( "Trigger with no target...\n" );
-      return;
-   }
-
-   mdl_node_transform( pnode, trigger->transform );
-   m4x3_invert_full( trigger->transform, trigger->inv_transform );
-
-   world->trigger_count ++;
-}
-
-
+#if 0
 VG_STATIC void world_pct_relay( world_instance *world, mdl_node *pnode )
 {
    struct logic_relay *relay = &world->logic_relays[ world->relay_count ];
@@ -319,6 +311,7 @@ VG_STATIC void world_pct_relay( world_instance *world, mdl_node *pnode )
    v3_copy( pnode->co, relay->pos );
    world->relay_count ++;
 }
+#endif
 
 
 VG_STATIC void world_pct_achievement( world_instance *world, mdl_node *pnode )
@@ -373,8 +366,9 @@ VG_STATIC void world_entities_process( world_instance *world )
       { k_classtype_spawn,    world_pct_spawn },
       { k_classtype_water,    world_pct_water },
       { k_classtype_audio,    world_pct_audio },
-      { k_classtype_trigger,  world_pct_trigger },
+#if 0
       { k_classtype_logic_relay, world_pct_relay },
+#endif
       { k_classtype_logic_achievement, world_pct_achievement },
       { k_classtype_world_light, world_pct_world_light },
       { k_classtype_nonlocal_gate, world_pct_nonlocal_gate }
@@ -764,17 +758,18 @@ VG_STATIC void world_post_process( world_instance *world )
    for( int i=0; i<world->audio_things_count; i++ )
    {
       struct world_audio_thing *thingy = &world->audio_things[ i ];
-      
-      audio_player_init( &thingy->player );
-      audio_player_set_flags( &thingy->player, thingy->flags );
-      audio_player_set_vol( &thingy->player, thingy->volume );
-      audio_player_set_pan( &thingy->player, 0.0f );
-
-      if( thingy->flags & AUDIO_FLAG_SPACIAL_3D )
-         audio_player_set_position( &thingy->player, thingy->pos );
 
       if( thingy->flags & AUDIO_FLAG_AUTO_START )
-         audio_player_playclip( &thingy->player, &thingy->temp_embedded_clip );
+      {
+         audio_channel *ch = 
+            audio_request_channel( &thingy->temp_embedded_clip, thingy->flags );
+
+         audio_channel_edit_volume( ch, thingy->volume, 1 );
+         audio_channel_set_spacial( ch, thingy->pos, thingy->range );
+
+         if( !(ch->flags & AUDIO_FLAG_LOOP) )
+            ch = audio_relinquish_channel( ch );
+      }
    }
    audio_unlock();
 
@@ -1020,6 +1015,10 @@ VG_STATIC void world_clean( world_instance *world )
    /* clean dangling pointers */
    world->meta = NULL;
 
+   /*
+    * TODO: Theres probably a better way to do this? 
+    */
+
    world->textures = NULL;
    world->texture_count = 0;
    world->materials = NULL;
@@ -1045,8 +1044,10 @@ VG_STATIC void world_clean( world_instance *world )
    world->lights = NULL;
    world->light_count = 0;
 
+#if 0
    world->logic_relays = NULL;
    world->relay_count = 0;
+#endif
 
    world->logic_achievements = NULL;
    world->achievement_count = 0;
@@ -1063,6 +1064,12 @@ VG_STATIC void world_clean( world_instance *world )
    world->collectors = NULL;
    world->collector_count = 0;
 
+   world->soundscapes = NULL;
+   world->soundscape_count = 0;
+
+   world->logic_bricks = NULL;
+   world->logic_brick_count = 0;
+
    world->nonlocal_gates = NULL;
    world->nonlocalgate_count = 0;
 
diff --git a/world_logic_bricks.h b/world_logic_bricks.h
new file mode 100644 (file)
index 0000000..2df236a
--- /dev/null
@@ -0,0 +1,495 @@
+#include "common.h"
+
+#ifndef WORLD_LOGIC_BRICKS_H
+#define WORLD_LOGIC_BRICKS_H
+
+#include "world.h"
+
+typedef struct logic_packet logic_packet;
+struct logic_packet
+{
+   u32 location, function;
+   union mdl_128bit_union data;
+   enum mdl_128bit_datatype type;
+};
+
+VG_STATIC void logic_bricks_debug_connection( world_instance *world,
+                                              mdl_node *from, u32 next,
+                                              v3f colour )
+{
+   if( next == 0 )
+      return;
+
+   mdl_node *to = mdl_node_from_id( world->meta, next );
+
+   v3f c;
+   float brightness = 0.8f + world->logic_bricks[ from->sub_uid ].usage * 4.0f;
+   v3_muls( colour, brightness, c );
+
+   u32 clamped = 0xff000000;
+
+   for( int i=0; i<3; i++ )
+   {
+      u8 byte = vg_minf( 1.0f, c[i] ) * 255.0f;
+      clamped |= byte << (i*8);
+   }
+
+   vg_line( from->co, to->co, clamped );
+}
+
+VG_STATIC void logic_bricks_debug( world_instance *world )
+{
+   v3f white = {1.0f,1.0f,1.0f},
+       red   = {1.0f,0.2f,0.1f},
+       black = {0.2f,0.2f,0.2f};
+
+   glLineWidth( 2.0f );
+
+   for( int i=0; i<world->logic_brick_count; i++ )
+   {
+      struct logic_brick_ref *ref = &world->logic_bricks[i];
+      mdl_node *node = ref->node;
+
+      void *entdata = mdl_get_entdata( world->meta, node );
+
+      if( ref->node->classtype == k_classtype_logic_wire )
+      {
+         struct classtype_logic_wire *wire = entdata;
+
+         logic_bricks_debug_connection( world, node, wire->next, white );
+      }
+      else if( ref->node->classtype == k_classtype_logic_chances )
+      {
+         struct classtype_logic_chances *chances = entdata;
+
+         logic_bricks_debug_connection(world, node, chances->targets[0], red );
+         logic_bricks_debug_connection(world, node, chances->targets[1], black);
+      }
+      else if( ref->node->classtype == k_classtype_signal_splitter )
+      {
+         struct classtype_signal_splitter *splitter = entdata;
+         logic_bricks_debug_connection( world, node, splitter->next[0], white );
+         logic_bricks_debug_connection( world, node, splitter->next[1], white );
+         logic_bricks_debug_connection( world, node, splitter->next[2], white );
+         logic_bricks_debug_connection( world, node, splitter->next[3], white );
+      }
+      else if( ref->node->classtype == k_classtype_soundscape )
+      {
+         struct classtype_soundscape *inf = entdata;
+         struct soundscape *s = &world->soundscapes[ ref->internal_id ];
+
+         v3f co;
+         v3_copy( ref->node->co, co );
+
+         boxf box;
+         box[0][0] = co[0]-0.12f;
+         box[0][1] = co[1]-0.12f;
+         box[0][2] = co[2]-0.12f;
+         box[1][0] = co[0]+0.12f;
+         box[1][1] = co[1]+0.12f + 0.1f*(float)inf->max_instances;
+         box[1][2] = co[2]+0.12f;
+
+         vg_line_boxf( box, VG__WHITE );
+
+         for( int i=0; i<s->usage_count; i++ )
+         {
+            vg_line_pt3( co, 0.09f, VG__GREEN );
+            co[1] += 0.2f;
+         }
+      }
+      else if( ref->node->classtype == k_classtype_trigger )
+      {
+         struct classtype_trigger *trigger = entdata;
+         logic_bricks_debug_connection( world, node, trigger->target, white );
+      }
+      else if( ref->node->classtype == k_classtype_particle_box )
+      {
+         struct classtype_particle_box *pb = entdata;
+         logic_bricks_debug_connection( world, node, pb->target, white );
+      }
+
+      ref->usage *= vg_maxf( 0.0f, 1.0f-vg.time_delta*5.0f );
+   }
+}
+
+VG_STATIC void logic_packet_terminate( logic_packet *packet )
+{
+   packet->location = 0xffffffff;
+}
+
+VG_STATIC void logic_wire_call( world_instance *world, 
+                                struct logic_brick_ref *ref, 
+                                logic_packet *packet )
+{
+   struct classtype_logic_wire *inf = mdl_get_entdata( world->meta, ref->node );
+
+   if( packet->function == 0 )         /* pass onwards */
+   {
+      if( inf->next )
+      {
+         if( inf->data_type != k_mdl_128bit_datatype_nothing )
+         {
+            packet->data = inf->data;
+            packet->type = inf->data_type;
+         }
+
+         mdl_node *next = mdl_node_from_id( world->meta, inf->next );
+         packet->location = next->sub_uid;
+         packet->function = inf->function;
+      }
+      else
+         logic_packet_terminate( packet );
+   }
+   else if( packet->function == 1 )    /* TODO enable */
+   {
+      logic_packet_terminate( packet );
+   }
+   else if( packet->function == 2 )    /* TODO disable */
+   {
+      logic_packet_terminate( packet );
+   }
+   else
+   {
+      vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void logic_chances_call( world_instance *world,
+                                   struct logic_brick_ref *ref,
+                                   logic_packet *packet )
+{
+   struct classtype_logic_chances *inf = 
+      mdl_get_entdata( world->meta, ref->node );
+
+   if( packet->function == 0 )      /* pass along */
+   {
+      int red = 1;
+
+      if( vg_randf() > inf->p )
+         red = 0;
+
+      if( inf->targets[red] )
+      {
+         mdl_node *pnext = mdl_node_from_id( world->meta, inf->targets[red] );
+
+         if( pnext->classtype == k_classtype_logic_wire )
+         {
+            packet->location = pnext->sub_uid;
+         }
+         else
+         {
+            vg_error( "[INVALID TARGET] logic_chances:pass( ... )\n" );
+            vg_warn(  "   target[%d] must be classtype logic_wire\n", red );
+            logic_packet_terminate( packet );
+         }
+      }
+      else
+      {
+         logic_packet_terminate( packet );
+      }
+   }
+   else if( packet->function == 1 ) /* set ratio */
+   {
+      if( packet->type == k_mdl_128bit_datatype_number )
+      {
+         inf->p = packet->data._f32;
+      }
+      else
+      {
+         vg_error( "[INVALID ARGUMENT] logic_chances:set_ratio( f32 p )\n" );
+      }
+
+      logic_packet_terminate( packet );
+   }
+   else
+   {
+      vg_error( "[INVALID FUNCTION] logic_chances:[%u]\n", packet->function );
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void logic_soundscape_call( world_instance *world,
+                                      struct logic_brick_ref *ref,
+                                      logic_packet *packet )
+{
+   struct classtype_soundscape *inf = mdl_get_entdata( world->meta, ref->node );
+   struct soundscape *soundscape = &world->soundscapes[ ref->internal_id ];
+
+   if( packet->function == 0 )   /* play */
+   {
+      /* TODO: Only spawn within certain range of player */
+
+      if( packet->type != k_mdl_128bit_datatype_target )
+      {
+         vg_error( "[INVALID ARGUMENT] logic_soundscape:play( ref sound )\n" );
+         vg_warn( "  got datatype: %u\n", packet->type );
+         logic_packet_terminate( packet );
+         return;
+      }
+
+      mdl_node *data = mdl_node_from_id( world->meta, packet->data._u32 );
+
+      if( data->classtype != k_classtype_audio )
+      {
+         vg_error( "[INVALID TARGET] logic_soundscape:play( ref sound )\n" );
+         logic_packet_terminate( packet );
+         return;
+      }
+
+      if( soundscape->usage_count < soundscape->max_instances )
+      {
+         struct world_audio_thing *audio = &world->audio_things[data->sub_uid];
+
+
+         for( int i=0; i<soundscape->max_instances; i++ )
+         {
+            if( !soundscape->channels[i] )
+            {
+               audio_lock();
+               soundscape->channels[i] = audio_request_channel(
+                                          &audio->temp_embedded_clip,
+                                           audio->flags );
+
+               if( soundscape->channels[i] )
+               {
+                  if( audio->flags & AUDIO_FLAG_SPACIAL_3D )
+                  {
+                     audio_channel_set_spacial( soundscape->channels[i],
+                                                soundscape->spawn_position,
+                                                audio->range );
+                  }
+
+                  audio_channel_edit_volume( soundscape->channels[i],
+                                             audio->volume,
+                                             1 );
+               }
+
+               audio_unlock();
+
+               soundscape->usage_count ++;
+               break;
+            }
+         }
+
+      }
+
+      logic_packet_terminate( packet );
+   }
+   else if( packet->function == 1 ) /* set position */
+   {
+      if( packet->type != k_mdl_128bit_datatype_vec3 )
+      {
+         vg_error( "[INVALID ARGUMENT] logic_soundscape:position( v3f co )\n" );
+         logic_packet_terminate( packet );
+         return;
+      }
+
+      v3_copy( packet->data._v4f, soundscape->spawn_position );
+      logic_packet_terminate( packet );
+   }
+   else
+   {
+      vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void _logic_trigger_base_call( world_instance *world, u32 target,
+                                         logic_packet *packet )
+{
+   if( packet->function == 0 )         /* pass onwards */
+   {
+      if( target )
+      {
+         mdl_node *next = mdl_node_from_id( world->meta, target );
+         packet->location = next->sub_uid;
+         packet->function = 0; /* always call the default function */
+      }
+      else
+         logic_packet_terminate( packet );
+   }
+   else
+   {
+      vg_error( "[INVALID FUNCTION] logic_trigger:[%u]\n", packet->function );
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void logic_trigger_call( world_instance *world,
+                                   struct logic_brick_ref *ref,
+                                   logic_packet *packet )
+{
+   struct classtype_trigger *inf = mdl_get_entdata( world->meta, ref->node );
+   _logic_trigger_base_call( world, inf->target, packet );
+}
+
+VG_STATIC void logic_particle_call( world_instance *world, 
+                                    struct logic_brick_ref *ref,
+                                    logic_packet *packet )
+{
+   struct classtype_particle_box *inf = 
+      mdl_get_entdata( world->meta, ref->node );
+
+   /* rate of 1.0 means we get one a second or 0.1 per tick */
+
+   if( vg_randf() < inf->rate * 0.1f )
+   {
+      ref->usage += 1.0f;
+      _logic_trigger_base_call( world, inf->target, packet );
+   }
+   else
+   {
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void logic_bricks_send_packet( world_instance *world,
+                                         logic_packet *packet );
+
+VG_STATIC void logic_splitter( world_instance *world,
+                               struct logic_brick_ref *ref,
+                               logic_packet *packet )
+{
+   struct classtype_signal_splitter *inf 
+      = mdl_get_entdata( world->meta, ref->node );
+
+   if( packet->function == 0 )         /* pass onwards */
+   {
+      for( int i=0; i<4; i++ )
+      {
+         if( inf->next[i] )
+         {
+            logic_packet copy = *packet;
+
+            mdl_node *next = mdl_node_from_id( world->meta, inf->next[i] );
+            copy.location = next->sub_uid;
+            copy.function = 0; /* always call the default function */
+
+            logic_bricks_send_packet( world, &copy );
+         }
+      }
+
+      logic_packet_terminate( packet );
+   }
+   else
+   {
+      vg_error( "[INVALID FUNCTION] logic_splitter:[%u]\n", packet->function );
+      logic_packet_terminate( packet );
+   }
+}
+
+VG_STATIC void logic_bricks_send_packet( world_instance *world,
+                                         logic_packet *packet )
+{
+   while( packet->location != 0xffffffff )
+   {
+      struct logic_brick_ref *ref = &world->logic_bricks[ packet->location ];
+      enum classtype type = ref->node->classtype;
+
+      if( type == k_classtype_logic_wire )
+      {
+         logic_wire_call( world, ref, packet );
+      }
+      else if( type == k_classtype_logic_chances )
+      {
+         logic_chances_call( world, ref, packet );
+      }
+      else if( type == k_classtype_soundscape )
+      {
+         logic_soundscape_call( world, ref, packet );
+      }
+      else if( type == k_classtype_trigger )
+      {
+         logic_trigger_call( world, ref, packet );
+      }
+      else if( type == k_classtype_particle_box )
+      {
+         logic_particle_call( world, ref, packet );
+         continue;
+      }
+      else if( type == k_classtype_signal_splitter )
+      {
+         logic_splitter( world, ref, packet );
+      }
+      else
+      {
+         vg_error( "Undefined logic brick (entity type %d)\n", type );
+         logic_packet_terminate( packet );
+      }
+
+      ref->usage += 1.0f;
+   }
+}
+
+VG_STATIC void logic_bricks_world_gen_allocate( world_instance *world )
+{
+   /* REVISION: unify allocations, loaders and extensions for entities.
+    *           we currently seem to do every which entity a different way */
+
+   world->logic_brick_count = 0;
+   world->logic_bricks = NULL;
+   world->soundscape_count = 0;
+   world->trigger_count = 0;
+
+   for( int i=0; i<world->meta->info.node_count; i++ )
+   {
+      mdl_node *pnode = mdl_node_from_id( world->meta, i );
+
+      if( pnode->classtype == k_classtype_logic_wire ||
+          pnode->classtype == k_classtype_logic_chances ||
+          pnode->classtype == k_classtype_soundscape ||
+          pnode->classtype == k_classtype_trigger ||
+          pnode->classtype == k_classtype_particle_box ||
+          pnode->classtype == k_classtype_signal_splitter )
+      {
+         world->logic_bricks = 
+            vg_linear_extend( world_global.generic_heap, 
+                              world->logic_bricks,
+                              sizeof( struct logic_brick_ref ) );
+
+         pnode->sub_uid = world->logic_brick_count;
+
+         struct logic_brick_ref *ref = 
+            &world->logic_bricks[ world->logic_brick_count ];
+         ref->node = pnode;
+         ref->internal_id = 0;
+
+         if( pnode->classtype == k_classtype_soundscape )
+         {
+            u32 id = world->soundscape_count;
+
+            struct soundscape *soundscape = &world->soundscapes[ id ];
+
+            struct classtype_soundscape *inf =
+               mdl_get_entdata( world->meta, pnode );
+
+            soundscape->label = mdl_pstr( world->meta, inf->label );
+            soundscape->max_instances = inf->max_instances;
+            soundscape->allow_transitions = inf->allow_transitions;
+            soundscape->transition_duration = inf->transition_duration;
+            v3_copy( pnode->co, soundscape->spawn_position );
+
+            ref->internal_id = id;
+            world->soundscape_count ++;
+         }
+         else if( pnode->classtype == k_classtype_trigger ||
+                  pnode->classtype == k_classtype_particle_box )
+         {
+            u32 id = world->trigger_count;
+            struct trigger_zone *trigger = &world->triggers[ id ];
+
+            mdl_node_transform( pnode, trigger->transform );
+            m4x3_invert_full( trigger->transform, trigger->inv_transform );
+            trigger->target_logic_brick = world->logic_brick_count;
+            trigger->classtype = pnode->classtype;
+
+            world->trigger_count ++;
+         }
+
+         world->logic_brick_count ++;
+      }
+   }
+}
+
+#endif /* WORLD_LOGIC_BRICKS_H */