source: golgotha/src/golg/g1_object.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 11 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 32.9 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "g1_object.hh"
10#include "obj3d.hh"
11#include "load3d.hh"
12#include "error/alert.hh"
13#include "memory/malloc.hh"
14#include "objs/model_id.hh"
15#include "error/error.hh"
16#include "math/angle.hh"
17#include "saver.hh"
18#include "map.hh"
19#include "map_man.hh"
20#include "map_cell.hh"
21#include "m_flow.hh"
22#include "light.hh"
23#include "objs/map_piece.hh"
24#include "g1_render.hh"
25#include "objs/stank.hh"
26#include "player.hh"
27#include "lisp/li_class.hh"
28#include "lisp/li_dialog.hh"
29#include "lisp/li_load.hh"
30#include "lisp/li_init.hh"
31#include "file/ram_file.hh"
32#include "li_objref.hh"
33#include "objs/damager.hh"
34#include "time/profile.hh"
35#include "controller.hh"
36#include "objs/explode_model.hh"
37#include "sound/sfx_id.hh"
38#include "objs/explosion1.hh"
39#include "objs/chunk_explosion.hh"
40#include "math/random.hh"
41#include "objs/model_collide.hh"
42#include "resources.hh"
43#include "objs/crate.hh"
44#include "g1_rand.hh"
45
46enum {
47  OLD_DATA_VERSION_2=2,
48  OLD_DATA_VERSION_3,
49  OLD_DATA_VERSION_4,          // includes movie path follow info
50  OLD_DATA_VERSION_5,          // "improved" occupied_squares handling
51  OLD_DATA_VERSION_6,          // doesn't save last position or movie path, saves flags as w32
52  OLD_DATA_VERSION_7,          // saves global_id
53  OLD_DATA_VERSION_8,          // saves 'vars'
54  DATA_VERSION                 // saves 'health'
55};
56
57S1_SFX(explosion_ground_vehicle, "explosion/ground_vehicle.wav", S1_3D, 20);
58
59static li_symbol_ref vortex("vortex"), explosion1("explosion1");
60static li_symbol_ref explode_model("explode_model"), chunk_explosion("chunk_explosion");
61static g1_explode_params def_params;
62
63li_symbol_ref g1_crate("crate");
64i4_profile_class   pf_unoccupy_location("unoccupy_location");
65
66g1_object_type g1_last_object_type=-1;  // largest object number assigned
67g1_object_definition_class *g1_object_type_array[G1_MAX_OBJECT_TYPES];
68// registered object definitions (starts at 1, since 0 is used for invalid entries)
69
70
71
72
73void g1_object_class::draw(g1_draw_context_class *context)
74{
75  g1_model_draw(this, draw_params, context);
76}
77
78
79i4_float g1_object_class::occupancy_radius() const
80{
81  if (draw_params.model)
82    return draw_params.model->extent;
83  else
84    return 0;
85}
86
87i4_window_class *g1_object_definition_class::create_edit_dialog()
88{
89  w32 selected_objects[G1_MAX_OBJECTS];
90  int t_sel=g1_get_map()->make_selected_objects_list(selected_objects, G1_MAX_OBJECTS);
91
92  if (t_sel==1)
93  {
94    g1_object_class *go=g1_global_id.get(selected_objects[0]);
95
96    if (go->vars && li_get_type(go->vars->type())->editor)
97    {     
98      li_function_type fun=li_function::get(li_get_fun(li_get_symbol("object_changed"),0),0)->value();
99
100      return new li_dialog_window_class(go->name(),
101                                        go->vars,
102                                        0,fun,0);
103    }
104  }
105
106  return 0;
107}
108
109g1_damage_map_struct *g1_object_definition_class::get_damage_map()
110{
111  if (!damage)
112  {
113    damage=g1_find_damage_map(type);
114    if (!damage)
115    {
116      i4_warning("damage map missing %s, using default", name());
117      damage=g1_find_damage_map(0);
118      if (!damage)
119        i4_error("no default");
120    }
121  }
122 
123  return damage;
124}
125
126g1_object_definition_class::g1_object_definition_class(char *_name,
127                                                       w32 type_flags,
128                                                       function_type _init,
129                                                       function_type _uninit)
130  : _name(_name),
131    init_function(_init), uninit_function(_uninit)
132{
133  flags=type_flags;
134
135  type = g1_add_object_type(this);
136  vars=0;
137  var_class=0;
138  damage=0;
139}
140
141void g1_object_definition_class::init()
142{
143  char buf[200];
144  sprintf(buf,"%s_vars", _name);
145  if (li_find_symbol(buf))
146    var_class=li_find_type(buf, 0);
147  else if (flags & TO_MAP_PIECE)
148    var_class=li_find_type("map_piece_vars");
149  else
150    var_class=0;
151
152  sprintf(buf,"%s_type_vars", _name);
153  if (li_find_symbol(buf))
154  {
155    int type_vars_type=li_find_type(buf);
156    if (type_vars_type)
157      vars=li_class::get(li_get_type(type_vars_type)->create(0,0),0);
158    else
159      vars=0;
160  }
161  else vars=0;
162
163  defaults=g1_get_object_defaults(_name, i4_F);
164 
165  if (init_function)
166    (*init_function)();
167
168}
169
170const char *g1_object_class::name() const
171{
172  return g1_object_type_array[id]->name();
173}
174
175
176i4_bool g1_object_class::out_of_bounds(i4_float x, i4_float y) const
177{
178  return (x<0 || x>=g1_get_map()->width() || y<0 || y>=g1_get_map()->height());
179}
180
181
182void g1_object_class::change_player_num(int new_player)
183{
184  if (new_player!=player_num)
185  {
186    g1_player_man.get(player_num)->remove_object(global_id);
187    player_num=new_player;
188    g1_player_man.get(new_player)->add_object(global_id);
189  }
190}
191
192g1_team_type g1_object_class::get_team() const
193{
194  return g1_player_man.get(player_num)->get_team();
195}
196
197
198void g1_object_class::grab_old()     // grab info about the current tick for interpolation
199{
200  lx=x;
201  ly=y;
202  lh=h;
203  ltheta = theta;
204  lpitch = pitch;
205  lroll  = roll;
206  for (w32 i=0;i<num_mini_objects;i++)
207    mini_objects[i].grab_old();
208}
209
210
211void g1_object_class::save(g1_saver_class *fp)
212{
213  fp->start_version(DATA_VERSION);
214
215  li_save_object(fp, vars,0);
216
217  if (!fp->write_global_id(global_id))
218    i4_warning("I'm invalid!?!?!  Help me!!!!\n");
219
220  w32 save_flags = flags & SAVE_FLAGS;
221  fp->write_format("ffffff421",
222                   &x,&y,&h,
223                   &theta, &pitch, &roll,
224                   &save_flags, &health, &player_num);
225  fp->end_version();
226}
227
228
229void g1_object_class::load_v9(g1_loader_class *fp)
230{
231  vars=(li_class *)li_load_typed_object(get_type()->var_class, fp, fp->li_remap,0);
232  global_id = fp->read_global_id();
233  g1_global_id.assign(global_id, this);
234
235  fp->read_format("ffffff421",
236                  &x,&y,&h,
237                  &theta, &pitch, &roll,
238                  &flags, &health, &player_num);
239
240#if 0
241  //(OLI) health limiting hack for dave
242  if (health>get_type()->defaults->health)
243    health=get_type()->defaults->health;
244#endif
245
246  g1_object_class::grab_old();
247}
248
249
250void g1_object_class::load_v8(g1_loader_class *fp)
251{
252  vars=(li_class *)li_load_typed_object(get_type()->var_class, fp, fp->li_remap,0);
253  load_v7(fp);
254}
255
256void g1_object_class::load_v7(g1_loader_class *fp)
257{
258  global_id = fp->read_global_id();
259  g1_global_id.assign(global_id, this);
260
261  x=lx=fp->read_float();
262  y=ly=fp->read_float();
263  h=lh=fp->read_float();
264  theta=ltheta=fp->read_float();
265  pitch=lpitch=fp->read_float();
266  roll=lroll=fp->read_float();
267  flags=fp->read_32();
268 
269  player_num=fp->read_8();   
270}
271
272
273void g1_object_class::load_v6(g1_loader_class *fp)
274{
275  global_id=g1_global_id.alloc(this);
276  x=lx=fp->read_float();
277  y=ly=fp->read_float();
278  h=lh=fp->read_float();
279  theta=ltheta=fp->read_float();
280  pitch=lpitch=fp->read_float();
281  roll=lroll=fp->read_float();
282  flags=fp->read_32();
283 
284  player_num=fp->read_8();   
285}
286
287
288void g1_object_class::load_v5(g1_loader_class *fp)
289{
290  global_id=g1_global_id.alloc(this);
291  fp->read_16();    // id - load removed... why was it there? -jc
292  fp->read_16();    // draw_id -load removed.. why was it there? -jc
293
294
295  fp->read_16();
296  fp->read_16();
297 
298  x=fp->read_float();
299  lx=fp->read_float();
300
301  y=fp->read_float();
302  ly=fp->read_float();
303
304  h=fp->read_float();
305  lh=fp->read_float();
306 
307  theta=fp->read_float();
308  ltheta=fp->read_float();
309     
310  pitch  = fp->read_float();
311  lpitch = fp->read_float();
312  roll   = fp->read_float();
313  lroll  = fp->read_float();
314 
315  player_num=fp->read_8();
316
317  if (player_num >= G1_MAX_PLAYERS)
318    player_num = g1_default_player;
319
320
321  flags=fp->read_8();
322
323  w8 t_scene_refs=fp->read_8();
324  if (t_scene_refs)
325  {
326    for (int i=0; i<t_scene_refs; i++)
327    {
328      fp->read_8();
329      fp->read_8();
330    }
331  }
332}
333
334void g1_object_class::load_v4(g1_loader_class *fp)
335{
336  load_v3(fp);
337  w8 t_scene_refs=fp->read_8();
338  if (t_scene_refs)
339  {
340    for (int i=0; i<t_scene_refs; i++)
341    {
342      fp->read_8();
343      fp->read_8();
344    }
345  }
346}
347
348void g1_object_class::load_v3(g1_loader_class *fp)
349{
350  global_id=g1_global_id.alloc(this);
351  id=fp->read_16();
352  fp->read_16();
353  fp->read_16();
354  fp->read_16();
355 
356  x=fp->read_float();
357  lx=fp->read_float();
358
359  y=fp->read_float();
360  ly=fp->read_float();
361
362  h=fp->read_float();
363  lh=fp->read_float();
364 
365  theta=fp->read_float();
366  ltheta=fp->read_float();
367     
368  pitch  = fp->read_float();
369  lpitch = fp->read_float();
370  roll   = fp->read_float();
371  lroll  = fp->read_float();
372
373  player_num=fp->read_8();
374  if (player_num >= G1_MAX_PLAYERS)
375    player_num = g1_default_player;
376
377  flags=fp->read_8();
378 
379  fp->read_16();
380  fp->read_16();
381  fp->read_16();
382  fp->read_16();
383
384}
385
386void g1_object_class::load_v2(g1_loader_class *fp)
387{
388  global_id=g1_global_id.alloc(this);
389  id=fp->read_16();
390  fp->read_16();
391  fp->read_16();
392  fp->read_16();
393 
394  x=fp->read_float();
395  lx=fp->read_float();
396
397  y=fp->read_float();
398  ly=fp->read_float();
399
400  h=fp->read_float();
401  lh=fp->read_float();
402 
403  theta=fp->read_float();
404  ltheta=fp->read_float();
405
406
407  //the up variable was removed
408  fp->read_float();  // x
409  fp->read_float();  // y
410  fp->read_float();  // z
411
412  pitch  = 0;
413  lpitch = 0;
414  roll   = 0;
415  lroll  = 0;
416
417  player_num=fp->read_8();
418  if (player_num >= G1_MAX_PLAYERS)
419    player_num = g1_default_player;
420
421  flags=fp->read_8();
422 
423  fp->read_16();
424  fp->read_16();
425  fp->read_16();
426  fp->read_16();     
427}
428
429
430g1_object_class::g1_object_class(g1_object_type id,
431                                 g1_loader_class *fp)
432  : id(id), occupied_squares(4,0), vars(0), world_transform(0),
433    mini_objects(0), num_mini_objects(0)
434{
435  w16 ver=0;
436  w16 data_size;
437
438  radar_image=0;
439  radar_type=G1_RADAR_NONE;
440
441  if (fp)
442    fp->get_version(ver,data_size);
443
444  //read in the correct version #
445  switch (ver)
446  {
447    case DATA_VERSION:       load_v9(fp); break; 
448    case OLD_DATA_VERSION_8: load_v8(fp); health=get_type()->defaults->health; break; 
449    case OLD_DATA_VERSION_7: load_v7(fp); health=get_type()->defaults->health; break; 
450    case OLD_DATA_VERSION_6: load_v6(fp); health=get_type()->defaults->health; break; 
451    case OLD_DATA_VERSION_5: load_v5(fp); health=get_type()->defaults->health; break; 
452    case OLD_DATA_VERSION_4: load_v4(fp); health=get_type()->defaults->health; break;
453    case OLD_DATA_VERSION_3: load_v3(fp); health=get_type()->defaults->health; break;
454    case OLD_DATA_VERSION_2: load_v2(fp); health=get_type()->defaults->health; break;
455       
456    default:
457      //if the file has an unrecognized version, seek past it
458      if (fp) fp->seek(fp->tell() + data_size);
459
460      health=get_type()->defaults->health;
461      global_id=g1_global_id.alloc(this);
462      lx=x=g1_get_map()->width()/2;
463      ly=y=g1_get_map()->height()/2;
464      lh=h=0;
465      ltheta=theta=0;
466      player_num=g1_default_player;
467      flags=0;       
468      pitch = roll = lpitch = lroll = 0;
469      break;
470  }
471
472  if (flags & SCRATCH_BIT)
473    i4_error("object created with scratch bit set, shouldn't happen");
474
475  if (fp) fp->end_version(I4_LF);
476
477  //bad lvariable check
478  if (fabs(lx-x)>1) lx=x;
479  if (fabs(ly-y)>1) ly=y;
480  if (fabs(lh-h)>1) lh=h;
481 
482  if (vars==0 && get_type()->var_class)
483    vars=li_class::get(li_get_type(get_type()->var_class)->create(0,0),0);
484}
485
486void g1_object_class::request_think()
487{
488  if (get_flag(THINKING | DELETED)==0)
489  {
490    g1_get_map()->request_think(this);
491    set_flag(THINKING,1);
492  }
493}
494
495void g1_object_class::request_remove()
496{
497  g1_get_map()->request_remove(this);
498}
499
500i4_bool g1_object_class::occupy_location()
501{
502  if (get_flag(MAP_OCCUPIED))
503    i4_error("occupy_location called twice");
504
505  if (get_flag(DELETED))
506    i4_error("occupy_location called on a deleted object!");
507 
508  if (occupancy_radius()<0.6)
509    return occupy_location_corners();
510  else
511    return occupy_location_model(draw_params);
512}
513
514i4_bool g1_object_class::occupy_location_center()
515{
516  g1_map_class *map = g1_get_map();
517  int width=map->width();
518
519  if (!(x>=0 && x<width && y>=0 && y<map->height()))
520  {
521    request_remove();
522    return i4_F;
523  }
524
525  map->add_object(*new_occupied_square(), i4_f_to_i(x), i4_f_to_i(y)); 
526
527  set_flag(MAP_OCCUPIED,1);
528
529  return i4_T;
530}
531
532i4_bool g1_object_class::occupy_location_corners()
533{
534  g1_map_class *map = g1_get_map();
535  int width=map->width();
536
537  // standard occupy location (4 corners)
538  sw32 x_left,x_right,y_top,y_bottom;
539 
540  if (!(x>=0 && x<width && y>=0 && y<map->height()))
541  {
542    request_remove();
543    return i4_F;
544  }
545
546  i4_float rad = occupancy_radius();
547
548
549  x_left   = i4_f_to_i(x-rad); if (x_left<0)                x_left=0;
550  x_right  = i4_f_to_i(x+rad); if (x_right>=map->width())   x_right=map->width()-1;
551  y_top    = i4_f_to_i(y-rad); if (y_top<0)                 y_top=0;
552  y_bottom = i4_f_to_i(y+rad); if (y_bottom>=map->height()) y_bottom=map->height()-1;
553
554  map->add_object(*new_occupied_square(), x_left,y_top); 
555
556  if (x_right != x_left)
557    map->add_object(*new_occupied_square(), x_right, y_top);
558
559  if (y_top != y_bottom)
560  {
561    map->add_object(*new_occupied_square(), x_left, y_bottom);
562
563    if (x_right != x_left)
564      map->add_object(*new_occupied_square(), x_right, y_bottom);
565  }
566
567  set_flag(MAP_OCCUPIED,1);
568
569
570  return i4_T;
571}
572
573i4_bool g1_object_class::occupy_location_model(const g1_model_draw_parameters &draw_params)
574{
575  g1_map_class *map = g1_get_map();
576  int width=map->width();
577
578  i4_transform_class trans;
579  calc_world_transform(1.0, &trans);
580  i4_3d_point_class p;
581  int ix,iy, offset;
582  int i,j;
583
584  g1_quad_object_class *model = draw_params.model;
585  if (!model)
586    return g1_object_class::occupy_location_center();
587
588 
589  g1_vert_class *vert = model->get_verts(draw_params.animation, draw_params.frame);
590
591  // large object occupy - occupy multiple points
592  enum { MAX_SQUARES=50 };
593  w16 sx[MAX_SQUARES], sy[MAX_SQUARES], num_squares=0;
594
595  // build list of occupied squares
596  for (i=0; i<model->num_vertex; i++)
597  {
598    trans.transform(vert->v, p);
599    ix = int(p.x); iy = int(p.y);
600    if (ix<0 || ix>=width || iy<0 || iy>=map->height())
601    {
602      // off the map, remove me!
603      request_remove();
604      return i4_F;
605    }
606   
607    // check for repeats
608    g1_map_cell_class *cell = map->cell(ix,iy);
609    if ((cell->flags & g1_map_cell_class::SCRATCH1)==0)
610    {
611      // nonrepeating square, add it
612      sx[num_squares]=ix; sy[num_squares]=iy;
613      cell->flags |= g1_map_cell_class::SCRATCH1;
614      num_squares++;
615    }
616    vert++;
617  }
618
619  // grow list to required size
620  if (num_squares>occupied_squares.max_size())
621    occupied_squares.resize(num_squares);
622
623    // we assume that the occupied square list is empty, since unoccupy should'be been called
624
625  for (i=0; i<num_squares; i++)
626  {
627    g1_object_chain_class *chn = new_occupied_square();
628    map->add_object(*chn, sx[i], sy[i]); 
629    map->cell(chn->offset)->flags &= ~g1_map_cell_class::SCRATCH1;
630  }
631
632
633  set_flag(MAP_OCCUPIED,1);
634
635
636  return i4_T;
637}
638
639
640
641i4_bool g1_object_class::occupy_location_model_extents(const g1_model_draw_parameters &draw_params)
642{
643  g1_map_class *map = g1_get_map();
644  int width=map->width();
645
646  i4_transform_class trans;
647  calc_world_transform(1.0, &trans);
648  i4_3d_point_class p;
649
650  g1_quad_object_class *model = draw_params.model;
651  if (!model)
652    return g1_object_class::occupy_location_center();
653
654 
655  g1_vert_class *vert = model->get_verts(draw_params.animation, draw_params.frame);
656  float x1=10000,y1=10000,x2=-1,y2=-1;
657
658  // build list of occupied squares
659  for (int i=0; i<model->num_vertex; i++)
660  {
661    trans.transform(vert->v, p);
662    if (p.x<x1) x1=p.x;
663    if (p.y<y1) y1=p.y;
664    if (p.x>x2) x2=p.x;
665    if (p.y>y2) y2=p.y;
666    vert++;
667  }
668 
669  if (x2==-1)
670  {
671    request_remove();
672    return i4_F;
673  }
674
675  int ix1=i4_f_to_i(x1), iy1=i4_f_to_i(y1),
676      ix2=i4_f_to_i(x2), iy2=i4_f_to_i(y2);
677  if (ix1<0) ix1=0;
678  if (iy1<0) iy1=0;
679  if (ix2>=map->width()) ix2=map->width()-1;
680  if (iy2>=map->height()) iy2=map->height()-1;
681 
682
683  int num_squares=(ix2-ix1+1)*(iy2-iy1+1);
684
685  // grow list to required size
686  if (num_squares>occupied_squares.max_size())
687    occupied_squares.resize(num_squares);
688
689    // we assume that the occupied square list is empty, since unoccupy should'be been called
690
691  for (int y=iy1; y<=iy2; y++)
692    for (int x=ix1; x<=ix2; x++)
693    {   
694      g1_object_chain_class *chn = new_occupied_square();
695      map->add_object(*chn, x,y); 
696    }
697 
698
699  set_flag(MAP_OCCUPIED,1);
700
701
702  return i4_T;
703}
704
705
706void g1_object_class::unoccupy_location()
707{
708  pf_unoccupy_location.start();
709 
710  g1_map_class *map = g1_get_map();
711
712  if (!get_flag(MAP_OCCUPIED))
713  {
714    i4_warning("unoccupy_location called twice");
715  }
716
717  set_flag(MAP_OCCUPIED,0);
718
719  I4_ASSERT(x>=0 && x<map->width() && y>=0 && y<map->height(),
720            "Object is off the map");
721
722  for (int i=0; i<occupied_squares.size(); i++)
723    map->remove_object(occupied_squares[i]);
724  occupied_squares.clear();
725
726  pf_unoccupy_location.stop();
727}
728
729//g1_mini_object stuff
730void g1_mini_object::calc_transform(i4_float ratio, i4_transform_class *transform)
731
732  i4_3d_vector          rot, t;
733
734  // interpolated position
735  t.interpolate(i4_3d_vector(lx,ly,lh), i4_3d_vector(x,y,h), ratio);
736  transform->translate(t); 
737
738  // interpolated rotations
739  rot.z = i4_interpolate_angle(lrotation.z,rotation.z,ratio);
740  transform->mult_rotate_z(rot.z);
741
742  rot.y = i4_interpolate_angle(lrotation.y,rotation.y,ratio);
743  transform->mult_rotate_y(rot.y);
744
745  rot.x = i4_interpolate_angle(lrotation.x,rotation.x,ratio);
746  transform->mult_rotate_x(rot.x);
747
748  // interpolated center offset
749  t.interpolate(loffset, offset, ratio);
750  transform->mult_translate(t);
751}
752
753inline void msvc50_hack(i4_transform_class &m1, i4_transform_class *m2, i4_transform_class *m3)
754{
755  m1.multiply((*m2),(*m3));
756}
757
758void g1_mini_object::draw(g1_draw_context_class *context,
759                          i4_transform_class *parent_transform,
760                          g1_screen_box *bound_box,
761                          g1_player_type player_num,
762                          i4_transform_class *use_this_transform,
763                          i4_bool pass_world_space_transform,
764                          i4_bool use_lod_model)
765{
766  if (use_lod_model && lod_model<=0)
767    return;
768
769  g1_quad_object_class *model;
770  if (use_lod_model)
771    model=g1_model_list_man.get_model(lod_model);
772  else
773    model=g1_model_list_man.get_model(defmodeltype);
774 
775  i4_transform_class local_transform;
776 
777  if (use_this_transform==0)
778  {
779    use_this_transform = &local_transform;
780    calc_transform(g1_render.frame_ratio, use_this_transform);
781  }
782 
783  i4_transform_class world_transform;
784 
785  msvc50_hack(world_transform, parent_transform, use_this_transform);
786
787//world_transform.multiply(*parent_world_transform, *use_this_transform);
788  i4_transform_class view_transform;
789
790  msvc50_hack(view_transform, context->transform, use_this_transform);
791
792//view_transform.multiply(*(context->transform),*use_this_transform);
793 
794  g1_render.render_object(model,
795                          &view_transform,
796                          pass_world_space_transform ? &world_transform : 0,
797                          1,
798                          player_num,
799                          0,//_this->frame,
800                          bound_box,
801                          0);
802}
803
804void g1_object_class::mark_as_selected()
805{
806  set_flag(SELECTED,1);
807}
808
809
810void g1_object_class::mark_as_unselected()
811{
812  set_flag(SELECTED,0);
813}
814
815
816//note: must be power of 2
817#define TRIG_TABLE_SIZE 1024
818
819i4_float g1_cos_lookup[TRIG_TABLE_SIZE];
820i4_float g1_sin_lookup[TRIG_TABLE_SIZE];
821
822i4_bool g1_trig_table_init = i4_F;
823
824const i4_float g1_trig_table_factor = (TRIG_TABLE_SIZE>>1) / 3.1415927f;
825const i4_float g1_ootrig_table_factor = 3.1415927f / (TRIG_TABLE_SIZE>>1);
826
827void g1_init_trig_tables()
828{
829  if (!g1_trig_table_init)
830  {
831    g1_trig_table_init = i4_T;
832    w32 i;
833    for (i=0;i<TRIG_TABLE_SIZE;i++)
834    {
835      g1_cos_lookup[i] = cos(i*g1_ootrig_table_factor);
836      g1_sin_lookup[i] = sin(i*g1_ootrig_table_factor);
837    }
838  }
839}
840
841inline sw32 f_to_i(float x)
842
843  sw32 result;
844
845#ifdef WIN32
846
847  _asm {
848    fld       x ;
849    fistp     result ;
850  }
851
852#else
853 
854  result = (sw32)x;
855
856#endif
857
858  return result;
859}
860
861i4_transform_class& i4_transform_class::rotate_x_y_z(i4_float x_rot, i4_float y_rot, i4_float z_rot, i4_bool use_lookup)
862{
863  i4_float cos_x,sin_x,cos_y,sin_y,cos_z,sin_z;
864
865  if (use_lookup)
866  {
867    g1_init_trig_tables();
868    w32 x_l = (f_to_i(x_rot*g1_trig_table_factor)) & (TRIG_TABLE_SIZE-1);
869    w32 y_l = (f_to_i(y_rot*g1_trig_table_factor)) & (TRIG_TABLE_SIZE-1);
870    w32 z_l = (f_to_i(z_rot*g1_trig_table_factor)) & (TRIG_TABLE_SIZE-1);
871 
872    cos_x=g1_cos_lookup[x_l];
873    sin_x=g1_sin_lookup[x_l];
874    cos_y=g1_cos_lookup[y_l];
875    sin_y=g1_sin_lookup[y_l];
876    cos_z=g1_cos_lookup[z_l];
877    sin_z=g1_sin_lookup[z_l];
878  }
879  else
880  {
881    cos_x=cos(x_rot);
882    sin_x=sin(x_rot);
883    cos_y=cos(y_rot);
884    sin_y=sin(y_rot);
885    cos_z=cos(z_rot);
886    sin_z=sin(z_rot);
887  }
888
889  x.x = cos_z*cos_y;
890  x.y = sin_z*cos_y;
891  x.z = -sin_y;
892
893  y.x = cos_z*sin_y*sin_x - sin_z*cos_x;
894  y.y = sin_z*sin_y*sin_x + cos_z*cos_x;
895  y.z = cos_y*sin_x;
896
897  z.x = cos_z*sin_y*cos_x + sin_z*sin_x;
898  z.y = sin_z*sin_y*cos_x - cos_z*sin_x;
899  z.z = cos_y*cos_x;
900
901  t.set (0,0,0);
902  return *this;
903}
904
905
906float g1_object_class::height_above_ground()
907{
908  return h-g1_get_map()->terrain_height(x,y);
909}
910
911void g1_object_class::calc_world_transform(i4_float ratio, i4_transform_class *transform)
912{
913  if (!transform)
914    transform = world_transform;
915
916  i4_float z_rot = i4_interpolate_angle(ltheta,theta, ratio);
917  i4_float y_rot = i4_interpolate_angle(lpitch,pitch, ratio);
918  i4_float x_rot = i4_interpolate_angle(lroll ,roll , ratio);
919
920  i4_3d_vector t;
921  t.interpolate(i4_3d_vector(lx,ly,lh), i4_3d_vector(x,y,h), ratio);
922
923  transform->translate(t); 
924  transform->mult_rotate_z(z_rot);
925  transform->mult_rotate_y(y_rot);
926  transform->mult_rotate_x(x_rot);
927}
928
929g1_object_class::~g1_object_class()
930{
931  if (mini_objects)
932  {
933    i4_free(mini_objects);
934    mini_objects = 0;
935  }
936 
937  g1_global_id.free(global_id);
938}
939
940// this is the call to add a new object_type to the game.
941g1_object_type g1_add_object_type(g1_object_definition_class *def)
942{
943  for (int i=1; i<G1_MAX_OBJECT_TYPES; i++)
944  {
945    if (g1_object_type_array[i]==0)
946    {
947      if (i>g1_last_object_type)
948        g1_last_object_type=i;
949
950      g1_object_type_array[i]=def;
951      return i;
952    }
953  }
954
955  i4_error("Object type limit exceeded (%d)",G1_MAX_OBJECT_TYPES);
956  return 0;
957}
958
959g1_object_type g1_get_object_type(const char *name)
960{
961  return g1_get_object_type(li_get_symbol(name));
962}
963
964g1_object_type g1_get_object_type(li_symbol *name)
965{
966  li_object *o=li_get_value(name);
967  if (o)
968    return li_int::get(o,0)->value();
969  else
970    return 0;
971}
972
973void g1_remove_object_type(g1_object_type type)
974{
975  I4_ASSERT(type!=0, "tried to remove invalid object");
976
977  if (g1_map_is_loaded())
978  {
979    g1_map_class *map=g1_get_map();
980    map->remove_object_type(type);
981  }
982
983  g1_object_type_array[type]=0;
984  while (g1_last_object_type>=0 && g1_object_type_array[g1_last_object_type]==0)
985    g1_last_object_type--;
986}
987
988void g1_initialize_loaded_objects()
989{
990  int i;
991 
992  for (i=1; i<G1_MAX_OBJECT_TYPES; i++)
993    if (g1_object_type_array[i])
994      li_set_value(li_get_symbol(g1_object_type_array[i]->name()), new li_int(i));
995           
996  for (i=1; i<G1_MAX_OBJECT_TYPES; i++)
997  {
998    if (g1_object_type_array[i])
999      g1_object_type_array[i]->init();
1000  }
1001}
1002
1003
1004void g1_uninitialize_loaded_objects()
1005{
1006  for (int i=1; i<G1_MAX_OBJECT_TYPES; i++)
1007  {
1008    if (g1_object_type_array[i])
1009    {
1010      g1_object_type_array[i]->uninit();
1011      g1_object_type_array[i]=0;
1012    }
1013  }
1014}
1015
1016i4_str *g1_object_class::get_context_string()
1017{
1018  char buf[101];
1019  i4_ram_file_class rf(buf,100);
1020  rf.printf("%s", name());
1021  if (vars)
1022    li_printf(&rf, " %O", vars);
1023
1024  buf[rf.tell()]=0;
1025  return new i4_str(buf);
1026}
1027
1028void g1_object_class::stop_thinking()
1029{
1030  if (get_flag(THINKING))
1031  {
1032    //clears this object out of the think que
1033    if (g1_get_map())
1034      g1_get_map()->remove_from_think_list(this);
1035   
1036    //clears the THINKING flag
1037    set_flag(THINKING,0);
1038  }
1039}
1040
1041// will mark all the objects & object types in the game
1042class g1_object_marker_class : li_gc_object_marker_class
1043{
1044public:
1045  virtual void mark_objects(int set)
1046  {
1047    int i;
1048
1049    for (i=0; i<=g1_last_object_type; i++)   
1050      if (g1_object_type_array[i])
1051      {
1052        li_class *v=g1_object_type_array[i]->vars;
1053        if (v)
1054        {
1055          if (v->is_marked()!=set)
1056            li_get_type(v->unmarked_type())->mark(v, set);
1057        }
1058      }
1059
1060
1061    for (i=0; i<G1_MAX_OBJECTS; i++)
1062    {
1063      g1_object_class *o=g1_global_id.get(i);
1064      if (!g1_global_id.preassigned(i) && ((w32)o>G1_MAX_OBJECTS))
1065      {
1066        li_class *c=o->vars;
1067
1068        if (c && c->is_marked()!=set)
1069          li_get_type(c->unmarked_type())->mark(c, set);
1070      }
1071    }
1072
1073  }
1074} g1_object_marker;
1075
1076
1077void g1_object_class::editor_draw(g1_draw_context_class *context)
1078{
1079  if (vars)
1080  {
1081    w32 colors[]={0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0x00ffff, 0xff00ff, 0xffffff};
1082    int color_on=0;
1083    li_type_number type=vars->type();
1084    int tvars=li_class_total_members(type);
1085
1086    for (int j=0; j<tvars; j++)
1087    {
1088      li_object *v=li_class_get_default(type, li_class_get_symbol(type,j));
1089      if (v && v->type()==li_g1_ref_type_number)
1090      {
1091        li_g1_ref::get(vars->value(j),0)->draw(this, colors[color_on], context);
1092        if (color_on<6)
1093          color_on++;
1094      }
1095      else if (v && v->type()==li_g1_ref_list_type_number)
1096      {
1097        li_g1_ref_list *r=li_g1_ref_list::get(vars->value(j),0);
1098        r->draw(this, colors[color_on], context);                     
1099        if (color_on<6)
1100          color_on++;
1101      }
1102    }
1103  } 
1104}
1105
1106
1107static li_symbol_ref acid("acid");
1108
1109i4_bool g1_object_class::check_collision(const i4_3d_vector &start,
1110                                         i4_3d_vector &ray)
1111{
1112  i4_3d_vector normal;
1113  if (occupancy_radius()<0.5)
1114    return g1_model_collide_radial(this, draw_params, start, ray);
1115  else
1116    return g1_model_collide_polygonal(this, draw_params, start, ray, normal);
1117}
1118
1119
1120void g1_apply_damage(g1_object_class *used,
1121                     g1_object_class *fired,
1122                     g1_object_class *hit,
1123                     const i4_3d_vector &dir)
1124{
1125  if (!used) return;
1126
1127  g1_damage_map_struct *dmap=used->get_type()->get_damage_map();
1128
1129  if (dmap->hurt_type==g1_damage_map_struct::HURT_SINGLE_GUY)
1130  {
1131    if (!hit || !hit->valid() || hit->player_num==used->player_num) return ;
1132   
1133    int amount=dmap->get_damage_for(hit->id);
1134    if (fired)
1135      fired->notify_damage(hit, amount);
1136   
1137    hit->damage(used, amount, dir);
1138
1139    if (dmap->special_damage)
1140      g1_create_damager_object(i4_3d_vector(hit->x, hit->y, hit->h),
1141                               amount, dmap->special_damage, fired, hit,
1142                               acid.get());
1143  }
1144  else
1145  {
1146    // damage what we hit
1147    if (hit && hit->player_num!=used->player_num)
1148    {
1149      int amount=dmap->get_damage_for(hit->id);
1150
1151      if (fired)
1152        fired->notify_damage(hit, amount);
1153     
1154      hit->damage(used, amount, dir);       
1155    }
1156
1157    // damage things in the radius
1158    g1_object_class *list[G1_MAX_OBJECTS];
1159   
1160    float radius=dmap->special_damage;
1161    float oo_radius=1.0/radius;
1162   
1163    int t=g1_get_map()->get_objects_in_range(used->x, used->y,
1164                                             radius, list, G1_MAX_OBJECTS,
1165                                             g1_object_class::TARGETABLE);
1166
1167    for (int i=0; i<t; i++)
1168    {
1169      g1_object_class *o=list[i];
1170      //      if (o->player_num!=used->player_num && o!=hit)  // hit only enemies
1171      if (o!=hit)          // smack up everyone
1172      {
1173        float dist=sqrt((used->x-o->x)*(used->x-o->x)+
1174                        (used->y-o->y)*(used->x-o->x)+
1175                        (used->h-o->h)*(used->h-o->h));
1176       
1177        if (dist<radius)
1178        {
1179          float max_amount=dmap->get_damage_for(o->id);
1180          float amount=(radius-dist)*oo_radius * max_amount;
1181         
1182          if (fired)
1183            fired->notify_damage(o, i4_f_to_i(amount));
1184         
1185          o->damage(used, i4_f_to_i(amount), dir);       
1186        }     
1187      }             
1188    }
1189  }                                   
1190}
1191
1192void g1_object_class::damage(g1_object_class *who_is_hurting,
1193                             int how_much_hurt, i4_3d_vector damage_dir)
1194{
1195  if (!valid())
1196    return;
1197 
1198  if (health-how_much_hurt<=0)
1199  {         
1200    health=0;
1201
1202    if (player_num!=g1_player_man.local_player)
1203    {
1204      g1_crate_class *c=(g1_crate_class *)g1_create_object(g1_get_object_type(g1_crate.get()));
1205
1206      // jc fixme : this is not determanistic if global_id's are not
1207
1208      if ((g1_rand(global_id) & 7)==0)
1209        c->setup(i4_3d_vector(x,y,h),
1210                 (g1_crate_class::ctype)(g1_rand(global_id) % g1_crate_class::MAX_TYPES),
1211                 g1_crate_class::SMALL,
1212                 200);       // 20 seconds to get the crate
1213    }
1214
1215
1216
1217    i4_3d_vector spot=i4_3d_vector(x, y, h);
1218    float r=g1_resources.visual_radius();
1219
1220    // don't explode or play sound if we are too far away from the camera
1221    if (g1_current_view_state()->dist_sqrd(spot)<r*r)
1222    {
1223      if (who_is_hurting && who_is_hurting->id==g1_get_object_type(vortex.get()))
1224      {
1225         
1226        g1_explode_model_class *e;
1227        e=(g1_explode_model_class *)g1_create_object(g1_get_object_type(explode_model.get()));
1228        g1_explode_params params;
1229        i4_3d_vector e_pos=i4_3d_vector(who_is_hurting->x, who_is_hurting->y, who_is_hurting->h);
1230       
1231        params.stages[1].setup(5, 0);
1232        params.stages[2].setup(50, -0.1);
1233        params.t_stages=3;
1234        e->setup(this, e_pos, params);
1235
1236        g1_camera_event cev;
1237        cev.type=G1_WATCH_EXPLOSION;
1238        cev.follow_object=e;
1239        g1_current_controller->view.suggest_camera_event(cev);
1240      }
1241      else
1242      {
1243        g1_chunk_explosion_class *ce;
1244
1245        char **chunk_names;
1246        int t_chunks=get_chunk_names(chunk_names);
1247        if (!t_chunks)
1248        {
1249          ce=(g1_chunk_explosion_class *)g1_create_object(g1_get_object_type(chunk_explosion.get()));
1250          ce->setup(i4_3d_vector(x,y,h),
1251                    i4_3d_vector(roll, pitch, theta),
1252                    draw_params.model, damage_dir*0.3, 1);
1253        }
1254        else
1255        {         
1256          for (int t=0; t<t_chunks; t++)
1257          {     
1258            ce=(g1_chunk_explosion_class *)g1_create_object(g1_get_object_type(chunk_explosion.get()));
1259            int model_id=g1_model_list_man.find_handle(chunk_names[t]);
1260            ce->setup(i4_3d_vector(x,y,h),
1261                      i4_3d_vector(roll, pitch, theta),
1262                      g1_model_list_man.get_model(model_id), damage_dir, t*5+1);
1263          }
1264        }
1265
1266
1267        g1_camera_event cev;
1268        cev.type=G1_WATCH_EXPLOSION;
1269        cev.follow_object=ce;
1270        g1_current_controller->view.suggest_camera_event(cev);
1271      }
1272
1273      explosion_ground_vehicle.play(x,y,h);
1274    }
1275    unoccupy_location();
1276    request_remove();
1277  }
1278  else
1279  {
1280    health-=how_much_hurt;
1281
1282    g1_camera_event cev;
1283    cev.type=G1_WATCH_HIT;
1284    cev.follow_object=this;
1285    g1_current_controller->view.suggest_camera_event(cev);
1286  }
1287}
1288
1289
1290li_object *g1_setup_stages(li_object *o, li_environment *env)
1291{
1292  int t=0;
1293  while (o)
1294  {
1295    def_params.stages[t].setup(li_get_int(li_eval(li_first(o,env), env),env),
1296                               li_get_float(li_eval(li_second(o,env), env),env),
1297                               (g1_stage_type)(li_get_int(li_eval(li_third(o, env), env),env))
1298                               );
1299    t++;
1300    o=li_cdr(o,env);
1301    o=li_cdr(o,env);
1302    o=li_cdr(o,env);
1303  }
1304 
1305  def_params.t_stages=t;
1306  return 0;
1307}
1308
1309li_automatic_add_function(g1_setup_stages, "stages");
Note: See TracBrowser for help on using the repository browser.