source: golgotha/src/golg/map.cc

Last change on this file was 80, checked in by Sam Hocevar, 12 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: 16.0 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 "player.hh"
10#include "error/error.hh"
11#include "g1_limits.hh"
12#include "image/color.hh"
13#include "map.hh"
14#include "window/win_evt.hh"
15#include "device/kernel.hh"
16#include "objs/model_id.hh"
17#include "image/image.hh"
18#include "loaders/load.hh"
19#include "init/init.hh"
20#include "resources.hh"
21#include "g1_object.hh"
22#include "objs/map_piece.hh"
23#include "sound_man.hh"
24#include "tile.hh"
25#include "resources.hh"
26#include "remove_man.hh"
27#include "math/pi.hh"
28#include "g1_speed.hh"
29#include "light.hh"
30#include "m_flow.hh"
31#include "statistics.hh"
32#include "input.hh"
33#include "time/profile.hh"
34#include "g1_render.hh"
35#include "height_info.hh"
36#include "checksum/checksum.hh"
37#include "solvemap_astar.hh"
38#include "cwin_man.hh"
39#include "map_light.hh"
40#include "map_man.hh"
41#include "lisp/li_class.hh"
42#include "objs/path_object.hh"
43#include "objs/vehic_sounds.hh"
44#include "map_cell.hh"
45#include "map_vert.hh"
46#include "tick_count.hh"
47#include "map_view.hh"
48#include "map_data.hh"
49
50g1_height_info::g1_height_info()
51{
52  floor_height   = 0.f;
53  ceiling_height = 1.f;
54  flags = BELOW_GROUND; 
55}
56
57
58i4_profile_class pf_map_think("map.cc think objects");
59i4_profile_class pf_map_post_think("map.cc post_think objects");
60i4_profile_class pf_notify_target_position_change("notify_target_pos_change");
61
62g1_statistics_counter_class g1_stat_counter;
63
64w32 g1_map_class::get_tick()
65{
66  return g1_tick_counter;
67}
68   
69g1_map_cell_class *g1_map_class::cell(w16 x, w16 y) const { return cells + y*w + x; }
70g1_map_cell_class *g1_map_class::cell(w32 offset) const  { return cells + offset; }
71g1_map_vertex_class *g1_map_class::vertex(w16 x, w16 y) const { return verts + y*(w+1) + x; }
72
73
74void g1_map_class::add_object(g1_object_chain_class &c, w32 x, w32 y)
75{
76  cells[c.offset = y*w+x].add_object(c);
77}
78
79void g1_map_class::remove_object(g1_object_chain_class &c)
80{
81  cells[c.offset].remove_object(c);
82}
83
84i4_float g1_map_class::min_terrain_height(w16 x, w16 y)
85{
86  g1_map_vertex_class *v1,*v2,*v3,*v4;
87   
88  v1 = verts+ x + y * (w+1);
89  v2 = v1+1;
90  v3 = v1+w+1;
91  v4 = v3+1;
92   
93  return g1_vertex_min(v1, g1_vertex_min(v2, g1_vertex_min(v3, v4)))->get_height();
94}
95
96// only use this if you know what you are doing
97void g1_map_class::change_map(int _w, int _h,
98                              g1_map_cell_class *_cells, g1_map_vertex_class *_vertex)
99{
100  if (cells)
101    i4_free(cells);
102 
103  if (verts)
104    i4_free(verts);
105
106  cells=_cells;
107  verts=_vertex;
108  w=_w;
109  h=_h;
110}
111
112
113void g1_map_class::remove_object_type(g1_object_type type)
114{
115  int i,j,k;
116  g1_map_cell_class *c=cell(0,0);
117  g1_object_chain_class *cell, *l;
118  g1_object_class *obj;
119
120  for (j=0; j<height(); j++)
121    for (i=0; i<width(); i++, c++)
122    {
123      for (cell=c->get_obj_list(); cell;)
124      {
125        l=cell;
126        cell=cell->next;
127        obj=l->object;
128        if (obj->id==type)
129        {         
130          obj->unoccupy_location();
131          obj->request_remove();
132        }
133      }
134    }
135}
136
137
138g1_map_class::g1_map_class(const i4_const_str &fname)
139{
140  recalc=0xffffffff;     // recalculate everything until further notice
141
142  sky_name=0;
143
144//   lod=0;
145  //  lod=(g1_map_lod_cell *) i4_malloc(sizeof(g1_map_lod_cell) * MAX_MAP_LOD, "lod");
146
147  filename=0;
148  set_filename(fname);
149
150  post_cell_draw=0;
151
152  w=0;
153  h=0;
154
155
156  think_head=think_tail=0;
157
158  current_movie=0;
159 
160  cells=0;
161  verts=0;
162
163  //  map=(g1_map_cell_class *)i4_malloc(w*h*sizeof(g1_map_cell_class),"map");
164  //  vert=(g1_map_vertex_class *)i4_malloc((w+1)*(h+1)*sizeof(g1_map_vertex_class),"map vert");
165
166  w32 x,count=w*h,y;
167 
168  solver = new g1_astar_map_solver_class;
169//   critical_graph=0;
170  movie_in_progress=i4_F;
171}
172
173g1_map_class::~g1_map_class()
174{
175  g1_stop_sound_averages();
176
177  g1_map_class *old_current=g1_current_map_PRIVATE;
178  g1_set_map(this);
179
180
181 
182  for (g1_map_data_class *md=g1_map_data_class::first; md; md=md->next)
183    md->free();
184
185
186  if (filename)
187    delete filename;
188
189  if (sky_name)
190    delete sky_name;
191
192  if (cells)
193  {
194    g1_object_class *olist[G1_MAX_OBJECTS];
195    w32 ids[G1_MAX_OBJECTS];
196
197    sw32 t=make_object_list(olist, G1_MAX_OBJECTS), i;
198
199    // can't use object pointers directly because one
200    // object might delete another
201    for (i=0; i<t; i++)
202      ids[i]=olist[i]->global_id;
203     
204
205    for (i=0; i<t; i++)
206    {
207      if (g1_global_id.check_id(ids[i]))
208      {
209        g1_object_class *o=g1_global_id.get(ids[i]);       
210        o->unoccupy_location();
211        o->request_remove();
212        g1_remove_man.process_requests();       
213      }
214    }
215    i4_free(cells);
216  }
217   
218
219  if (verts)
220    i4_free(verts);
221
222  if (current_movie)
223    delete current_movie;
224 
225  if (solver)
226    delete solver;
227 
228
229
230  if (old_current==this)
231    g1_set_map(0);
232  else
233    g1_set_map(old_current);
234
235}
236
237void check_olist()
238{
239  g1_object_class *olist[G1_MAX_OBJECTS];
240  sw32 t=g1_get_map()->make_object_list(olist, G1_MAX_OBJECTS);
241}
242
243// returns total added
244sw32 g1_map_class::make_object_list(g1_object_class **buffer, sw32 buf_size) 
245{
246  int x=width()*height(), i;
247  sw32 t=0;
248  g1_map_cell_class *c=cells;
249  if (buf_size==0) return 0;
250
251
252  for (i=0; i<x; i++, c++)
253    if (c->object_list)
254    {
255      for (g1_object_chain_class *obj=c->get_obj_list(); obj; obj=obj->next)
256      {
257        g1_object_class *o=obj->object;
258        if (!o->get_flag(g1_object_class::SCRATCH_BIT))   /// make sure object only added once
259        {
260          o->set_flag(g1_object_class::SCRATCH_BIT, 1);
261          buffer[t++]=o;
262          if (t==buf_size)
263          {
264            i=x;
265            obj=0;
266          }
267        }
268      }
269    }
270
271  for (i=0; i<t; i++)
272    buffer[i]->set_flag(g1_object_class::SCRATCH_BIT, 0);
273
274  return t;
275}
276
277sw32 g1_map_class::make_selected_objects_list(w32 *buffer, sw32 buf_size)
278{
279  int x=width()*height(), i;
280  sw32 t=0;
281  g1_map_cell_class *c=cells;
282  if (buf_size==0) return 0;
283
284
285  for (i=0; i<x; i++, c++)
286    if (c->object_list)
287    {
288      for (g1_object_chain_class *obj=c->get_obj_list(); obj; obj=obj->next)
289      {
290        g1_object_class *o=obj->object;
291
292        // make sure object only added once
293        if (o->selected() && !o->get_flag(g1_object_class::SCRATCH_BIT))   
294        {
295          o->set_flag(g1_object_class::SCRATCH_BIT, 1);
296          buffer[t++]=o->global_id;
297          if (t==buf_size)
298          {
299            i=x;
300            obj=0;
301          }
302        }
303      }
304    }
305
306  for (i=0; i<t; i++)
307    g1_global_id.get(buffer[i])->set_flag(g1_object_class::SCRATCH_BIT, 0);
308
309  return t;
310}
311
312void g1_map_class::think_objects()
313{
314  li_class *old_this=li_this;
315
316  recalc_static_stuff();
317
318
319  pf_map_think.start();
320  g1_input.que_keys(tick_time);
321
322
323  w32 i,h;
324 
325  w32 start_tail = think_tail;
326  w32 start_head = think_head;
327 
328  //do the think()'s 
329  i = start_tail;
330  h = start_head;
331
332  g1_reset_sound_averages();
333
334  pf_map_think.start();
335
336  for (; i!=h; )
337  {
338    g1_object_class *o=think_que[i];
339
340    //always check to make sure the pointer
341    //is good. objects might have removed themselves
342    //from the map while still in the que, and left
343    //a null pointer in their place
344    if (o)
345    {
346      li_this=o->vars;
347      o->grab_old();
348    }
349
350    i++;
351    if (i>=THINK_QUE_SIZE)
352      i=0;
353  }
354
355  i = start_tail;
356  h = start_head;
357  for (; i!=h; )
358  {
359    g1_object_class *o=think_que[i];
360
361    //always check to make sure the pointer
362    //is good. objects might have removed themselves
363    //from the map while still in the que, and left
364    //a null pointer in their place
365    if (o)
366    {
367      li_this=o->vars;
368      o->set_flag(g1_object_class::THINKING, 0);
369      o->think();
370    }
371
372    i++;
373    if (i>=THINK_QUE_SIZE)
374      i=0;
375  }
376
377  pf_map_think.stop();
378
379
380  pf_map_post_think.start();
381 
382  //do the post_think()'s
383  i = start_tail;
384  h = start_head;
385
386  for (; i!=h; )
387  {
388    g1_object_class *o=think_que[i];   
389
390    think_tail++;
391    if (think_tail>=THINK_QUE_SIZE)
392      think_tail=0;
393
394    //always check to make sure the pointer
395    //is good. objects might have removed themselves
396    //from the map while still in the que, and left
397    //a null pointer in their place
398    if (o)
399    {
400      li_this=o->vars;
401      o->post_think();
402    }
403
404    i++;
405    if (i>=THINK_QUE_SIZE)
406      i=0;
407  }
408  pf_map_post_think.stop();
409
410  g1_recalc_sound_averages();
411
412
413  g1_tick_counter++;
414  tick_time.add_milli((1000/G1_HZ));
415
416
417  li_this=old_this;
418  pf_map_think.stop();
419 
420}
421
422
423void g1_map_class::damage_range(g1_object_class *obj,
424                                i4_float x, i4_float y, i4_float z,
425                                i4_float range, w16 damage, i4_float falloff)
426// damage to vehicles centers at x,y,z and falls off by falloff*damage at range distance
427//   from the center of the damage range
428{
429  sw32 ix,iy,
430    sx = sw32(x-range),
431    ex = sw32(x+range)+1,
432    sy = sw32(y-range),
433    ey = sw32(y+range)+1;
434
435  // clip region
436  if (sx<0) sx=0;
437  if (ex>width()) ex=width();
438  if (sy<0) sy=0;
439  if (ey>height()) ey=height();
440
441  // get first one
442  g1_map_cell_class *c;
443  g1_object_chain_class *objlist;
444  i4_float dist,dx,dy,dz;
445
446  range *= range;
447  falloff *= i4_float(damage)/range;
448
449  for (iy=sy; iy<ey; iy++)
450  {
451    c = cell(sx,iy);
452    for (ix=sx; ix<ex; ix++, c++)
453    {
454      for (objlist=c->get_obj_list(); objlist; objlist=objlist->next)
455      {
456        g1_object_class *hurt_obj=objlist->object;
457
458        if (objlist==&hurt_obj->occupied_squares[0]) // make sure object is only hurt once
459        {
460          if (hurt_obj->get_flag(g1_object_class::TARGETABLE))
461// && hurt_obj->player_num!=obj->player_num)
462          {
463            dx=x-hurt_obj->x;
464            dy=y-hurt_obj->y;
465            dz=z-hurt_obj->h;
466            dist = dx*dx+dy*dy+dz*dz;
467            if (dist<range)
468              hurt_obj->damage(obj, damage - (int)(falloff*range), i4_3d_vector (0,0,g1_resources.gravity));
469          }
470        }
471      }
472    }
473  }
474}
475
476
477
478g1_object_class *g1_map_class::find_object_by_id(w32 object_id,
479                                                 g1_player_type prefered_team)
480{
481  sw32 i,j=width()*height();
482  g1_map_cell_class *c=cells;
483  g1_object_chain_class *o;
484  g1_object_class *best=0;
485
486  for (i=0; i<j; i++, c++)
487  {
488    for (o=c->get_obj_list(); o; o=o->next)
489    {
490      if (o->object->id==object_id)
491      {
492        if (o->object->player_num==prefered_team)             
493          return o->object;
494        else
495          best=o->object;
496      }
497    }
498  }
499  return best;
500}
501
502
503void g1_map_class::remove_from_think_list(g1_object_class *obj)
504{
505  w32 i = think_tail,
506      h = think_head;
507 
508  for (; i!=h;)
509  {
510    if (think_que[i]==obj) think_que[i]=0;
511     
512    i++;
513    if (i>=THINK_QUE_SIZE)
514      i=0;
515  }
516}
517
518void g1_map_class::request_remove(g1_object_class *obj)
519{
520  obj->flags |= g1_object_class::DELETED;
521
522  if (obj->flags & g1_object_class::THINKING)
523  {
524    obj->stop_thinking();
525  }
526 
527  g1_remove_man.request_remove(obj);
528}
529
530
531i4_const_str g1_map_class::get_filename()
532{
533  return *filename;
534}
535
536void g1_map_class::set_filename(const i4_const_str &fname)
537{
538  if (filename)
539    delete filename;
540  filename=new i4_str(fname);
541}
542
543
544
545
546void g1_map_class::recalc_static_stuff()
547{
548  i4_bool reset_time=i4_F;
549
550//   if (recalc & (G1_RECALC_BLOCK_MAPS | G1_RECALC_CRITICAL_DATA))
551//     li_call("add_undo", li_make_list(new li_int(G1_MAP_CRITICAL_DATA), 0));
552   
553  if (recalc & G1_RECALC_STATIC_LIGHT)
554    g1_calc_static_lighting();               // defined in light.cc
555
556
557//   if (recalc & G1_RECALC_BLOCK_MAPS)   
558//   {
559//     make_block_maps();
560//     reset_time=i4_T;
561//   }
562
563  if (recalc & G1_RECALC_RADAR_VIEW)
564  {
565//     init_lod();   //(OLI) need to put this in the proper place
566
567    g1_radar_recalculate_backgrounds();
568    reset_time=i4_T;
569  }
570
571  if (recalc & (G1_RECALC_WATER_VERTS))
572  {
573    g1_map_vertex_class *v=verts+(w+1)+1;
574    g1_map_cell_class *c=cells+(w)+1;
575
576    for (int y=1; y<h-1; y++)
577    {
578      for (int x=1; x<w-1; x++, c++, v++)
579      {
580        if ((g1_tile_man.get(c[0].type)->flags & g1_tile_class::WAVE) &&
581            (g1_tile_man.get(c[-1].type)->flags & g1_tile_class::WAVE) &&
582            (g1_tile_man.get(c[-w].type)->flags & g1_tile_class::WAVE) &&
583            (g1_tile_man.get(c[-w-1].type)->flags & g1_tile_class::WAVE))
584          v->flags |= g1_map_vertex_class::APPLY_WAVE_FUNCTION;
585      }
586      v+=2;
587      c+=2;
588      v++;     
589    }
590
591    reset_time=i4_T;
592  }
593 
594  recalc=0;
595
596  if (reset_time)
597    tick_time.get();     // don't simulate ticks for the calculation stuff
598}
599
600
601void g1_map_class::range_iterator::begin(float x, float y, float range)
602//{{{
603{
604  g1_map_class *map = g1_get_map();
605  int wx = map->width(), wy = map->height();
606
607  left   = i4_f_to_i(x - range); if (left<0)      left=0;
608  right  = i4_f_to_i(x + range); if (right>wx-1)  right=wx-1;
609  top    = i4_f_to_i(y - range); if (top<0)       top=0;
610  bottom = i4_f_to_i(y + range); if (bottom>wy-1) bottom=wy-1;
611
612  ix = right;
613  iy = top-1;
614  cell = 0;
615  chain = 0;
616
617  object_mask_flags=0xffffffff;
618  type_mask_flags=0xffffffff;
619}
620//}}}
621
622void g1_map_class::range_iterator::safe_restart()
623//{{{
624{
625  chain=0;
626}
627//}}}
628
629i4_bool g1_map_class::range_iterator::end()
630//{{{
631{
632  return (iy>=bottom);
633}
634//}}}
635
636void g1_map_class::range_iterator::next()
637//{{{
638{
639  return;
640  /*
641  g1_object_class *o;
642
643  if (chain) chain = chain->next;
644
645  while (iy<bottom)
646  {
647    if (!chain)
648    {
649      ++ix;
650      ++cell;
651      if (ix<=right)
652        chain = cell->get_obj_list();
653      else
654      {
655        ix = left;
656        iy++;
657        cell = &g1_get_map()->cell(left, iy);
658      }
659    }
660    else
661    {
662      o = chain->object;
663      if (&o->occupied_squares[0]!=chain ||
664          (o->flags & object_mask_flags)==0 ||
665          (g1_object_type_array[o->id]->flags & type_mask_flags)==0)
666        chain = chain->next;
667      else
668        return;
669    }
670  }
671  */
672}
673//}}}
674
675sw32 g1_map_class::get_objects_in_range(float x, float y, float range,
676                                        g1_object_class *dest_array[], w32 array_size,
677                                        w32 object_mask_flags, w32 type_mask_flags)
678{
679  sw32 x_left,x_right,y_top,y_bottom;
680 
681  x_left   = i4_f_to_i(x - range); if (x_left<0)     x_left=0;
682  x_right  = i4_f_to_i(x + range); if (x_right>w-1)  x_right=w-1;
683  y_top    = i4_f_to_i(y - range); if (y_top<0)      y_top=0;
684  y_bottom = i4_f_to_i(y + range); if (y_bottom>h-1) y_bottom=h-1;
685 
686  sw32 ix,iy; 
687  sw32 num_found=0;
688 
689  for (iy=y_top;  iy<=y_bottom; iy++)
690  {
691    g1_map_cell_class *cell = g1_get_map()->cell(x_left, iy);
692
693    for (ix=x_left; ix<=x_right;  ix++, cell++)
694    {     
695      g1_object_chain_class *p     = cell->get_solid_list();
696
697      while (p && num_found<array_size)
698      {   
699        g1_object_class *o = p->object;
700
701        if (o && (&o->occupied_squares[0]==p) && (o->flags & object_mask_flags))
702        {
703          if (g1_object_type_array[o->id]->flags & type_mask_flags)
704          {
705            dest_array[num_found] = p->object;
706            num_found++;
707          }
708        }
709     
710        p = p->next_solid();
711      }
712   
713      if (num_found >= array_size)
714        break;
715    }
716   
717    if (num_found >= array_size)
718        break;
719  }
720 
721  return num_found;
722}
Note: See TracBrowser for help on using the repository browser.