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

Last change on this file since 80 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: 18.4 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 "map.hh"
10#include "saver.hh"
11#include "tile.hh"       
12#include "g1_object.hh"
13#include "path.hh"
14#include "load3d.hh"
15#include "m_flow.hh"
16#include "player.hh"
17#include "light.hh"
18#include "remove_man.hh"
19#include "g1_render.hh"
20#include "saver_id.hh"
21// #include "critical_graph.hh"
22// #include "solvemap_astar.hh"
23
24#include "objs/old_ids.hh"
25#include "height_info.hh"
26#include "loaders/load.hh"
27#include "map_man.hh"
28#include "cwin_man.hh"
29
30#include "objs/map_piece.hh"
31#include "lisp/li_load.hh"
32#include "map_cell.hh"
33#include "map_vert.hh"
34#include "tick_count.hh"
35#include "map_data.hh"
36
37void g1_map_class::save_objects(g1_saver_class *out)
38{
39  g1_object_class *olist[G1_MAX_OBJECTS];
40  sw32 t=make_object_list(olist, G1_MAX_OBJECTS), ttypes=0, i;
41           
42  out->set_helpers(olist, t);
43
44  // save the names of all the object types
45  out->mark_section(G1_SECTION_OBJECT_TYPES_V1);
46  out->write_32(g1_last_object_type+1);
47
48  for (i=0; i<=g1_last_object_type; i++)
49    if (g1_object_type_array[i])
50    {
51      const char *name=g1_object_type_array[i]->name();
52      int len=strlen(name)+1;
53      out->write_16(len);
54      out->write((void*)name,len);
55    }
56    else out->write_16(0);
57
58
59  out->mark_section("golgotha object type info");
60  for (i=0; i<=g1_last_object_type; i++)
61  {
62    int han=out->mark_size();
63    if (g1_object_type_array[i])
64      g1_object_type_array[i]->save(out);     
65    out->end_mark_size(han);
66  }
67
68
69  out->mark_section(G1_SECTION_OBJECTS_V1);
70  out->write_32(t);
71
72  // if objects change at a base level (g1_object_class) then a new section
73  // should be created here
74  out->mark_section(G1_SECTION_OBJECT_BASE_V1);
75  for (i=0; i<t; i++)
76  {
77    out->mark_section(G1_SECTION_OBJECT_LIST + i);
78    out->write_16(olist[i]->id);
79    olist[i]->save(out);
80  }
81}
82
83void g1_map_class::save(g1_saver_class *out, w32 sections)
84{
85  w32 i,j,k, tobjs=0;
86
87  out->mark_section("li_type_info");
88  li_save_type_info(out,0);
89 
90  // need to save the width and height of the map if saves cells or verts
91  if (sections & (G1_MAP_CELLS | G1_MAP_VERTS))
92  {
93    out->mark_section(G1_SECTION_MAP_DIMENSIONS_V1);
94    out->write_16(width());
95    out->write_16(height());
96  }
97
98  if (sections & G1_MAP_SKY)
99    save_sky(out);
100
101
102  if (sections & G1_MAP_TICK)
103  {
104    out->mark_section(G1_SECTION_TICK);
105    out->write_32(get_tick());
106  }
107
108
109  if (sections & G1_MAP_CELLS)
110  {
111    // this so if the tiles get moved around after save, we can match them back up
112    out->mark_section(G1_SECTION_TILE_MATCHUP_V1);
113    out->write_32(g1_tile_man.total());
114
115    for (i=0; i<g1_tile_man.total(); i++)
116      out->write_32(g1_tile_man.get(i)->filename_checksum);
117
118    g1_save_map_cells(cells, width() * height(), out);
119  }
120
121  if (sections & G1_MAP_VERTS)
122    g1_save_map_verts(verts, (w+1)*(h+1), out, i4_T);
123
124  if (sections & G1_MAP_SELECTED_VERTS)
125  {
126    out->mark_section("golgotha selected verts");
127   
128    int l=(w+1)*(h+1);
129    g1_map_vertex_class *v=verts;
130
131    for (i=0; i<l; i++, v++)
132      if (v->need_undo())
133      {
134        out->write_16(i);
135        g1_save_map_verts(v, 1, out, i4_F);
136      }
137
138    out->write_16(0xffff);
139  }
140       
141  if (sections & G1_MAP_PLAYERS)
142  {
143    out->mark_section(G1_SECTION_PLAYER_INFO);
144    g1_player_man.save(out);
145  }
146
147  if (sections & G1_MAP_OBJECTS)
148    save_objects(out);
149
150
151  if (sections & G1_MAP_LIGHTS)
152    g1_lights.save(out);
153
154
155  if ((sections & G1_MAP_MOVIE) && current_movie)
156  {
157    out->mark_section(G1_SECTION_MOVIE);
158    current_movie->save(out);   
159  }
160
161//   if ((sections & G1_MAP_CRITICAL_POINTS) && critical_graph)
162//   {
163//     out->mark_section(G1_SECTION_CRITICAL_POINTS_V1);
164//     critical_graph->save_points(out);
165//   }
166
167//   if ((sections & G1_MAP_CRITICAL_DATA) && critical_graph)
168//   {
169//     out->mark_section(G1_SECTION_CRITICAL_GRAPH_V1);
170//     critical_graph->save_graph(out);
171
172//     out->mark_section(G1_SECTION_CRITICAL_MAP_V1);
173//     save_critical_map(out);
174//   }
175
176  if (sections & G1_MAP_VIEW_POSITIONS)
177    g1_cwin_man->save_views(out);
178
179  for (g1_map_data_class *md=g1_map_data_class::first; md; md=md->next)
180    md->save(out, sections);
181
182}
183
184
185struct tile_matchup
186{
187  w16 old_tile_number;
188  w32 old_checksum;
189};
190
191int tile_matchup_compare(const void *a, const void *b)
192{
193  if ( ((tile_matchup *)a)->old_checksum<((tile_matchup *)b)->old_checksum)
194    return -1;
195  else if ( ((tile_matchup *)a)->old_checksum>((tile_matchup *)b)->old_checksum)
196    return 1;
197  else
198    return 0;
199}
200
201// this will create a remap array which maps the tiles saved previously into the
202// currently tile, so we can added and remove tiles from our list without screwing
203// up previously saved maps
204static w16 *g1_map_get_tile_remap(g1_loader_class *fp)   // returns 0 on failure
205{
206  if (!fp->goto_section(G1_SECTION_TILE_MATCHUP_V1))
207    return 0;
208  w32 i,t=fp->read_32();    // how many tile types there were when sved
209
210  tile_matchup *tl=(tile_matchup *)i4_malloc(t*sizeof(tile_matchup), "tile matchup");
211  for (i=0; i<t; i++)
212  {
213    tl[i].old_tile_number=i;
214    tl[i].old_checksum=fp->read_32();
215  }
216
217  // sort so we can do a binary search for faster matchup
218  qsort(tl,  t, sizeof(tile_matchup), tile_matchup_compare);
219
220  w16 *remap=(w16 *)i4_malloc(t*sizeof(w16), "tile remap");
221  memset(remap, 0, t*sizeof(w16));
222
223  for (i=0; i< g1_tile_man.total(); i++)
224  {
225    w32 find_id=g1_tile_man.get(i)->filename_checksum,cur;
226    w32 lo=0,hi=t,mid;
227    i4_bool done=i4_F;
228    mid=(hi+lo+1)/2;
229
230    do
231    {
232      cur=tl[mid].old_checksum;
233      if (cur==find_id)
234      {
235        done=i4_T;
236        remap[tl[mid].old_tile_number]=i;
237      }
238      else
239      {
240        if (cur<find_id)
241          lo=mid;
242        else hi=mid;
243
244        w32 last_mid=mid;
245        mid=(hi+lo)/2;
246        if (last_mid==mid)
247          done=i4_T;
248      }
249       
250    } while (!done);
251  }
252  i4_free(tl);
253  return remap;
254}
255
256i4_bool g1_map_class::load_sky(g1_loader_class *fp)
257
258  if (sky_name)
259    delete sky_name;
260
261  if (fp->goto_section(G1_SECTION_SKY_V1))
262    sky_name=fp->read_counted_str();   
263
264  return i4_T;
265}
266
267void g1_map_class::save_sky(g1_saver_class *fp)
268{
269  fp->mark_section(G1_SECTION_SKY_V1);
270
271  if (sky_name)   
272    fp->write_counted_str(*sky_name);
273}
274
275
276struct g1_sorted_obj_struct
277{
278  const char *name;
279  w16 type;
280};
281
282int g1_sorted_obj_struct_compare(const g1_sorted_obj_struct *a, const g1_sorted_obj_struct *b)
283{
284  return strcmp(a->name, b->name);
285}
286
287
288extern w32 g1_num_objs_in_view; // from map_fast
289
290//returns a list of objects
291g1_object_class **g1_map_class::load_objects(g1_loader_class *fp, w32 &tobjs)
292{
293  int i;
294  tobjs=0;
295  g1_object_class **obj_list=0;
296
297  g1_object_type *o_remap=0;
298
299  for (i=0; i<G1_MAX_PLAYERS; i++)
300      g1_player_man.get(i)->owned_objects.clear();
301
302  if (fp->goto_section(G1_SECTION_OBJECT_TYPES_V1))
303  {
304    i4_array<g1_sorted_obj_struct> sorted_objs(g1_last_object_type+1, 0);
305    for (i=0; i<=g1_last_object_type; i++)
306      if (g1_object_type_array[i])
307      {
308        g1_sorted_obj_struct o;
309        o.name=g1_object_type_array[i]->name();
310        o.type=i;
311        sorted_objs.add(o);
312      }
313     
314    sorted_objs.sort(g1_sorted_obj_struct_compare);
315
316    int old_total=fp->read_32();
317    o_remap=(g1_object_type *)i4_malloc(sizeof(g1_object_type) * old_total, "obj remap");
318
319    char name[512];
320    for (i=0; i<old_total; i++)
321    {
322      int nlen=fp->read_16();
323
324      if (nlen)
325      {
326        fp->read(name, nlen);
327
328        g1_sorted_obj_struct o;
329        o.name=name;
330       
331        int find=sorted_objs.binary_search(&o, g1_sorted_obj_struct_compare);
332        if (find==-1)
333        {
334          i4_warning("No match for old object type %s", name);
335          o_remap[i]=-1;
336        }
337        else
338          o_remap[i]=sorted_objs[find].type;
339      }
340      else
341        o_remap[i]=-1;
342    }
343
344    if (fp->goto_section("golgotha object type info"))
345    {
346      for (i=0; i<old_total; i++)
347      {
348        w32 size=fp->read_32();
349        if (o_remap[i]==-1)             // skip over types we don't know about
350          fp->seek(fp->tell()+size);
351        else
352          g1_object_type_array[o_remap[i]]->load(fp);
353      }
354    }
355  }
356 
357
358  if (fp->goto_section(G1_SECTION_OBJECTS_V1))
359  {
360    think_head=think_tail=0;
361
362    // reset the global id list
363    g1_global_id.init();
364    g1_global_id.claim_freespace();
365
366 
367
368    if (!o_remap)
369      o_remap=g1_get_old_object_type_remap();
370
371    tobjs=fp->read_32();
372    //tobjs=0;
373    if (tobjs)
374    {
375      w16 bomber_type = g1_get_object_type("bomber"); //(OLI) bomber hack for demo
376
377      obj_list=(g1_object_class **)i4_malloc(sizeof(g1_object_class *) * tobjs, "tmp object list");
378   
379      fp->set_remap(tobjs);
380      if (fp->goto_section(G1_SECTION_OBJECT_BASE_V1))
381      {
382        for (i=0; i<tobjs; i++)
383        {       
384          fp->goto_section(G1_SECTION_OBJECT_LIST + i);
385          sw16 obj_type=o_remap[fp->read_16()];
386     
387          if (obj_type==bomber_type)    //(OLI) bomber hack for demo
388            obj_type=-1;
389
390          if (obj_type>=0 && obj_type<=g1_last_object_type && g1_object_type_array[obj_type])
391          {
392            g1_object_class *o=g1_object_type_array[obj_type]->create_object(obj_type,fp);
393
394            g1_map_piece_class *mp = g1_map_piece_class::cast(o);           
395
396            if (o->global_id==g1_global_id.invalid_id())
397            {
398              i4_warning("object has invalid id for itself");
399              delete o;
400              o=0;
401            }
402//             else if (mp)
403//             {
404//               delete o;
405//               o=0;
406//             }
407            else
408            if (o->player_num>=G1_MAX_PLAYERS)
409            {
410              i4_warning("map load : object '%s' deleted, bad player number",
411                         g1_object_type_array[obj_type]->name());
412              delete o;
413              o=0;
414            } else if (o->x<0 || o->y<0 || o->x>=width() || o->y>=height() || o->id!=obj_type)
415            {
416              i4_warning("map load : object '%s' deleted, off map or loaded wrong",
417                         g1_object_type_array[obj_type]->name());
418              delete o;
419              o=0;
420            }
421           
422            obj_list[i]=o;
423          }
424          else
425          {
426            obj_list[i]=0;
427          }
428        }
429      }
430      fp->end_remap();
431      // now the object will convert all of there refernces to other objects from w16 to
432      // pointers
433     
434      fp->set_helpers(obj_list, tobjs);
435 
436      fp->convert_references();
437    }
438 
439  }
440   
441  if (o_remap)
442    i4_free(o_remap);
443 
444  return obj_list;
445
446}
447
448// returns the sections that were actually read
449w32 g1_map_class::load(g1_loader_class *fp, w32 sections)
450{
451  sw32 i, ret=0;
452  g1_object_class **obj_list=0;
453
454  g1_map_class *old_current=g1_current_map_PRIVATE;
455  g1_set_map(this);
456
457  w32 tobjs=0;
458  sw32 lw,lh;
459  i4_bool load_cells=(sections & G1_MAP_CELLS)!=0;
460  i4_bool load_verts=(sections & G1_MAP_VERTS)!=0;
461
462  if (sections & G1_MAP_RES_FILENAME && fp->goto_section("golgotha map res filename"))
463  {
464    i4_str *res = fp->read_counted_str();
465    //(OLI) what do we do with this string?
466    delete res;
467  }
468
469  if (fp->goto_section("li_type_info"))
470    fp->li_remap=li_load_type_info(fp,0);
471
472  if (sections & (G1_MAP_CELLS | G1_MAP_VERTS))
473  {
474    if (!fp->goto_section(G1_SECTION_MAP_DIMENSIONS_V1))
475      return 0;
476 
477    lw=fp->read_16();
478    lh=fp->read_16(); 
479
480    // must load cells and verts together if new load   
481    if (load_cells != load_verts &&
482        (cells!=0 || verts!=0) &&
483        (lw!=w  || lh!=h))
484    {
485      i4_warning("trying to merge in cells or verts of differnt map size");
486      sections &= ~(G1_MAP_CELLS | G1_MAP_VERTS);   // don't try to load these
487    }
488  }
489
490
491  if (sections & G1_MAP_SKY)
492  {
493    if (load_sky(fp))
494      ret|=G1_MAP_SKY;
495  }
496
497  if ((sections & G1_MAP_TICK) && (fp->goto_section(G1_SECTION_TICK)))
498  {
499    g1_tick_counter=fp->read_32();
500    ret|=G1_MAP_TICK;
501  }
502 
503
504  g1_object_class *olist[G1_MAX_OBJECTS];
505  sw32 t_old_objects=0;
506
507  if (cells)  // if old cells in map get all the objects off the map before proceeding
508  {
509    t_old_objects=make_object_list(olist, G1_MAX_OBJECTS);
510    for (i=0; i<t_old_objects; i++)
511      olist[i]->unoccupy_location();
512  }
513 
514  if (sections & G1_MAP_CELLS)   
515  {
516    if (cells)
517    {
518      i4_free(cells);
519      cells=0;
520    }
521   
522    if (load_cells == load_verts)
523    {
524      w=lw;
525      h=lh;
526      g1_map_width=w;
527      g1_map_height=h;
528    }
529
530    int a_size=w * h *sizeof(g1_map_cell_class);
531    cells=(g1_map_cell_class *)i4_malloc(a_size,"map");
532    g1_cells=cells;
533    memset(cells, 0, a_size);
534
535    w16 *tile_remap=g1_map_get_tile_remap(fp);
536    if (!tile_remap)
537      return i4_F;
538
539    if (g1_load_map_cells(cells, w*h, tile_remap, fp))
540      ret|=G1_MAP_CELLS;
541
542
543    i4_free(tile_remap);
544   
545    recalc|=G1_RECALC_PAD_LIST;
546  }
547
548
549
550  if (sections & G1_MAP_VERTS)
551  {
552    if (verts)
553      i4_free(verts);
554
555    int size=(lw+1)*(lh+1)*sizeof(g1_map_vertex_class);
556    verts=(g1_map_vertex_class *)i4_malloc(size,"");
557    g1_verts=verts;
558
559    g1_load_map_verts(verts, (lw+1)*(lh+1), fp, 1);
560    ret|=G1_MAP_VERTS;
561  }
562  else if (sections & G1_MAP_SELECTED_VERTS)
563  { 
564    if (fp->goto_section("golgotha selected verts"))
565    {
566      i=fp->read_16();
567      while (i!=0xffff)
568      {
569        g1_load_map_verts(verts+i, 1, fp, 0);
570        i=fp->read_16();
571      }
572
573      ret|=G1_MAP_SELECTED_VERTS;
574    }
575  }
576   
577  if ((sections & G1_MAP_PLAYERS) && fp->goto_section(G1_SECTION_PLAYER_INFO))
578  {
579    if (g1_player_man.load(fp))
580      ret|=G1_MAP_PLAYERS;
581  }
582
583  if (sections & G1_MAP_OBJECTS) 
584  {
585    for (i=0; i<t_old_objects; i++)
586    {
587      request_remove(olist[i]);
588      g1_remove_man.process_requests();       
589    }
590    t_old_objects=0;
591
592
593    obj_list=load_objects(fp, tobjs);
594    ret|=G1_MAP_OBJECTS;   
595  }
596
597  if (sections & G1_MAP_LIGHTS)
598  {
599    if (g1_lights.load(fp))
600      ret|=G1_MAP_LIGHTS;
601  }
602
603  if ((sections & G1_MAP_MOVIE) && (fp->goto_section(G1_SECTION_MOVIE)))
604  {
605    if (current_movie)
606      delete current_movie;
607
608    current_movie=g1_load_movie_flow(fp);
609
610
611    ret|=G1_MAP_MOVIE;
612  }
613
614  if (sections & G1_MAP_VIEW_POSITIONS)
615    g1_cwin_man->load_views(fp);
616  else if (sections & G1_MAP_OBJECTS)
617    g1_cwin_man->load_views(0);
618
619  if (obj_list)
620  {
621    for (i=0; i<tobjs; i++)
622      if (obj_list[i])
623      {
624        g1_object_class *o=obj_list[i];
625
626        o->occupy_location();
627        o->grab_old();          // is this ok?  currently, this is needed to get all ground
628                                //   rolls and pitches correct in the level
629       
630        if (o->get_flag(g1_object_class::THINKING))
631          request_think(o);
632
633        g1_player_man.get(o->player_num)->add_object(o->global_id);
634      }
635 
636    fp->convert_references();   
637    fp->set_helpers(0,0);   // make sure no one tries to use this later 
638
639    // validate everyone's data, especially if other objects have been deleted
640    for (i=0; i<tobjs; i++)
641      if (obj_list[i])
642        obj_list[i]->validate();
643
644    i4_free(obj_list);
645  }
646  else if (fp->references_were_loaded())
647    i4_error("could not convert references because objects not loaded");
648
649  // add previously removed object into the map if we aren't loading them later
650  if (t_old_objects)
651  {
652    if (sections & G1_MAP_OBJECTS)  // delete these object, they were supposedly loaded
653    {
654      for (i=0; i<t_old_objects; i++)
655      {
656        request_remove(olist[i]);
657        g1_remove_man.process_requests();       
658      }
659    }
660    else  // otherwise add them back into the map
661    {
662
663      for (i=0; i<t_old_objects; i++)
664        olist[i]->occupy_location();
665    }
666  }
667
668  for (g1_map_data_class *md=g1_map_data_class::first; md; md=md->next)
669    md->load(fp, sections);
670
671
672  g1_map_vertex_class *v[4];
673  i4_3d_vector v0,v1,v2,v3,vec1,vec2,vec3;
674  sw32 cx,cy;
675
676  for (cy=0; cy<height(); cy++)
677  for (cx=0; cx<width();  cx++)
678  {   
679    g1_map_cell_class *cell = cells+cx+cy*width();
680
681    v[0] = verts + cx + cy * (width()+1);       //v[0]   v[1]
682    v[1] = v[0]+1;                             //v[3]   v[2]
683    v[2] = v[1]+width()+1;
684    v[3] = v[2]-1;
685
686    v0.x = cx;
687    v0.y = cy;
688    v0.z = v[0]->get_height();
689
690    v1.x = cx+1;
691    v1.y = cx;
692    v1.z = v[1]->get_height();
693
694    v2.x = cx+1;
695    v2.y = cy+1;
696    v2.z = v[2]->get_height();
697
698    v3.x = cx;
699    v3.y = cy+1;
700    v3.z = v[3]->get_height();
701
702    vec1.x = v1.x - v0.x;
703    vec1.y = v1.y - v0.y;
704    vec1.z = v1.z - v0.z;
705
706    vec2.x = v2.x - v0.x;
707    vec2.y = v2.y - v0.y;
708    vec2.z = v2.z - v0.z;
709
710    vec3.cross(vec1,vec2);
711
712    i4_float dist = vec3.dot(v0);
713
714    if (fabs(vec3.dot(v3) - dist) < 0.00000001) cell->flags |= g1_map_cell_class::PLANAR;
715  }
716
717  recalc_static_stuff();
718  tick_time.get();
719
720  g1_set_map(old_current);
721
722  if (fp->li_remap)
723  {
724    li_free_type_info(fp->li_remap);
725    fp->li_remap=0;
726  }
727
728
729  return i4_T;
730}
731
732void g1_map_class::reload()
733{
734  i4_file_class *in=i4_open(*filename);
735  if (in)
736  {
737    g1_loader_class *l=g1_open_save_file(in);
738    if (l)
739    {
740      load(l, G1_MAP_ALL);
741      delete l;
742    }
743  }
744}
745
746// void g1_map_class::save_critical_map(g1_saver_class *f)
747// {
748//   int i,j,k;
749//   g1_map_cell_class *c=cell(0,0);
750
751//   for (j=0; j<height(); j++)
752//     for (i=0; i<width(); i++, c++)
753//       f->write(c->nearest_critical, sizeof(c->nearest_critical));
754// }
755
756// void g1_map_class::load_critical_map(g1_loader_class *f)
757// {
758//   int i,j,k;
759//   g1_map_cell_class *c=&cell(0,0);
760
761//   for (j=0; j<height(); j++)
762//     for (i=0; i<width(); i++, c++)
763//       f->read(c->nearest_critical, sizeof(c->nearest_critical));
764// }
765
Note: See TracBrowser for help on using the repository browser.