nonlocal stuff again
[carveJwlIkooP6JGAAIwe30JlM.git] / world_logic_bricks.h
1 #include "common.h"
2
3 #ifndef WORLD_LOGIC_BRICKS_H
4 #define WORLD_LOGIC_BRICKS_H
5
6 #include "world.h"
7
8 #if 0
9
10 typedef struct logic_packet logic_packet;
11 struct logic_packet
12 {
13 u32 location, function;
14 union mdl_128bit_union data;
15 enum mdl_128bit_datatype type;
16 };
17
18 VG_STATIC void logic_bricks_debug_connection( world_instance *world,
19 mdl_node *from, u32 next,
20 v3f colour )
21 {
22 if( next == 0 )
23 return;
24
25 mdl_node *to = mdl_node_from_id( world->meta, next );
26
27 v3f c;
28 float brightness = 0.8f + world->logic_bricks[ from->sub_uid ].usage * 4.0f;
29 v3_muls( colour, brightness, c );
30
31 u32 clamped = 0xff000000;
32
33 for( int i=0; i<3; i++ )
34 {
35 u8 byte = vg_minf( 1.0f, c[i] ) * 255.0f;
36 clamped |= byte << (i*8);
37 }
38
39 vg_line( from->co, to->co, clamped );
40 }
41
42 VG_STATIC void logic_bricks_debug( world_instance *world, v3f pos )
43 {
44 v3f white = {1.0f,1.0f,1.0f},
45 red = {1.0f,0.2f,0.1f},
46 black = {0.2f,0.2f,0.2f};
47
48 glLineWidth( 2.0f );
49
50 for( int i=0; i<world->logic_brick_count; i++ )
51 {
52 struct logic_brick_ref *ref = &world->logic_bricks[i];
53 mdl_node *node = ref->node;
54
55 if( v3_dist2( node->co, pos ) > 50.0f*50.0f )
56 continue;
57
58 void *entdata = mdl_get_entdata( world->meta, node );
59
60 if( ref->node->classtype == k_classtype_logic_wire )
61 {
62 struct classtype_logic_wire *wire = entdata;
63
64 logic_bricks_debug_connection( world, node, wire->next, white );
65 }
66 else if( ref->node->classtype == k_classtype_logic_chances )
67 {
68 struct classtype_logic_chances *chances = entdata;
69
70 logic_bricks_debug_connection(world, node, chances->targets[0], red );
71 logic_bricks_debug_connection(world, node, chances->targets[1], black);
72 }
73 else if( ref->node->classtype == k_classtype_signal_splitter )
74 {
75 struct classtype_signal_splitter *splitter = entdata;
76 logic_bricks_debug_connection( world, node, splitter->next[0], white );
77 logic_bricks_debug_connection( world, node, splitter->next[1], white );
78 logic_bricks_debug_connection( world, node, splitter->next[2], white );
79 logic_bricks_debug_connection( world, node, splitter->next[3], white );
80 }
81 else if( ref->node->classtype == k_classtype_soundscape )
82 {
83 struct classtype_soundscape *inf = entdata;
84 struct soundscape *s = &world->soundscapes[ ref->internal_id ];
85
86 v3f co;
87 v3_copy( ref->node->co, co );
88
89 boxf box;
90 box[0][0] = co[0]-0.12f;
91 box[0][1] = co[1]-0.12f;
92 box[0][2] = co[2]-0.12f;
93 box[1][0] = co[0]+0.12f;
94 box[1][1] = co[1]+0.12f + 0.1f*(float)inf->max_instances;
95 box[1][2] = co[2]+0.12f;
96
97 vg_line_boxf( box, VG__WHITE );
98
99 for( int i=0; i<s->usage_count; i++ )
100 {
101 vg_line_pt3( co, 0.09f, VG__GREEN );
102 co[1] += 0.2f;
103 }
104 }
105 else if( ref->node->classtype == k_classtype_trigger )
106 {
107 struct classtype_trigger *trigger = entdata;
108 logic_bricks_debug_connection( world, node, trigger->target, white );
109 }
110 else if( ref->node->classtype == k_classtype_particle_box )
111 {
112 struct classtype_particle_box *pb = entdata;
113 logic_bricks_debug_connection( world, node, pb->target, white );
114 }
115
116 ref->usage *= vg_maxf( 0.0f, 1.0f-vg.time_delta*5.0f );
117 }
118 }
119
120 VG_STATIC void logic_packet_terminate( logic_packet *packet )
121 {
122 packet->location = 0xffffffff;
123 }
124
125 VG_STATIC void logic_wire_call( world_instance *world,
126 struct logic_brick_ref *ref,
127 logic_packet *packet )
128 {
129 struct classtype_logic_wire *inf = mdl_get_entdata( world->meta, ref->node );
130
131 if( packet->function == 0 ) /* pass onwards */
132 {
133 if( inf->next )
134 {
135 if( inf->data_type != k_mdl_128bit_datatype_nothing )
136 {
137 packet->data = inf->data;
138 packet->type = inf->data_type;
139 }
140
141 mdl_node *next = mdl_node_from_id( world->meta, inf->next );
142 packet->location = next->sub_uid;
143 packet->function = inf->function;
144 }
145 else
146 logic_packet_terminate( packet );
147 }
148 else if( packet->function == 1 ) /* TODO enable */
149 {
150 logic_packet_terminate( packet );
151 }
152 else if( packet->function == 2 ) /* TODO disable */
153 {
154 logic_packet_terminate( packet );
155 }
156 else
157 {
158 vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
159 logic_packet_terminate( packet );
160 }
161 }
162
163 VG_STATIC void logic_chances_call( world_instance *world,
164 struct logic_brick_ref *ref,
165 logic_packet *packet )
166 {
167 struct classtype_logic_chances *inf =
168 mdl_get_entdata( world->meta, ref->node );
169
170 if( packet->function == 0 ) /* pass along */
171 {
172 int red = 1;
173
174 if( vg_randf() > inf->p )
175 red = 0;
176
177 if( inf->targets[red] )
178 {
179 mdl_node *pnext = mdl_node_from_id( world->meta, inf->targets[red] );
180
181 if( (pnext->classtype == k_classtype_logic_wire) ||
182 (pnext->classtype == k_classtype_logic_chances) ||
183 (pnext->classtype == k_classtype_signal_splitter) )
184 {
185 packet->location = pnext->sub_uid;
186 }
187 else
188 {
189 vg_error( "[INVALID TARGET] logic_chances:pass( ... )\n" );
190 vg_warn( " target[%d] must be classtype logic_wire\n", red );
191 logic_packet_terminate( packet );
192 }
193 }
194 else
195 {
196 logic_packet_terminate( packet );
197 }
198 }
199 else if( packet->function == 1 ) /* set ratio */
200 {
201 if( packet->type == k_mdl_128bit_datatype_number )
202 {
203 inf->p = packet->data._f32;
204 }
205 else
206 {
207 vg_error( "[INVALID ARGUMENT] logic_chances:set_ratio( f32 p )\n" );
208 }
209
210 logic_packet_terminate( packet );
211 }
212 else
213 {
214 vg_error( "[INVALID FUNCTION] logic_chances:[%u]\n", packet->function );
215 logic_packet_terminate( packet );
216 }
217 }
218
219 VG_STATIC void logic_soundscape_call( world_instance *world,
220 struct logic_brick_ref *ref,
221 logic_packet *packet )
222 {
223 struct classtype_soundscape *inf = mdl_get_entdata( world->meta, ref->node );
224 struct soundscape *soundscape = &world->soundscapes[ ref->internal_id ];
225
226 if( packet->function == 0 ) /* play */
227 {
228 /* TODO: Only spawn within certain range of player */
229
230 if( packet->type != k_mdl_128bit_datatype_target )
231 {
232 vg_error( "[INVALID ARGUMENT] logic_soundscape:play( ref sound )\n" );
233 vg_warn( " got datatype: %u\n", packet->type );
234 logic_packet_terminate( packet );
235 return;
236 }
237
238 mdl_node *data = mdl_node_from_id( world->meta, packet->data._u32 );
239
240 if( data->classtype != k_classtype_audio )
241 {
242 vg_error( "[INVALID TARGET] logic_soundscape:play( ref sound )\n" );
243 logic_packet_terminate( packet );
244 return;
245 }
246
247 if( soundscape->usage_count < soundscape->max_instances )
248 {
249 struct world_audio_thing *audio = &world->audio_things[data->sub_uid];
250
251
252 for( int i=0; i<soundscape->max_instances; i++ )
253 {
254 if( !soundscape->channels[i] )
255 {
256 audio_lock();
257 soundscape->channels[i] = audio_request_channel(
258 &audio->temp_embedded_clip,
259 audio->flags );
260
261 if( soundscape->channels[i] )
262 {
263 if( audio->flags & AUDIO_FLAG_SPACIAL_3D )
264 {
265 audio_channel_set_spacial( soundscape->channels[i],
266 soundscape->spawn_position,
267 audio->range );
268 }
269
270 audio_channel_edit_volume( soundscape->channels[i],
271 audio->volume,
272 1 );
273 }
274
275 audio_unlock();
276
277 soundscape->usage_count ++;
278 break;
279 }
280 }
281
282 }
283
284 logic_packet_terminate( packet );
285 }
286 else if( packet->function == 1 ) /* set position */
287 {
288 if( packet->type != k_mdl_128bit_datatype_vec3 )
289 {
290 vg_error( "[INVALID ARGUMENT] logic_soundscape:position( v3f co )\n" );
291 logic_packet_terminate( packet );
292 return;
293 }
294
295 v3_copy( packet->data._v4f, soundscape->spawn_position );
296 logic_packet_terminate( packet );
297 }
298 else
299 {
300 vg_error( "[INVALID FUNCTION] logic_wire:[%u]\n", packet->function );
301 logic_packet_terminate( packet );
302 }
303 }
304
305 VG_STATIC void _logic_trigger_base_call( world_instance *world, u32 target,
306 logic_packet *packet )
307 {
308 if( packet->function == 0 ) /* pass onwards */
309 {
310 if( target )
311 {
312 mdl_node *next = mdl_node_from_id( world->meta, target );
313 packet->location = next->sub_uid;
314 packet->function = 0; /* always call the default function */
315 }
316 else
317 logic_packet_terminate( packet );
318 }
319 else
320 {
321 vg_error( "[INVALID FUNCTION] logic_trigger:[%u]\n", packet->function );
322 logic_packet_terminate( packet );
323 }
324 }
325
326 VG_STATIC void logic_trigger_call( world_instance *world,
327 struct logic_brick_ref *ref,
328 logic_packet *packet )
329 {
330 struct classtype_trigger *inf = mdl_get_entdata( world->meta, ref->node );
331 _logic_trigger_base_call( world, inf->target, packet );
332 }
333
334 VG_STATIC void logic_particle_call( world_instance *world,
335 struct logic_brick_ref *ref,
336 logic_packet *packet )
337 {
338 struct classtype_particle_box *inf =
339 mdl_get_entdata( world->meta, ref->node );
340
341 /* rate of 1.0 means we get one a second or 0.1 per tick */
342
343 if( vg_randf() < inf->rate * 0.1f )
344 {
345 ref->usage += 1.0f;
346 _logic_trigger_base_call( world, inf->target, packet );
347 }
348 else
349 {
350 logic_packet_terminate( packet );
351 }
352 }
353
354 VG_STATIC void logic_bricks_send_packet( world_instance *world,
355 logic_packet *packet );
356
357 VG_STATIC void logic_splitter( world_instance *world,
358 struct logic_brick_ref *ref,
359 logic_packet *packet )
360 {
361 struct classtype_signal_splitter *inf
362 = mdl_get_entdata( world->meta, ref->node );
363
364 if( packet->function == 0 ) /* pass onwards */
365 {
366 for( int i=0; i<4; i++ )
367 {
368 if( inf->next[i] )
369 {
370 logic_packet copy = *packet;
371
372 mdl_node *next = mdl_node_from_id( world->meta, inf->next[i] );
373 copy.location = next->sub_uid;
374 copy.function = 0; /* always call the default function */
375
376 logic_bricks_send_packet( world, &copy );
377 }
378 }
379
380 logic_packet_terminate( packet );
381 }
382 else
383 {
384 vg_error( "[INVALID FUNCTION] logic_splitter:[%u]\n", packet->function );
385 logic_packet_terminate( packet );
386 }
387 }
388
389 VG_STATIC void logic_bricks_send_packet( world_instance *world,
390 logic_packet *packet )
391 {
392 while( packet->location != 0xffffffff )
393 {
394 struct logic_brick_ref *ref = &world->logic_bricks[ packet->location ];
395 enum classtype type = ref->node->classtype;
396
397 if( type == k_classtype_logic_wire )
398 {
399 logic_wire_call( world, ref, packet );
400 }
401 else if( type == k_classtype_logic_chances )
402 {
403 logic_chances_call( world, ref, packet );
404 }
405 else if( type == k_classtype_soundscape )
406 {
407 logic_soundscape_call( world, ref, packet );
408 }
409 else if( type == k_classtype_trigger )
410 {
411 logic_trigger_call( world, ref, packet );
412 }
413 else if( type == k_classtype_particle_box )
414 {
415 logic_particle_call( world, ref, packet );
416 continue;
417 }
418 else if( type == k_classtype_signal_splitter )
419 {
420 logic_splitter( world, ref, packet );
421 }
422 else
423 {
424 vg_error( "Undefined logic brick (entity type %d)\n", type );
425 logic_packet_terminate( packet );
426 }
427
428 ref->usage += 1.0f;
429 }
430 }
431
432 VG_STATIC void logic_bricks_world_gen_allocate( world_instance *world )
433 {
434 /* REVISION: unify allocations, loaders and extensions for entities.
435 * we currently seem to do every which entity a different way */
436
437 world->logic_brick_count = 0;
438 world->logic_bricks = NULL;
439 world->soundscape_count = 0;
440 world->trigger_count = 0;
441
442 for( int i=0; i<world->meta->info.node_count; i++ )
443 {
444 mdl_node *pnode = mdl_node_from_id( world->meta, i );
445
446 if( pnode->classtype == k_classtype_logic_wire ||
447 pnode->classtype == k_classtype_logic_chances ||
448 pnode->classtype == k_classtype_soundscape ||
449 pnode->classtype == k_classtype_trigger ||
450 pnode->classtype == k_classtype_particle_box ||
451 pnode->classtype == k_classtype_signal_splitter )
452 {
453 world->logic_bricks =
454 vg_linear_extend( world_global.generic_heap,
455 world->logic_bricks,
456 sizeof( struct logic_brick_ref ) );
457
458 pnode->sub_uid = world->logic_brick_count;
459
460 struct logic_brick_ref *ref =
461 &world->logic_bricks[ world->logic_brick_count ];
462 ref->node = pnode;
463 ref->internal_id = 0;
464
465 if( pnode->classtype == k_classtype_soundscape )
466 {
467 u32 id = world->soundscape_count;
468
469 struct soundscape *soundscape = &world->soundscapes[ id ];
470
471 struct classtype_soundscape *inf =
472 mdl_get_entdata( world->meta, pnode );
473
474 soundscape->label = mdl_pstr( world->meta, inf->label );
475 soundscape->max_instances = inf->max_instances;
476 soundscape->allow_transitions = inf->allow_transitions;
477 soundscape->transition_duration = inf->transition_duration;
478 v3_copy( pnode->co, soundscape->spawn_position );
479
480 ref->internal_id = id;
481 world->soundscape_count ++;
482 }
483 else if( pnode->classtype == k_classtype_trigger ||
484 pnode->classtype == k_classtype_particle_box )
485 {
486 u32 id = world->trigger_count;
487 struct trigger_zone *trigger = &world->triggers[ id ];
488
489 mdl_node_transform( pnode, trigger->transform );
490 m4x3_invert_full( trigger->transform, trigger->inv_transform );
491 trigger->target_logic_brick = world->logic_brick_count;
492 trigger->classtype = pnode->classtype;
493
494 world->trigger_count ++;
495 }
496
497 world->logic_brick_count ++;
498 }
499 }
500 }
501
502 #endif
503
504
505
506
507
508 #endif /* WORLD_LOGIC_BRICKS_H */