source: golgotha/src/golg/objs/path_object.cc

Last change on this file 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: 14.2 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 "objs/path_object.hh"
10#include "object_definer.hh"
11#include "lisp/li_init.hh"
12#include "lisp/li_class.hh"
13#include "li_objref.hh"
14#include "map_man.hh"
15#include "map.hh"
16#include "saver.hh"
17#include "li_objref.hh"
18#include "player.hh"
19#include "g1_render.hh"
20#include "objs/map_piece.hh"
21#include "isllist.hh"
22#include "objs/bases.hh"
23#include "sound/sfx_id.hh"
24
25extern int g1_show_list;  // defined in map_piece.cc
26
27enum
28{
29  DATA_VERSION1=1,
30  DATA_VERSION,
31};
32
33
34
35
36static li_symbol_class_member active("active");
37static li_symbol_ref on("on"), yes("yes"), no("no"), already_attached("already_attached");
38
39static li_symbol_ref off("off"), s_add_link("add_link"), s_remove_link("remove_link");
40static li_g1_ref_class_member start("start");
41static li_symbol_class_member bridgeable_spot("bridgeable_spot");
42
43i4_isl_list<g1_path_object_class> g1_path_object_list;
44
45
46static li_g1_ref_list_class_member links("links"), enemy_links("enemy_links"),
47  controlled_objects("controlled_objects");
48
49static li_int_class_member warning_level("warning_level");
50
51
52int g1_path_object_class::bomb_warning_level()
53{
54  return vars->get(warning_level);
55}
56
57g1_path_object_class::bridge_status_type g1_path_object_class::get_bridge_status()
58{
59  li_symbol *s=vars->get(bridgeable_spot);
60  if (s==yes.get())
61    return NO_BRIDGE;
62  else if (s==no.get())
63    return NOT_BRIDGABLE;
64  else
65    return HAS_BRIDGE;
66}
67
68g1_path_object_class::g1_path_object_class(g1_object_type id, g1_loader_class *fp)
69  : g1_object_class(id, fp), link(8,16)
70{
71  int i;
72  w16 ver=0,data_size;
73  if (fp) fp->get_version(ver,data_size);
74
75  switch (ver)
76  {
77    case DATA_VERSION:
78    {
79      for (i=0; i<G1_MAX_TEAMS; i++)
80        last_selected_tick[i]=fp->read_32();
81     
82      link_index[0]=0;
83      for (i=0; i<G1_MAX_TEAMS; i++)
84        link_index[i+1] = fp->read_8();
85
86      for (i=0; i<link_index[G1_MAX_TEAMS]; i++)
87      {
88        link_class *l = link.add();
89       
90        l->path.load(fp);
91        l->object.load(fp);
92      }
93    } break;
94
95    default:
96    {
97      if (fp) fp->seek(fp->tell() + data_size);
98
99      link_index[0]=0;
100      for (i=0; i<G1_MAX_TEAMS; i++)
101      {
102        last_selected_tick[i]=1;
103        link_index[i+1]=0;
104      }
105    } break;
106  }
107  if (fp) fp->end_version(I4_LF);
108
109  draw_params.setup("blackred");
110  set_flag(SELECTABLE | TARGETABLE, 1);
111}
112   
113void g1_path_object_class::validate()
114{
115  for (int a=0; a<G1_MAX_TEAMS; a++)
116    for (int i=total_links((g1_team_type)a)-1; i>=0; i--)
117    {
118      link_class *l = &link[link_index[a]+i];
119      if (!l->path.valid() || !l->object.valid())
120      {
121        link.remove(link_index[a] + i);
122        for (int t=a; t<G1_MAX_TEAMS; t++)
123          link_index[t+1]--;
124      }
125    }
126}
127   
128void g1_path_object_class::save(g1_saver_class *fp)
129{
130  int i;
131
132  g1_object_class::save(fp);
133
134  fp->start_version(DATA_VERSION);
135
136  for (i=0; i<G1_MAX_TEAMS; i++)
137    fp->write_32(last_selected_tick[i]);
138 
139  for (i=0; i<G1_MAX_TEAMS; i++)
140    fp->write_8(link_index[i+1]);
141
142  for (i=0; i<link.size(); i++)
143  {
144    link[i].path.save(fp);
145    link[i].object.save(fp);
146  }
147
148  fp->end_version();
149}
150   
151i4_bool g1_path_object_class::occupy_location()
152{
153
154  int a,i;
155
156  if (occupy_location_corners())
157  {
158    g1_path_object_list.insert(*this);
159    return i4_T;
160  }
161  else return i4_F; 
162}
163
164
165void g1_path_object_class::unoccupy_location()
166{
167  if (get_flag(MAP_OCCUPIED))
168  {
169    g1_object_class::unoccupy_location();
170    g1_path_object_list.find_and_unlink(this);
171  }
172}
173
174void g1_path_object_class::draw(g1_draw_context_class *context)
175{
176  if (g1_show_list)
177  {
178    int a=0;
179    for (int i=0; i<link.size(); i++)
180    {
181      while (i>=link_index[a+1]) a++; // determine team number
182      i4_float offs = a*0.2-0.1;
183      i4_color col = (a==0)? 0xffff : 0xff00ff;
184      g1_object_class *o = link[i].get_object();
185      if (o)
186        g1_render.render_3d_line(i4_3d_point_class(x+offs,y+offs,h+0.1),
187                                 i4_3d_point_class(o->x+offs, o->y+offs, o->h+0.1),
188                                 col, 0, context->transform);
189    }
190  }
191
192#if 0 
193  if (controlled_objects()->size())
194    g1_model_draw(this, draw_params, context);
195  else
196#endif
197    g1_editor_model_draw(this, draw_params, context);
198
199}
200 
201
202void g1_path_object_class::add_controlled_object(g1_object_class *o)
203{
204  li_class_context context(vars);
205  li_g1_ref_list *list=controlled_objects()->clone();
206  vars->set_value(controlled_objects.offset, list);
207  if (list->find(o)<0)
208    list->add(o);
209}
210
211void g1_path_object_class::add_link(g1_team_type team, g1_path_object_class *o)
212{
213  if (get_path_index(team, o)<0)
214  {
215    link_class *l = link.add_at(link_index[team+1]);
216    l->path = o;
217    l->object = o;
218    for (int i=team; i<G1_MAX_TEAMS; i++)
219      link_index[i+1]++;
220  }
221}
222
223i4_bool g1_path_object_class::remove_link(g1_team_type team, g1_path_object_class *p)
224{
225  int loc = get_path_index(team, p);
226  if (loc>=0)
227  {
228    link.remove(link_index[team] + loc);
229    for (int i=team; i<G1_MAX_TEAMS; i++)
230      link_index[i+1]--;
231    return i4_T;
232  }
233  return i4_F;
234}
235
236void g1_path_object_class::request_remove()
237{
238  int team=0;
239  for (int i=0; i<link.size(); i++)
240  {
241    while (i>=link_index[team+1]) team++; // determine team number
242
243    g1_object_class *o = link[i].get_object();
244    g1_map_piece_class *mp;
245   
246    while (mp = g1_map_piece_class::cast(o))
247    {
248      if (mp->next_path.get() == this)
249        o = mp->prev_object.get();
250      else
251        o = mp->next_object.get();
252      mp->unlink();
253    }
254
255    g1_path_object_class *path = link[i].get_path();
256
257
258    I4_TEST(o == path, "Invalid Linked List!");
259
260    if (path)
261      path->remove_link((team==G1_ALLY)? G1_ENEMY : G1_ALLY, this);
262  }
263  link.clear();
264  g1_object_class::request_remove();
265
266}
267
268li_object *g1_path_object_class::message(li_symbol *message_name,
269                                         li_object *message_params,
270                                         li_environment *env)
271{
272  li_class_context context(vars);
273 
274  if (message_name==on.get() || message_name==off.get())
275    active() = on.get();
276  else if (message_name==s_add_link.get())
277  {
278    g1_object_class *o=li_g1_ref::get(message_params,env)->value();
279    g1_path_object_class *path = g1_path_object_class::cast(o);
280
281    if (path)
282    {
283      add_link(G1_ALLY, path);
284      path->add_link(G1_ENEMY, this);
285    }
286  }
287  else if (message_name==s_remove_link.get())
288  {
289    g1_object_class *o=li_g1_ref::get(message_params,env)->value();
290    g1_path_object_class *path = g1_path_object_class::cast(o);
291   
292    if (path)
293    {
294      remove_link(G1_ALLY, path);
295      path->remove_link(G1_ENEMY, this);
296    }
297  }
298
299  return 0;
300}
301
302int g1_path_object_class::get_path_index(g1_team_type team, g1_path_object_class *o) const
303{
304  for (int i=link_index[team]; i<link_index[team+1]; i++)
305    if (link[i].get_path() == o)
306      return i-link_index[team];
307
308  return -1;
309}
310
311int g1_path_object_class::get_path_index(g1_path_object_class *o) const
312{
313  for (int i=0; i<link.size(); i++)
314    if (link[i].get_path() == o)
315      return i;
316
317  return -1;
318}
319
320int g1_path_object_class::get_object_index(g1_object_class *o) const
321{
322  for (int i=0; i<link.size(); i++)
323    if (link[i].get_object() == o)
324      return i;
325
326  return -1;
327}
328
329g1_path_object_class *g1_path_object_class::get_recent_link(g1_team_type team,
330                                                            g1_path_object_class *last_used)
331{
332  g1_path_object_class *best=0;
333 
334  w32 max_allowed=last_used ? last_used->last_selected_tick[team] : 0xffffffff;
335 
336  w32 t=total_links(team);
337  w32 best_tick=0;
338  int past_it=0;
339     
340  for (int i=0; i<t; i++)
341  {
342    g1_path_object_class *p=get_link(team,i);
343    int tick=p->last_selected_tick[team];
344   
345    if (tick<=max_allowed)
346    {
347      if (tick<max_allowed && tick>best_tick)
348      {
349        best=p;
350        best_tick=tick;
351      }
352      else if (tick==max_allowed && past_it && best_tick!=max_allowed)
353      {
354        best=p;
355        best_tick=tick;
356      }
357    }
358   
359    if (p==last_used)
360      past_it=1;
361  }
362 
363  return best;
364}
365   
366
367int g1_path_object_class::total_controlled_objects()
368{
369  return li_g1_ref_list::get(vars->get(controlled_objects),0)->size();
370}
371
372g1_object_class *g1_path_object_class::get_controlled_object(int object_num)
373{
374  return li_g1_ref_list::get(vars->get(controlled_objects),0)->value(object_num);
375}
376
377// returns the total destinations found (banks & etc that are attached to the path)
378int g1_path_object_class::find_path_destinations(g1_object_class **list,
379                                                 int list_size,
380                                                 g1_team_type team)
381{
382  i4_array<g1_object_class *> objects_to_unmark(128,128);
383  i4_array<g1_path_object_class *> unvisited_nodes(128,128);
384 
385  int off=vars->member_offset(team==G1_ALLY ? "links" : "enemy_links");
386  unvisited_nodes.add(this);
387  int unvisited_head=0;   
388  int t_in_list=0;
389
390  while (unvisited_head<unvisited_nodes.size())
391  { 
392    g1_path_object_class *p=unvisited_nodes[unvisited_head++];
393   
394    if (p && !p->get_flag(SCRATCH_BIT))
395    {
396      p->set_flag(SCRATCH_BIT, 1);
397      objects_to_unmark.add(p);
398
399      li_g1_ref_list *l=li_g1_ref_list::get(p->vars->value(off),0);           
400      int t=l->size(), i;
401      for (i=0; i<t; i++)
402      {
403        g1_object_class *o=l->value(i);
404        if (o)
405          unvisited_nodes.add(g1_path_object_class::cast(o));
406      }
407
408      if (li_g1_ref_list::get(p->vars->get(controlled_objects),0)->size())
409        list[t_in_list++]=p;
410    }
411  }
412   
413  for (int i=0; i<objects_to_unmark.size(); i++)
414    objects_to_unmark[i]->set_flag(SCRATCH_BIT, 0);
415
416  return t_in_list;
417}
418
419
420int g1_path_object_class::find_path(g1_team_type team,
421                                    g1_path_object_class **stack,
422                                    int stack_size)
423{
424  int t=0;
425  g1_path_object_class *o=this;
426  do
427  {
428    stack[t++]=o;
429    if (o)
430      o=o->get_recent_link(team, 0);
431  } while (o && t<stack_size);
432 
433  I4_ASSERT(t<stack_size, "Either paths are too long or path loop encountered!");
434
435  return t;
436}
437
438 
439int g1_path_object_class::find_path(g1_team_type team, g1_path_object_class *dest,
440                                    g1_path_object_class **stack,
441                                    int stack_size)
442{
443  g1_path_object_class *visited[1024];
444  w32 most_recently_selected[256];
445
446  I4_ASSERT(stack_size<=256, "can't find paths greater than 256.  bump this up, if needed.");
447
448  int depth=0, num_visited=0;
449
450  enum {BIG_NUM=0xffffffff };
451 
452  stack[depth] = this;
453  stack[depth+1] = 0;
454  most_recently_selected[depth] = BIG_NUM;
455  set_flag(g1_object_class::SCRATCH_BIT,1);
456  visited[num_visited++] = this;
457
458  do
459  {
460    g1_path_object_class *o = stack[depth]->get_recent_link(team, stack[depth+1]);
461    if (o)
462    {
463      o->set_flag(g1_object_class::SCRATCH_BIT,1);
464      visited[num_visited++] = o;
465
466      depth++;
467      stack[depth] = o;
468      stack[depth+1] = 0;
469    }
470    else
471      depth--;
472  } while (depth>=0 && stack[depth]!=dest);
473
474  for (int i=0; i<num_visited; i++)
475    visited[i]->set_flag(g1_object_class::SCRATCH_BIT,0);
476
477  if (depth<0)
478    depth=0;
479
480  if (depth)
481  {
482    while (stack[depth]) // whatsthis? && stack[depth]->total_links(type)>0)
483    {
484      g1_path_object_class *o = stack[depth]->get_recent_link(team, 0);
485      stack[++depth] = o;
486    }
487 
488    stack[++depth]=0;
489  }
490
491  for (int j=0; j<depth; j++)
492    if (!stack[j])
493      return j;
494
495  return depth;
496}
497
498void g1_path_object_class::change_player_num(int new_player)
499{
500  g1_object_class::change_player_num(new_player);
501  int t=total_controlled_objects();
502  for (int i=0; i<t; i++)
503  {
504    g1_object_class *o=get_controlled_object(i);
505    if (o && o->player_num!=new_player)
506    {
507      char msg[100];
508      w32 color;
509      if (new_player==g1_player_man.local_player)
510      {
511        sprintf(msg, "Building Captured : %s", o->name());
512        color=0x00ff00;
513      }
514      else
515      {
516        sprintf(msg, "Building Lost : %s", o->name());
517        color=0xff0000;
518      }
519
520      g1_player_man.show_message(msg, color, g1_player_man.local_player);
521
522      o->change_player_num(new_player);
523    }
524
525  }
526}
527
528g1_path_object_class* g1_path_object_class::find_next(g1_team_type team,
529                                                      g1_path_object_class *dest)
530{
531  g1_path_object_class *path[256];
532 
533  find_path(team, dest, path, 256);
534  return path[1];
535}
536
537void g1_path_object_class::editor_draw(g1_draw_context_class *context)
538{
539  int i;
540  for (i=0; i<total_links(G1_ALLY); i++)
541  {
542    g1_object_class *o = get_link(G1_ALLY,i);
543    if (o)
544    {
545      g1_render.render_3d_line(i4_3d_point_class(x,y,h+0.1),
546                               i4_3d_point_class(o->x, o->y, o->h+0.1),
547                               0xffffff, 0, context->transform);
548    }
549  }
550
551  for (i=0; i<total_links(G1_ENEMY); i++)
552  {
553    g1_object_class *o = get_link(G1_ENEMY,i);
554    if (o)
555    {
556      g1_render.render_3d_line(i4_3d_point_class(o->x, o->y, o->h+0.1),
557                               i4_3d_point_class(x,y,h+0.1),
558                               0xffffff, 0, context->transform);
559    }
560  }
561  li_g1_ref_list::get(vars->get(controlled_objects),0)->draw(this, 0xff0000, context); 
562}
563
564g1_object_definer<g1_path_object_class>
565g1_path_object_def("path_object",
566                   g1_object_definition_class::EDITOR_SELECTABLE |
567                   g1_object_definition_class::TO_PATH_OBJECT);
568
Note: See TracBrowser for help on using the repository browser.