1 /*
2  *  Abuse - dark 2D side-scrolling platform game
3  *  Copyright (c) 1995 Crack dot Com
4  *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
5  *
6  *  This software was released into the Public Domain. As with most public
7  *  domain software, no warranty is made or implied by Crack dot Com, by
8  *  Jonathan Clark, or by Sam Hocevar.
9  */
10 
11 #if defined HAVE_CONFIG_H
12 #   include "config.h"
13 #endif
14 
15 #if (defined(__MACH__) || !defined(__APPLE__))
16 #include <sys/stat.h>
17 #endif
18 
19 #include <string.h>
20 #include <limits.h>
21 #include <time.h>
22 #include <unistd.h>
23 
24 #include "common.h"
25 
26 #include "light.h"
27 #include "level.h"
28 #include "game.h"
29 #include "intsect.h"
30 #include "lisp.h"
31 #include "dprint.h"
32 #include "particle.h"
33 #include "objects.h"
34 #include "jrand.h"
35 #include "clisp.h"
36 #include "status.h"
37 #include "dev.h"
38 #include "demo.h"
39 #include "pcxread.h"
40 #include "profile.h"
41 #include "sbar.h"
42 #include "cop.h"
43 #include "nfserver.h"
44 #include "lisp_gc.h"
45 
46 level *current_level;
47 
attacker(game_object * who)48 game_object *level::attacker(game_object *who)
49 {
50   int32_t d=0x7fffffff;
51   game_object *c=NULL;
52   view *f=the_game->first_view;
53   for (; f; f=f->next)
54   {
55     if (f->focus)
56     {
57       int32_t tmp_d=abs(f->focus->x-who->x)+abs(f->focus->y-who->y);
58       if (tmp_d<d)
59       {
60     d=tmp_d;
61     c=f->focus;
62       }
63     }
64   }
65   CONDITION(c,"no attacker found");
66   return c;
67 }
68 
69 
70 
is_attacker(game_object * who)71 int level::is_attacker(game_object *who)
72 {
73   return who->controller()!=NULL;
74 }
75 
76 
main_character()77 game_object *level::main_character()
78 {
79   return the_game->first_view->focus;
80 }
81 
load_fail()82 void level::load_fail()
83 {
84   if (map_fg)    free(map_fg);   map_fg=NULL;
85   if (map_bg)    free(map_bg);   map_bg=NULL;
86   if (Name)      free(Name);     Name=NULL;
87 
88   first_active=NULL;
89   view *f=player_list;
90   for (; f; f=f->next)
91     if (f->focus)
92       current_level->remove_object(f->focus);
93 
94   while (first)
95   {
96     first_active=first;
97     first=first->next;
98     if (dev_cont)
99       dev_cont->notify_deleted_object(first_active);
100     delete first_active;
101   }
102 
103   while (area_list)
104   {
105     area_controller *l=area_list;
106     area_list=area_list->next;
107     delete l;
108   }
109 
110   last=NULL;
111   delete_panims();
112   delete_all_lights();
113 
114 }
115 
~level()116 level::~level()
117 {
118   load_fail();
119   if (attack_list) free(attack_list);
120   if (target_list) free(target_list);
121   if (block_list) free(block_list);
122   if (all_block_list) free(all_block_list);
123   if (first_name) free(first_name);
124 }
125 
restart()126 void level::restart()
127 {
128   view *f;
129   game_object *found=NULL,*o;
130   f=the_game->first_view;
131   for (o=first; f && o; o=o->next)
132   {
133     while (f && !f->focus) f=f->next;
134     if (f)
135     {
136       if (!strcmp(object_names[o->otype],"START"))
137       {
138     if (!found) found=o;
139     f->focus->x=o->x;
140     f->focus->y=o->y;
141     f->focus->set_hp(get_ability(f->focus->otype,start_hp));
142     f->focus->set_state(stopped);
143     f=f->next;
144       }
145     }
146   }
147   while (f)
148   {
149     if (f->focus)
150     {
151       f->focus->x=found->x;
152       f->focus->y=found->y;
153       f->focus->set_hp(get_ability(f->focus->otype,start_hp));
154       f->focus->set_state(stopped);
155     }
156     f=f->next;
157   }
158 }
159 
160 
next_focus()161 void level::next_focus()
162 {
163 /*  int i;
164   for (i=0; i<total_objs; i++)
165     if (obj[i]==the_game->first_view->focus)
166     {
167       int tries=total_objs;
168       do
169       {
170     i++;
171     if (i==total_objs)
172       i=0;
173     the_game->first_view->focus=obj[i];
174       }  while ((!the_game->first_view->focus->is_playable() ||
175          the_game->first_view->focus->hp<=0) && tries--);
176       return ;
177     }            */
178 }
179 
unactivate_all()180 void level::unactivate_all()
181 {
182   first_active=NULL;
183   game_object *o=first;
184   attack_total=0;  // reset the attack list
185   target_total=0;
186   block_total=0;
187   all_block_total=0;
188 
189   for (; o; o=o->next)
190     o->active=0;
191 }
192 
193 
pull_actives(game_object * o,game_object * & last_active,int & t)194 void level::pull_actives(game_object *o, game_object *&last_active, int &t)
195 {
196   int i=o->total_objects();
197   for (; i; i--)        // pull any linked object into active list
198   {
199     game_object *other=o->get_object(i-1);
200     if (!other->active)
201     {
202       other->active=1;
203       if (other->can_block())              // if object can block other player, keep a list for fast testing
204       {
205     add_block(other);
206     add_all_block(other);
207       } else if (other->hurtable())
208         add_all_block(other);
209 
210       t++;
211       last_active->next_active=other;
212       last_active=other;
213       pull_actives(o,last_active,t);
214     }
215   }
216 }
217 
add_actives(int32_t x1,int32_t y1,int32_t x2,int32_t y2)218 int level::add_actives(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
219 {
220   int t=0;
221   game_object *last_active=NULL;
222   if (first_active)
223     for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
224 
225   game_object *o=first;
226   for (; o; o=o->next)
227   {
228     if (!o->active)
229     {
230       int32_t xr=figures[o->otype]->rangex,
231            yr=figures[o->otype]->rangey;
232 
233       if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
234       {
235 
236     if (o->can_block())              // if object can block other player, keep a list for fast testing
237     {
238       add_block(o);
239       add_all_block(o);
240     } else if (o->hurtable())
241           add_all_block(o);
242 
243 
244     o->active=1;
245     t++;
246     if (!first_active)
247       first_active=o;
248     else
249           last_active->next_active=o;
250     last_active=o;
251 
252     pull_actives(o,last_active,t);
253       }
254     }
255   }
256   if (last_active)
257     last_active->next_active=NULL;
258   return t;
259 }
260 
261 
add_drawables(int32_t x1,int32_t y1,int32_t x2,int32_t y2)262 int level::add_drawables(int32_t x1, int32_t y1, int32_t x2, int32_t y2)
263 {
264   int t=0,ft=0;
265   game_object *last_active=NULL;
266   if (first_active)
267   {
268     for (last_active=first_active; last_active->next_active; last_active=last_active->next_active);
269   } else ft=1;
270 
271   game_object *o=first;
272   for (; o; o=o->next)
273   {
274     if (ft || !o->active)
275     {
276       int32_t xr=figures[o->otype]->draw_rangex,
277       yr=figures[o->otype]->draw_rangey;
278 
279       if (o->x+xr>=x1 && o->x-xr<=x2 && o->y+yr>=y1 && o->y-yr<=y2)
280       {
281     t++;
282     if (!first_active)
283     first_active=o;
284     else
285     last_active->next_active=o;
286     last_active=o;
287     o->active=1;
288       } else if (ft) o->active=0;  // if this is the first pass, then mark objects not in this ranges as not active
289     }
290   }
291   if (last_active)
292     last_active->next_active=NULL;
293   return t;
294 }
295 
296 
make_view_list(int nplayers)297 view *level::make_view_list(int nplayers)
298 {
299   int startable;
300   CONDITION(nplayers>0,"make_view_list with <=0 players!\n");
301   view *f=NULL;
302   int j,use_type=current_start_type;
303   figures[use_type]->cache_in();
304   game_object *o,*last_start=NULL;
305   int num=0;
306 
307   for (j=0,o=first; o && j<nplayers; o=o->next)
308   {
309     if (!strcmp(object_names[o->otype],"START"))
310     {
311       f=new view(create(use_type,o->x,o->y),f,num); num++;
312       f->focus->set_controller(f);
313       add_object_after(f->focus,o);
314       j++;
315       last_start=o;
316     }
317   }
318 
319   // if we couldn't find enough starts then create the rest of the players at the original start
320   startable=j;  // if we haven't created anyone yet, it's because we can't
321 
322   for (; j<nplayers; j++)
323   {
324     if (startable)
325     {
326       game_object *o=create(use_type,f->focus->x,f->focus->y);
327       f=new view(o,f,num); num++;
328       f->focus->set_controller(f);
329       add_object_after(o,last_start);
330     }
331     else
332     {
333       f=new view(NULL,f,num);
334       num++;
335     }
336   }
337   return f;
338 }
339 
wall_push()340 void level::wall_push()
341 {
342   int32_t sx1,sy1,sx2,sy2,xv,yv;
343   game_object *o=first_active;
344   for (; o; o=o->next_active)
345   {
346     if (o->pushable())
347     {
348       o->picture_space(sx1,sy1,sx2,sy2);
349       xv=sx1-o->x;
350       yv=0;
351       o->try_move(o->x,o->y-1,xv,yv,1);         // check for wall pushes on the left using feet
352       if (xv!=sx1-o->x)                         // is the character in the wall?
353       {
354     xv=-xv;
355     o->try_move(o->x,o->y-1,xv,yv,1);       // see how far to the right we can push the character
356     o->x+=xv;
357       } else
358       {
359     xv=sx2-o->x;
360     o->try_move(o->x,o->y-1,xv,yv,1);      // now check the right of the character for a wall
361     if (xv!=sx2-o->x)
362     {
363       xv=-xv;
364       o->try_move(o->x,o->y-1,xv,yv,1);
365       o->x+=xv;
366     }
367       }
368     }
369   }
370 }
371 
372 
try_pushback(game_object * subject,game_object * target)373 void level::try_pushback(game_object *subject,game_object *target)
374 {
375   if (subject->pushable() && target->pushable() &&
376       subject->state!=dead && target->state!=dead &&
377       subject->state!=dieing && target->state!=dieing)
378   {
379     int b1=subject->push_range(),b2=target->push_range();
380     if (abs(subject->x-target->x)<b1+b2)
381     {
382       int32_t tmove=b1+b2-abs(subject->x-target->x),xv,yv=0,xv2;
383       if (subject->x>target->x)
384         xv=tmove/2;
385       else xv=-tmove/2;
386       xv2=-xv;
387 
388       subject->try_move(subject->x,subject->y,xv,yv,3);
389       subject->x+=xv;
390 
391       yv=0;
392       target->try_move(target->x,target->y,xv2,yv,3);
393       target->x+=xv2;
394     }
395   }
396 }
397 
398 /*
399 void level::check_collisions()
400 {
401   game_object *target,*reciever=NULL;
402   int32_t sx1,sy1,sx2,sy2,tx1,ty1,tx2,ty2,hitx,hity,
403       s_centerx,t_centerx;
404 
405   for (game_object *subject=first_active; subject; subject=subject->next_active)
406   {
407     subject->picture_space(sx1,sy1,sx2,sy2);
408     s_centerx=subject->x_center();
409 
410     int hit=0;
411     reciever=NULL;
412     for (target=first_active; target; target=target->next_active)
413     {
414       if (target!=subject)
415       {
416     target->picture_space(tx1,ty1,tx2,ty2);
417 
418         if (!(sx2<tx1 || sx1>tx2 || sy1>ty2 || sy2<ty1))  // are they semi/overlapping?
419         {
420       try_pushback(subject,target);
421       if (subject->can_hurt(target))    // see if we can hurt him before calculating
422       {
423         t_centerx=target->x_center();
424         point_list *s_hit,*t_damage;
425 
426         s_hit=subject->current_figure()->hit;
427         t_damage=target->current_figure()->damage;
428 
429         unsigned char *s_dat=s_hit->data,
430         *t_dat;
431         int i,j;
432         for (i=(int)s_hit->tot-1; i>0 && !hit; i--)
433         {
434           for (t_dat=t_damage->data,j=(int)t_damage->tot-1; j>0 && !hit; j--)
435           {
436         int32_t x1,y1,x2,y2,          // define the two line segments to check
437         xp1,yp1,xp2,yp2;
438 
439         xp1=target->x+target->tx(*t_dat);  t_dat++;
440         yp1=target->y+target->ty(*t_dat);  t_dat++;
441         xp2=target->x+target->tx(*t_dat);
442         yp2=target->y+target->ty(t_dat[1]);
443 
444         x1=subject->x+subject->tx(s_dat[0]);
445         y1=subject->y+subject->ty(s_dat[1]);
446         x2=subject->x+subject->tx(s_dat[2]);
447         y2=subject->y+subject->ty(s_dat[3]);
448 
449 
450         // ok, now we know which line segemnts to check for intersection
451         // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
452         int _x2=x2,_y2=y2;
453         setback_intersect(x1, y1, x2, y2, xp1, yp1, xp2, yp2,0);
454 
455 
456         if (x2!=_x2 || _y2!=y2)
457         {
458           reciever=target;
459           hitx=((x1+x2)/2+(xp1+xp2)/2)/2;
460           hity=((y1+y1)/2+(yp1+yp2)/2)/2;
461         }
462           }
463           s_dat+=2;
464         }
465       }
466     }
467       }
468     }
469     if (reciever)
470     {
471       reciever->do_damage((int)subject->current_figure()->hit_damage,subject,hitx,hity,0,0);
472       subject->note_attack(reciever);
473       hit=1;
474     }
475   }
476 }
477 */
478 
boundary_setback(game_object * subject,int32_t x1,int32_t y1,int32_t & x2,int32_t & y2)479 game_object *level::boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
480 {
481   game_object *l=NULL;
482   int32_t tx1,ty1,tx2,ty2,t_centerx;
483   game_object *target=first_active;
484   game_object **blist=block_list;
485   int t=block_total;
486   for (; t; t--,blist++)
487   {
488     target=*blist;
489     if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
490     {
491       target->picture_space(tx1,ty1,tx2,ty2);
492       if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
493         (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
494       {
495     t_centerx=target->x_center();
496     boundary *t_damage;
497     if (target->direction>0)
498     t_damage=target->current_figure()->f_damage;
499     else
500     t_damage=target->current_figure()->b_damage;
501     unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
502     int iter=t_damage->tot-1;
503     while(iter-->0)
504     {
505       int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
506       int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
507       int32_t xp2=target->x+target->tx(*t_dat);
508       int32_t yp2=target->y+target->ty(t_dat[1]);
509 
510       // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
511       if (*ins)
512       {
513         if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
514         l=target;
515       }
516       else
517       {
518         if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
519         l=target;
520       }
521       ins++;
522 
523     }
524       }
525     }
526   }
527   return l;       // return the last person we intersected
528 }
529 
530 
all_boundary_setback(game_object * subject,int32_t x1,int32_t y1,int32_t & x2,int32_t & y2)531 game_object *level::all_boundary_setback(game_object *subject, int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
532 {
533   game_object *l=NULL;
534   int32_t tx1,ty1,tx2,ty2,t_centerx;
535   game_object *target=first_active;
536   game_object **blist=all_block_list;
537   int t=all_block_total;
538   for (; t; t--,blist++)
539   {
540     target=*blist;
541     if (target!=subject && (target->total_objects()==0 || target->get_object(0)!=subject))
542     {
543       target->picture_space(tx1,ty1,tx2,ty2);
544       if (!((x2<tx1 && x1<tx1) || (x1>tx2 && x2>tx2) ||
545         (y1>ty2 && y2>ty2) || (y1<ty1 && y2<ty1)))  // are they semi/overlapping?
546       {
547     t_centerx=target->x_center();
548     boundary *t_damage;
549     if (target->direction>0)
550     t_damage=target->current_figure()->f_damage;
551     else
552     t_damage=target->current_figure()->b_damage;
553     unsigned char *t_dat=t_damage->data,*ins=t_damage->inside;
554     int iter=t_damage->tot-1;
555     while(iter-->0)
556     {
557       int32_t xp1=target->x+target->tx(*t_dat);  t_dat++;
558       int32_t yp1=target->y+target->ty(*t_dat);  t_dat++;
559       int32_t xp2=target->x+target->tx(*t_dat);
560       int32_t yp2=target->y+target->ty(t_dat[1]);
561 
562       // now check to see if (x1,y1-x2,y2) intercest with (xp1,yp1-xp2,yp2)
563       if (*ins)
564       {
565         if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1))
566         l=target;
567       }
568       else
569       {
570         if (setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1))
571         l=target;
572       }
573       ins++;
574     }
575       }
576     }
577   }
578   return l;       // return the last person we intersected
579 }
580 
581 
582 //bFILE *rcheck=NULL,*rcheck_lp=NULL;
583 
interpolate_draw_objects(view * v)584 void level::interpolate_draw_objects(view *v)
585 {
586   int32_t old_x,old_y;
587   current_view=v;
588 
589   game_object *o=first_active;
590   for (; o; o=o->next_active)
591   {
592     old_x=o->x;
593     old_y=o->y;
594     o->x=(o->last_x+o->x)/2;
595     o->y=(o->last_y+o->y)/2;
596     o->last_x=old_x;
597     o->last_y=old_y;
598   }
599 
600   for (o=first_active; o; o=o->next_active)
601     o->draw();
602 
603   for (o=first_active; o; o=o->next_active)
604   {
605     o->x=o->last_x;
606     o->y=o->last_y;
607   }
608 }
609 
610 bFILE *rcheck=NULL,*rcheck_lp=NULL;
611 
612 extern int sshot_fcount,screen_shot_on;
613 
tick()614 int level::tick()
615 {
616   game_object *o,*l=NULL,  // l is last, used for delete
617               *cur;        // cur is current object, NULL if object deletes it's self
618   int ret=1;
619 
620   if (profiling())
621     profile_reset();
622 
623 /*  // test to see if demo is in sync
624   if (current_demo_mode()==DEMO_PLAY)
625   {
626     if (!rcheck) rcheck=open_file("rcheck","rb");
627     int32_t x=rcheck->read_uint32();
628     if (x!=rand_on)
629       dprintf("off!\n");
630   } else if (current_demo_mode()==DEMO_RECORD)
631   {
632     if (!rcheck)
633     {
634       rcheck=open_file("rcheck","wb");
635       rcheck_lp=open_file("rcheck.lp","wb");
636     }
637     rcheck->write_uint32(rand_on);
638   } else
639   {
640     if (rcheck)
641     {
642       delete rcheck;
643       rcheck=NULL;
644     }
645     if (rcheck_lp)
646     {
647       delete rcheck_lp;
648       rcheck_lp=NULL;
649     }
650   }*/
651 
652   for (o=first_active; o; )
653   {
654     o->last_x=o->x;
655     o->last_y=o->y;
656     cur=o;
657     view *c=o->controller();
658     if (!(dev&SUSPEND_MODE) || c)
659     {
660       o->set_flags(o->flags()&(0xff-FLAG_JUST_HIT-FLAG_JUST_BLOCKED));
661 
662       if (c)
663       {
664     area_controller *a,*smallest=NULL;
665     int32_t smallest_size=0xffffffff;
666     for (a=area_list; a; a=a->next)
667       if (o->x>=a->x && o->y>=a->y && o->x<=a->x+a->w && o->y<=a->y+a->h)
668       {
669         int32_t size=a->w*a->h;
670         if (size<smallest_size)
671         {
672           smallest=a;
673           smallest_size=size;
674         }
675       }
676 
677     if (c->local_player())
678     {
679       if (!shutdown_lighting)       // should we initiate a lighting shutdown?
680       {
681         if (massive_frame_panic>30)
682         {
683           shutdown_lighting=100;
684           shutdown_lighting_value=c->ambient;
685         }
686       } else if (massive_frame_panic)  // do we need brighten towards 63?
687       {
688         if (shutdown_lighting_value<63)
689           shutdown_lighting_value++;
690       } else if (shutdown_lighting>1)        // delay for some time before turning back on
691         shutdown_lighting--;
692       else if (shutdown_lighting_value!=c->ambient) // do we need to lower light toward real ambient?
693       {
694         if (abs(shutdown_lighting_value-c->ambient)<4)
695           shutdown_lighting_value=c->ambient;
696         else
697           if (shutdown_lighting_value<c->ambient)
698               shutdown_lighting_value+=4;
699         else if (shutdown_lighting_value>c->ambient)
700           shutdown_lighting_value-=4;
701       } else shutdown_lighting=0;                    // back to normal
702     }
703 
704     if (smallest)
705       c->configure_for_area(smallest);
706 
707 
708     o->move(c->x_suggestion,c->y_suggestion,c->b1_suggestion|(c->b2_suggestion<<1)|
709         (c->b3_suggestion<<2));
710 
711     if (o->otype!=current_start_type)
712     {
713       int32_t fmp=o->fmp();
714       int reduce=figures[o->otype]->morph_power;
715       if (reduce)
716       {
717         fmp-=reduce;
718         o->add_power(fmp>>16);
719         o->set_fmp(fmp&0xffff);
720         if (o->mp()<=0)
721         o->morph_into(current_start_type,NULL,-1,9);
722       }
723     }
724 
725     l=o;
726     o=o->next_active;
727       }
728       else if (!o->decide())      // if object returns 0, delete it... I don't like 0's :)
729       {
730     game_object *p=o;
731     o=o->next_active;
732     delete_object(p);
733     cur=NULL;
734       } else
735       {
736     o=o->next_active;
737     l=o;
738       }
739     } else
740     {
741       o=o->next_active;
742       l=o;
743     }
744 
745     clear_tmp();
746 
747     if (cur)
748     {
749       point_list *p=cur->current_figure()->hit;  // see if this character is on an attack frame
750       if (p && p->tot)
751         add_attacker(cur);               // if so add him to attack list for later collision detect
752 
753       if (cur->hurtable())                    // add to target list if is hurtable
754         add_target(cur);
755 
756     }
757 
758   }
759   tick_panims();
760 
761   check_collisions();
762 //  wall_push();
763 
764   set_tick_counter(tick_counter()+1);
765 
766   if (sshot_fcount!=-1)
767   {
768     sshot_fcount++;
769     if ((sshot_fcount%70)==0)
770     {
771       char name[100];
772       sprintf(name,"shot%04d.pcx",screen_shot_on++);
773       write_PCX(screen,pal,name);
774     }
775   }
776 
777   return ret;
778 }
779 
set_tick_counter(uint32_t x)780 void level::set_tick_counter(uint32_t x)
781 {
782   ctick=x;
783 }
784 
draw_areas(view * v)785 void level::draw_areas(view *v)
786 {
787   int32_t sx1,sy1,sx2,sy2;
788   area_controller *a=area_list;
789   for (; a; a=a->next)
790   {
791     int c1,c2;
792     if (a->active)
793     {
794       c1=morph_sel_frame_color;
795       c2=wm->bright_color();
796     } else
797     {
798       c2=morph_sel_frame_color;
799       c1=wm->bright_color();
800     }
801 
802     the_game->game_to_mouse(a->x,a->y,v,sx1,sy1);
803     the_game->game_to_mouse(a->x+a->w,a->y+a->h,v,sx2,sy2);
804     screen->rectangle(sx1,sy1,sx2,sy2,c1);
805     screen->bar(sx1-1,sy1-1,sx1+1,sy1+1,c2);
806     screen->bar(sx2-1,sy2-1,sx2+1,sy2+1,c2);
807   }
808 }
809 
draw_objects(view * v)810 void level::draw_objects(view *v)
811 {
812   current_view=v;
813   game_object *o=first_active;
814   if (dev&MAP_MODE)
815   {
816     for (; o; o=o->next_active)
817       o->map_draw();
818   } else
819   {
820     for (; o; o=o->next_active)
821       o->draw();
822   }
823 
824   clear_tmp();
825 }
826 
calc_bgsize(uint16_t fgw,uint16_t fgh,uint16_t & bgw,uint16_t & bgh)827 void calc_bgsize(uint16_t fgw, uint16_t  fgh, uint16_t  &bgw, uint16_t  &bgh)
828 {
829   bgw=fgw/ASPECT+8;
830   bgh=fgh/ASPECT+8;
831 }
832 
833 
set_size(int w,int h)834 void level::set_size(int w, int h)
835 {
836   if (w*h>200000)
837   {
838     the_game->show_help(symbol_str("too_big"));
839     return ;
840   }
841 
842   uint16_t *new_fg,*new_bg;
843   new_fg=(uint16_t *)malloc(w*h*sizeof(int16_t));
844   memset(new_fg,0,w*h*sizeof(int16_t));
845 
846   int x,y,miny=(h<fg_height)? h : fg_height,minx=(w<fg_width)? w : fg_width;
847 
848   uint16_t nbw,nbh;
849   calc_bgsize(w,h,nbw,nbh);
850 
851   new_bg=(uint16_t *)malloc((int)nbw*(int)nbh*sizeof(int16_t));
852   memset(new_bg,0,(int)nbw*(int)nbh*sizeof(int16_t));
853 
854   for (y=0; y<miny; y++)
855     for (x=0; x<minx; x++)
856       new_fg[x+y*w]=get_fg(x,y);
857 
858   miny=(nbh<bg_height) ? nbh : bg_height;
859   minx=(nbw<bg_width) ? nbw : bg_width;
860 
861   for (y=0; y<miny; y++)
862     for (x=0; x<minx; x++)
863       new_bg[x+y*nbw]=get_bg(x,y);
864 
865   free(map_fg);
866   free(map_bg);
867   map_fg=new_fg;
868   map_bg=new_bg;
869   fg_width=w;
870   fg_height=h;
871   bg_height=nbh;
872   bg_width=nbw;
873 
874   char msg[80];
875   sprintf(msg,"Level %s size now %d %d\n",name(),foreground_width(),foreground_height());
876   the_game->show_help(msg);
877 }
878 
879 
locate_var(bFILE * fp,spec_directory * sd,char * str,int size)880 int locate_var(bFILE *fp, spec_directory *sd, char *str, int size)
881 {
882   spec_entry *se=sd->find(str);
883   if (se)
884   {
885     fp->seek(se->offset,0);
886     if (RC_type_size(fp->read_uint8())!=size)
887       return 0;
888     else return 1;
889   }
890   return 0;
891 }
892 
893 
894 // load objects assumes current objects have already been disposed of
old_load_objects(spec_directory * sd,bFILE * fp)895 void level::old_load_objects(spec_directory *sd, bFILE *fp)
896 {
897   spec_entry *se=sd->find("objects");
898   total_objs=0;
899   first=last=first_active=NULL;
900   int i,j;
901   if (se)
902   {
903     fp->seek(se->offset,0);
904     /******************************* Read debug info ******************************/
905     int16_t old_tot=fp->read_uint16();
906     uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
907     char old_name[150];
908     for (i=0; i<old_tot; i++)
909     {
910       fp->read(old_name,fp->read_uint8());    // read the name
911       for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
912       {
913     if (!strcmp(old_name,object_names[j]))
914           o_remap[i]=j;
915       }
916     }
917 
918 
919     /***************************** Read state names *********************************/
920     int old_stot=fp->read_uint16();
921     unsigned char *s_remap=(unsigned char *)malloc(old_stot);
922     for (i=0; i<old_stot; i++)
923     {
924       fp->read(old_name,fp->read_uint8());
925       s_remap[i]=stopped;           // non exsitant states get mapped into stopped state
926       for (j=0; j<MAX_STATE; j++)                  // see if old state exist now
927     if (!strcmp(state_names[j],old_name))
928          s_remap[i]=j;
929     }
930     total_objs=fp->read_uint32();
931 
932     se=sd->find("type");
933     if (se)
934     {
935       fp->seek(se->offset,0);
936       last=NULL;
937       if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
938       {
939     for (i=0; i<total_objs; i++)
940     {
941       uint16_t t=fp->read_uint16();
942       game_object *p=new game_object(o_remap[t],1);
943       clear_tmp();
944       if (!first) first=p; else last->next=p;
945       last=p; p->next=NULL;
946     }
947 
948 
949     se=sd->find("state");
950     if (se)
951     {
952       fp->seek(se->offset,0);
953       if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
954       {
955         game_object *l=first;
956         for (i=0; i<total_objs; i++,l=l->next)
957         {
958           character_state s=(character_state)s_remap[fp->read_uint16()];
959           if (l->otype!=0xffff)
960           {
961         if (l->has_sequence((character_state)s))
962           l->state=s;
963         else l->state=stopped;
964         l->current_frame=0;
965           }
966         }
967       }
968     }
969 
970     int frame_var=0;
971     int i=0;
972     for (; i<TOTAL_OBJECT_VARS; i++)
973       if (!strcmp(object_descriptions[i].name,"cur_frame"))
974         frame_var=i;
975 
976     int j=0;
977     for (; j<default_simple.total_vars(); j++)
978     {
979       spec_entry *se=sd->find(object_descriptions[j].name);
980       if (se)
981       {
982         fp->seek(se->offset,0);
983         int t=object_descriptions[j].type;
984         if (fp->read_uint8()!=t)
985           dprintf("Warning : load level -> var '%s' size changed\n");
986         else
987         {
988           game_object *f=first;
989           for (; f; f=f->next)
990           {
991         switch (t)
992         {
993           case RC_8 : f->set_var(j,fp->read_uint8()); break;
994           case RC_16 : f->set_var(j,fp->read_uint16()); break;
995           case RC_32 : f->set_var(j,fp->read_uint32()); break;
996         }
997 
998         // check to make sure the frame number is not out of bounds from the time
999         // it was last saved
1000         if (j==frame_var)
1001         {
1002           if (f->otype!=0xffff && f->current_frame>=
1003               figures[f->otype]->get_sequence(f->state)->length())
1004             f->current_frame=0;
1005         }
1006           }
1007         }
1008       } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1009     }
1010       }
1011     }
1012 
1013     free(o_remap);
1014     free(s_remap);
1015   }
1016 
1017 }
1018 
1019 
1020 // load objects assumes current objects have already been disposed of
load_objects(spec_directory * sd,bFILE * fp)1021 void level::load_objects(spec_directory *sd, bFILE *fp)
1022 {
1023   spec_entry *se=sd->find("object_descripitions");
1024   total_objs=0;
1025   first=last=first_active=NULL;
1026   int i,j;
1027   if (!se)
1028   {
1029     old_load_objects(sd,fp);
1030     return ;
1031   }
1032   else if (se)
1033   {
1034     fp->seek(se->offset,0);
1035     int16_t old_tot=fp->read_uint16();
1036     se=sd->find("describe_names");
1037     if (!se || !old_tot)
1038       return ;
1039 
1040     uint16_t *o_remap=(uint16_t *)malloc(old_tot * 2);
1041     uint16_t *o_backmap=(uint16_t *)malloc(total_objects * 2);
1042     memset(o_backmap,0xff,total_objects*2);
1043     char old_name[150];
1044     for (i=0; i<old_tot; i++)
1045     {
1046       fp->read(old_name,fp->read_uint8());    // read the name
1047       for (o_remap[i]=0xffff,j=0; j<total_objects; j++)  // check for matching current name
1048       {
1049     if (!strcmp(old_name,object_names[j]))
1050     {
1051           o_remap[i]=j;
1052       o_backmap[j]=i;
1053     }
1054       }
1055     }
1056 
1057     se=sd->find("describe_states");
1058     if (!se) { free(o_remap); free(o_backmap); return ; }
1059     int16_t **s_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1060     int16_t *s_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1061     fp->seek(se->offset,0);
1062     int i=0;
1063     for (; i<old_tot; i++)
1064     {
1065       int16_t t=fp->read_uint16();
1066       s_remap_totals[i]=t;
1067       if (t)
1068       {
1069         s_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1070     int j=0;
1071     for (; j<t; j++)
1072       *(s_remap[i]+j)=stopped;    // if no remap found, then go to stopped state
1073       }
1074       else s_remap[i]=0;
1075 
1076       int j=0;
1077       for (; j<t; j++)
1078       {
1079     fp->read(old_name,fp->read_uint8());
1080     int new_type=o_remap[i];
1081     if (new_type<total_objects)     // make sure old object still exsist
1082     {
1083       int k=0;
1084       for (; k<figures[new_type]->ts; k++)
1085       {
1086         if (figures[new_type]->seq[k] &&
1087            !strcmp(lstring_value(((LSymbol *)figures[new_type]->seq_syms[k])->GetName()),old_name))
1088         *(s_remap[i]+j)=k;
1089       }
1090     }
1091       }
1092     }
1093 
1094     int16_t **v_remap=NULL;
1095     int16_t *v_remap_totals=NULL;
1096     int load_vars=1;
1097     se=sd->find("describe_lvars");
1098     if (se)
1099     {
1100       v_remap=(int16_t **)malloc(old_tot*sizeof(int16_t *));
1101       v_remap_totals=(int16_t *)malloc(old_tot*sizeof(int16_t));
1102 
1103       fp->seek(se->offset,0);
1104       int i=0;
1105       for (; i<old_tot; i++)
1106       {
1107     int16_t t=fp->read_uint16();
1108     v_remap_totals[i]=t;
1109     if (t)
1110     {
1111       v_remap[i]=(int16_t *)malloc(t*sizeof(int16_t));
1112       memset(v_remap[i],0xff,t*sizeof(int16_t));
1113     } else { v_remap[i]=NULL; }
1114     int j=0;
1115     for (; j<t; j++)
1116     {
1117       fp->read(old_name,fp->read_uint8());
1118       int new_type=o_remap[i];
1119       if (new_type!=0xffff)        // make sure old object still exsist
1120       {
1121         int k=0;
1122         for (; k<figures[new_type]->tiv; k++)
1123         {
1124           if (figures[new_type]->vars[k])
1125           {
1126         if (!strcmp(lstring_value(((LSymbol *)figures[new_type]->vars[k])->GetName()),old_name))
1127           *(v_remap[i]+j)=figures[new_type]->var_index[k];
1128           }
1129         }
1130       }
1131     }
1132       }
1133       load_vars=1;
1134     }
1135 
1136     se=sd->find("object_list");
1137     if (se)
1138     {
1139       total_objs=fp->read_uint32();
1140 
1141       se=sd->find("type");
1142       if (se)
1143       {
1144     fp->seek(se->offset,0);
1145     last=NULL;
1146     if (fp->read_uint8()==RC_16)    //  read type array, this should be type RC_16
1147     {
1148       int i=0;
1149       for (; i<total_objs; i++)
1150       {
1151         uint16_t t=fp->read_uint16();
1152         game_object *p=new game_object(o_remap[t],1);
1153         clear_tmp();
1154         if (!first) first=p; else last->next=p;
1155         last=p; p->next=NULL;
1156       }
1157 
1158       se=sd->find("state");
1159       if (se)
1160       {
1161         fp->seek(se->offset,0);
1162         if (fp->read_uint8()==RC_16)    //  read state array, this should be type RC_16
1163         {
1164           game_object *l=first;
1165           for (i=0; i<total_objs; i++,l=l->next)
1166           {
1167         int st=fp->read_uint16();
1168         if (l->otype==0xffff)
1169           l->state=stopped;
1170         else
1171         {
1172           character_state s=(character_state)(*(s_remap[o_backmap[l->otype]]+st));
1173           if (l->has_sequence((character_state)s))
1174                 l->state=s;
1175           else l->state=stopped;
1176           l->current_frame=0;
1177         }
1178           }
1179         }
1180       }
1181 
1182       se=sd->find("lvars");
1183       if (se && load_vars)
1184       {
1185         fp->seek(se->offset,0);
1186         int abort=0;
1187         game_object *o=first;
1188         for (; o && !abort; o=o->next)
1189         {
1190           int16_t ot=fp->read_uint16();
1191           int k=0;
1192           for (; k<ot; k++)
1193           {
1194         if (fp->read_uint8()!=RC_32) abort=1;
1195         else
1196         {
1197           int32_t v=fp->read_uint32();
1198           if (o->otype!=0xffff)     // non-exstant object
1199           {
1200             int remap=*(v_remap[o_backmap[o->otype]]+k);
1201             if (remap!=-1 && figures[o->otype]->tiv>=k)
1202             {
1203               o->lvars[remap]=v;
1204             }
1205           }
1206         }
1207           }
1208         }
1209       }
1210 
1211       int frame_var=0;
1212       for (i=0; i<TOTAL_OBJECT_VARS; i++)
1213         if (!strcmp(object_descriptions[i].name,"cur_frame"))
1214           frame_var=i;
1215 
1216 
1217       int j=0;
1218       for (; j<default_simple.total_vars(); j++)
1219       {
1220         spec_entry *se=sd->find(object_descriptions[j].name);
1221         if (se)
1222         {
1223           fp->seek(se->offset,0);
1224           int t=object_descriptions[j].type;
1225           if (fp->read_uint8()!=t)
1226             dprintf("Warning : load level -> var '%s' size changed\n");
1227           else
1228           {
1229         game_object *f=first;
1230         for (; f; f=f->next)
1231         {
1232           switch (t)
1233           {
1234             case RC_8 :
1235             { f->set_var(j,fp->read_uint8()); } break;
1236             case RC_16 :
1237             { f->set_var(j,fp->read_uint16()); } break;
1238             case RC_32 :
1239             { f->set_var(j,fp->read_uint32()); } break;
1240           }
1241 
1242           // check to make sure the frame number is not out of bounds from the time
1243           // it was last saved
1244           if (j==frame_var)
1245           {
1246             if (f->otype!=0xffff && f->current_frame>=
1247             figures[f->otype]->get_sequence(f->state)->length())
1248             f->current_frame=0;
1249           }
1250         }
1251           }
1252         } else dprintf("Warning : load level -> no previous var %s\n",default_simple.var_name(j));
1253       }
1254     }
1255       }
1256     }
1257 
1258     int k=0;
1259     for (; k<old_tot; k++)
1260     {
1261       if (s_remap_totals[k])
1262         free(s_remap[k]);
1263     }
1264 
1265     int l=0;
1266     for (; l<old_tot; l++)
1267     {
1268       if (v_remap_totals[l])
1269         free(v_remap[l]);
1270     }
1271     free(v_remap_totals);
1272     free(s_remap_totals);
1273     free(o_remap);
1274     free(o_backmap);
1275     free(s_remap);
1276     free(v_remap);
1277   }
1278 
1279 }
1280 
level(spec_directory * sd,bFILE * fp,char const * lev_name)1281 level::level(spec_directory *sd, bFILE *fp, char const *lev_name)
1282 {
1283   spec_entry *e;
1284   area_list=NULL;
1285 
1286   attack_list=NULL;
1287   attack_list_size=attack_total=0;
1288 
1289   target_list=NULL;
1290   target_list_size=target_total=0;
1291 
1292   block_list=NULL;
1293   block_list_size=block_total=0;
1294 
1295   all_block_list=NULL;
1296   all_block_list_size=all_block_total=0;
1297   first_name=NULL;
1298 
1299   the_game->need_refresh();
1300 
1301   char cmd[100];
1302   sprintf(cmd,symbol_str("loading"),lev_name);
1303   stack_stat stat(cmd);
1304   Name = strdup(lev_name);
1305 
1306   e=sd->find("first name");
1307   if (e)
1308   {
1309     fp->seek(e->offset,0);
1310     int len=fp->read_uint8();   // read the length of the string
1311     first_name=(char *)malloc(len);
1312     fp->read(first_name,len);    // read the string
1313   } else
1314   {
1315     first_name = strdup(Name);
1316   }
1317 
1318   e=sd->find("fgmap");
1319   int no_fg=0,no_bg=0;
1320 
1321   if (e)
1322   {
1323     fp->seek(e->offset,0);
1324     fg_width=fp->read_uint32();
1325     fg_height=fp->read_uint32();
1326     map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1327     fp->read((char *)map_fg,2*fg_width*fg_height);
1328     int t=fg_width*fg_height;
1329     uint16_t *map=map_fg;
1330     while (t) { *map=lstl(*map); map++; t--; }
1331   } else
1332   {
1333     the_game->show_help("Warning foreground map missing");
1334     no_fg=1;
1335   }
1336   stat_man->update(5);
1337 
1338   e=sd->find("bgmap");
1339   if (e)
1340   {
1341     fp->seek(e->offset,0);
1342     bg_width=fp->read_uint32();
1343     bg_height=fp->read_uint32();
1344     map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1345     fp->read((char *)map_bg,2*bg_width*bg_height);
1346     int t=bg_width*bg_height;
1347     uint16_t *map=map_bg;
1348     while (t) { *map=lstl(*map); map++; t--; }
1349   } else
1350   {
1351     the_game->show_help("Warning background map missing");
1352     no_bg=1;
1353   }
1354 
1355   if (no_fg && !no_bg)
1356   {
1357     fg_width=bg_width;
1358     fg_height=bg_height;
1359     map_fg=(uint16_t *)malloc(2*fg_width*fg_height);
1360     memset(map_fg,0,2*fg_width*fg_height);
1361   }
1362 
1363   if (no_bg)
1364   {
1365     bg_width=fg_width/8+8;
1366     bg_height=fg_height/8+8;
1367     map_bg=(uint16_t *)malloc(2*bg_width*bg_height);
1368     memset(map_bg,0,2*bg_width*bg_height);
1369   }
1370   stat_man->update(10);
1371 
1372   /***************** Check map for non exsistant tiles **************************/
1373   int32_t i,w;
1374   uint16_t *m;
1375   spec_entry *load_all=sd->find("player_info");
1376   for (i=0,w=fg_width*fg_height,m=map_fg; i<w; i++,m++)
1377   {
1378     if (!load_all)
1379       (*m)=(*m)&(~0x8000);    // clear the has-seen bit on the tile
1380 
1381     if (fgvalue(*m)>=nforetiles || foretiles[fgvalue(*m)]<0)
1382       *m=0;
1383   }
1384 
1385   for (i=0,w=bg_width*bg_height,m=map_bg; i<w; i++,m++)
1386   {
1387     if ( (bgvalue(*m)>=nbacktiles) || backtiles[bgvalue(*m)]<0)
1388        *m=0;
1389   }
1390 
1391   load_options(sd,fp);
1392   stat_man->update(15);
1393 
1394 //  first=first_active=last=NULL;
1395   load_objects(sd,fp);
1396   stat_man->update(25);
1397 
1398   object_node *players,*objs;
1399   players=make_player_onodes();
1400   objs=make_not_list(players);
1401 
1402 
1403 
1404   read_lights(sd,fp,lev_name);
1405   load_links(fp,sd,objs,players);
1406   int players_got_loaded=load_player_info(fp,sd,objs);
1407 
1408 
1409   game_object *l=first;
1410   for (; l; )
1411   {
1412     game_object *p=l;
1413     l=l->next;
1414     if (p->otype==0xffff || p->x<0 || p->y<0)
1415       delete_object(p);
1416   }
1417 
1418   load_cache_info(sd,fp);
1419 
1420   if (!players_got_loaded)
1421   {
1422     level *old=current_level;
1423     current_level=this;
1424 
1425     object_node *list=NULL;
1426     list=make_not_list(list);     // create a list of the object list in case objects change positions
1427 
1428     object_node *ln=list;
1429     for (; ln; ln=ln->next)
1430       ln->me->reload_notify();
1431     delete_object_list(list);
1432 
1433     current_level=old;
1434 
1435     insert_players();
1436   }
1437 
1438   delete_object_list(players);
1439   delete_object_list(objs);
1440 
1441 }
1442 
1443 
1444 /*
1445    [object_descriptions] 2 total_type
1446    for(1..total_types)
1447    {
1448      ["object_names"]  1,(name)
1449 
1450      ["object_states"]  2(total),<2=number,1,name>
1451 
1452      ["object_lvars"]   2(total),<1(type),1,name>
1453    }
1454 
1455   [object_list]
1456    4 total_objects
1457    for(1..total_objects)
1458    {
1459      ["type"]
1460      ["state"]
1461      ["lvars"]
1462      ...
1463    }
1464 
1465 */
1466 
1467 
get_prof_assoc_filename(char * filename,char * prof_filename)1468 void get_prof_assoc_filename(char *filename, char *prof_filename)
1469 {
1470   char *s1,*s2,*dot=NULL;
1471   for (s1=filename,s2=prof_filename,dot=NULL; *s1; s1++,s2++)
1472   {
1473     *s2=*s1;
1474     if (*s1=='.') dot=s2;
1475   }
1476   if (dot) s2=dot+1;
1477 
1478   *(s2++)='c';
1479   *(s2++)='p';
1480   *(s2++)='f';
1481   *s2=0;
1482 }
1483 
level_loaded_notify()1484 void level::level_loaded_notify()
1485 {
1486   char *n;
1487   if (first_name)
1488     n=first_name;
1489   else
1490     n=name();
1491   if (strstr(n,"levels/level"))
1492   {
1493     char nm[100];
1494     sprintf(nm,"music/abuse%c%c.hmi",n[12],n[13]);
1495     bFILE *fp=open_file(nm,"rb");
1496     if (fp->open_failure())
1497     {
1498       delete fp;
1499     }
1500     else
1501     {
1502       if (current_song) { current_song->stop(); delete current_song; }
1503 
1504       delete fp;
1505       current_song=new song(nm);
1506       current_song->play(music_volume);
1507     }
1508   }
1509 
1510 /*  if (DEFINEDP(symbol_function(l_level_loaded)))
1511   {
1512     int sp=current_space;
1513     current_space=PERM_SPACE;
1514 
1515     void *arg_list=NULL;
1516     PtrRef r1(arg_list);
1517     push_onto_list(LString::Create(n),arg_list);
1518     ((LSymbol *)l_level_loaded)->EvalFunction(arg_list);
1519 
1520     current_space=sp;
1521   } */
1522 }
1523 
1524 
create_dir(char * filename,int save_all,object_node * save_list,object_node * exclude_list)1525 bFILE *level::create_dir(char *filename, int save_all,
1526              object_node *save_list, object_node *exclude_list)
1527 {
1528   spec_directory sd;
1529   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"Copyright 1995 Crack dot Com, All Rights reserved",NULL,0,0));
1530   if (first_name)
1531     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"first name",NULL,strlen(first_name)+2,0));
1532 
1533 
1534 
1535   sd.add_by_hand(new spec_entry(SPEC_GRUE_FGMAP,"fgmap",NULL,4+4+fg_width*fg_height*2,0));
1536   sd.add_by_hand(new spec_entry(SPEC_GRUE_BGMAP,"bgmap",NULL,4+4+bg_width*bg_height*2,0));
1537   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"bg_scroll_rate",NULL,1+4*4,0));
1538 
1539   int ta=0;
1540   area_controller *a=area_list;
1541   for (; a; a=a->next) ta++;
1542 
1543   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"area_list.v1",NULL,1+ta*(4*11)+4,0));
1544 
1545   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"tick_counter",NULL,1+4,0));
1546 
1547 
1548 
1549   // how many object types are we goint to save, use a short to specify how many
1550   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_descripitions",NULL,2,0));
1551 
1552 
1553   int size=0;
1554   int i=0;
1555   for (; i<total_objects; i++)       // now save the names of the objects so if ordering
1556     size+=1+strlen(object_names[i])+1;    // changes in future versions we can adjust in load
1557   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_names",NULL,size,0));
1558 
1559 
1560   size=0;
1561   for (i=0; i<total_objects; i++)
1562   {
1563     size+=2;  // total number of states
1564     int j=0;
1565     for (; j<figures[i]->ts; j++)
1566       if (figures[i]->seq[j])
1567         size+=1+strlen(lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName()))+1;
1568   }
1569   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_states",NULL,size,0));
1570 
1571 
1572 
1573   size=0;
1574   for (i=0; i<total_objects; i++)
1575   {
1576     size+=2;  // total number of variables
1577     int j=0;
1578     for (; j<figures[i]->tiv; j++)
1579       if (figures[i]->vars[j])
1580         size+=1+strlen(lstring_value(((LSymbol *)figures[i]->vars[j])->GetName()))+1;
1581   }
1582   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"describe_lvars",NULL,size,0));
1583 
1584 
1585 
1586   // how many objects are we goint to save, use a int32_t to specify how many
1587   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_list",NULL,4,0));
1588 
1589   int32_t t=0;
1590   object_node *o=save_list;
1591   for (; o; o=o->next)
1592     t++;
1593 
1594   // type and state aren't normal records because they will be remapped on loading
1595   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"type",NULL,1+2*t,0));
1596   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"state",NULL,1+2*t,0));
1597 
1598 
1599   // now save all the lvars for each object
1600   for (size=0,o=save_list; o; o=o->next)
1601     size+=figures[o->me->otype]->tv*5+2;
1602   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"lvars",NULL,size,0));
1603 
1604 
1605   for (i=0; i<TOTAL_OBJECT_VARS; i++)
1606     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,object_descriptions[i].name,NULL,1+
1607               RC_type_size(object_descriptions[i].type)*t,0));
1608 
1609   add_light_spec(&sd,Name);
1610 
1611 
1612   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"object_links",NULL,1+4+total_object_links(save_list)*8,0));
1613   sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"light_links",NULL,1+4+total_light_links(save_list)*8,0));
1614 
1615   if (save_all)
1616   {
1617     t=0;
1618     view *v=player_list;
1619     for (; v; v=v->next) t++;
1620     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_info",NULL,t*4+4,0));
1621 
1622     int tv=total_view_vars();
1623     int i=0;
1624     for (; i<tv; i++)
1625       sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,get_view_var_name(i),NULL,1+4*t,0));
1626     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"random_start",NULL,5,0));
1627 
1628     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"weapon_array",NULL,1+4+total_weapons*4*t,0));
1629 
1630     int name_len=0;
1631     for (v=player_list; v; v=v->next)
1632       name_len+=strlen(v->name)+2;
1633     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"player_names",NULL,name_len,0));
1634 
1635     sd.add_by_hand(new spec_entry(SPEC_IMAGE,"thumb nail",NULL,4+160*(100+wm->font()->height()*2),0));
1636   }
1637 
1638   sd.calc_offsets();
1639 
1640   return sd.write(filename);
1641 }
1642 
1643 void scale_put(image *im, image *screen, int x, int y, short new_width, short new_height);
1644 
write_thumb_nail(bFILE * fp,image * im)1645 void level::write_thumb_nail(bFILE *fp, image *im)
1646 {
1647   image *i = new image(vec2i(160, 100 + wm->font()->height() * 2));
1648   i->clear();
1649   scale_put(im,i,0,0,160,100);
1650   if (first_name)
1651     wm->font()->put_string(i,80-strlen(first_name)*wm->font()->width()/2,100,first_name);
1652 
1653   time_t t;
1654   t=time(NULL);
1655   char buf[80];
1656 
1657   strftime(buf,80,"%T %A %B %d",localtime(&t));
1658   wm->font()->put_string(i,80-strlen(buf)*wm->font()->width()/2,100+wm->font()->height(),buf);
1659 
1660   fp->write_uint16(i->Size().x);
1661   fp->write_uint16(i->Size().y);
1662 
1663   i->Lock();
1664   for(int y = 0; y < i->Size().y; y++)
1665     fp->write(i->scan_line(y),i->Size().x);
1666   i->Unlock();
1667 
1668   delete i;
1669 }
1670 
write_player_info(bFILE * fp,object_node * save_list)1671 void level::write_player_info(bFILE *fp, object_node *save_list)
1672 {
1673   int32_t t=0;
1674   view *v=player_list;
1675   for (; v; v=v->next) t++;
1676   fp->write_uint32(t);
1677 
1678   for (v=player_list; v; v=v->next)
1679     fp->write_uint32(object_to_number_in_list(v->focus,save_list));
1680 
1681   int tv=total_view_vars();
1682   int i=0;
1683   for (; i<tv; i++)
1684   {
1685     fp->write_uint8(RC_32);
1686     for (v=player_list; v; v=v->next)
1687       fp->write_uint32(v->get_view_var_value(i));
1688   }
1689 
1690   fp->write_uint8(RC_32);
1691   fp->write_uint32(rand_on);
1692 
1693   fp->write_uint8(RC_32);
1694   fp->write_uint32(total_weapons);
1695   for (v=player_list; v; v=v->next)
1696     for (i=0; i<total_weapons; i++)
1697       fp->write_uint32(v->weapons[i]);
1698 
1699   for (v=player_list; v; v=v->next)
1700   {
1701     int len=strlen(v->name)+1;
1702     fp->write_uint8(len);
1703     fp->write(v->name,len);
1704   }
1705 }
1706 
1707 
load_player_info(bFILE * fp,spec_directory * sd,object_node * save_list)1708 int level::load_player_info(bFILE *fp, spec_directory *sd, object_node *save_list)
1709 {
1710   int ret;
1711   spec_entry *se=sd->find("player_info");
1712   if (se)
1713   {
1714     fp->seek(se->offset,0);
1715 
1716     int set_first_view=0;
1717     if (the_game->first_view==player_list) set_first_view=1;
1718     int my_player_number=-1;
1719 
1720     view *v=player_list;
1721     for (; v; v=v->next)
1722     { v->suggest.send_view=0;
1723       v->suggest.send_weapon_change=0;
1724     }
1725 
1726     for (v=player_list; v; v=v->next)
1727       if (v->local_player())
1728          my_player_number=v->player_number;
1729 
1730     while (player_list)    // delete all of the views (they will get recreated)
1731     {
1732       v=player_list;
1733       if (v->focus)
1734       {
1735         if (v->focus->controller())
1736          v->focus->set_controller(NULL);
1737     delete v->focus;
1738       }
1739 
1740       player_list=player_list->next;
1741       delete v;
1742     }
1743 
1744     int32_t total_players=fp->read_uint32();
1745     view *last=NULL;
1746     int i=0;
1747     for (; i<total_players; i++)
1748     {
1749       game_object *o=number_to_object_in_list(fp->read_uint32(),save_list);
1750       v=new view(o,NULL,0);
1751       if (o) o->set_controller(v);
1752       if (player_list)
1753         last->next=v;
1754       else player_list=v;
1755       last=v;
1756     }
1757     if (set_first_view)
1758       the_game->first_view=player_list;
1759 
1760     for (i=0; i<total_view_vars(); i++)
1761     {
1762       char const *find_name = get_view_var_name(i);
1763       se=sd->find(find_name);
1764 
1765       if (se)
1766       {
1767     fp->seek(se->offset,0);
1768     if (fp->read_uint8()==RC_32)
1769     {
1770       for (v=player_list; v; v=v->next)
1771             v->set_view_var_value(i,fp->read_uint32());
1772     }
1773       } else
1774       {
1775     for (v=player_list; v; v=v->next)
1776         v->set_view_var_value(i,0);
1777       }
1778     }
1779 
1780     se=sd->find("random_start");      // start of index into random table
1781     if (se)
1782     {
1783       fp->seek(se->offset,0);
1784       if (fp->read_uint8()==RC_32)
1785         rand_on=fp->read_uint32();
1786     } else rand_on=0;
1787 
1788     se=sd->find("weapon_array");
1789     if (se)
1790     {
1791       fp->seek(se->offset,0);
1792       if (fp->read_uint8()==RC_32)
1793       {
1794     int32_t m=fp->read_uint32();  // read how many weapons exsisted when last saved
1795     int i;
1796     for (v=player_list; v; v=v->next)
1797     {
1798       for (i=0; i<m; i++)
1799       {
1800         int32_t x=fp->read_uint32();
1801         if (i<total_weapons)
1802         {
1803           v->weapons[i]=x;
1804           v->last_weapons[i]=x;
1805         }
1806       }
1807     }
1808       }
1809     }  else
1810     {
1811       for (v=player_list; v; v=v->next)
1812       {
1813     memset(v->last_weapons,0xff,total_weapons*sizeof(int32_t));
1814     memset(v->weapons,0xff,total_weapons*sizeof(int32_t));
1815       }
1816     }
1817 
1818     se=sd->find("player_names");
1819     if (se)
1820     {
1821       fp->seek(se->offset,0);
1822       for (v=player_list; v; v=v->next)
1823       {
1824     uint8_t len=fp->read_uint8();
1825     fp->read(v->name,len);
1826       }
1827     }
1828 
1829     ret=1;
1830     recalc_local_view_space();
1831 
1832   } else
1833   {
1834     LSymbol *fun = LSymbol::FindOrCreate("set_player_defaults");
1835     if (DEFINEDP(fun->GetFunction()))
1836     {
1837       view *f;
1838       game_object *o=current_object;
1839       for (f=player_list; f; f=f->next)
1840       {
1841     if (f->focus)
1842     {
1843       current_object=f->focus;
1844       void *m=mark_heap(TMP_SPACE);
1845       fun->EvalFunction(NULL);
1846       restore_heap(m,TMP_SPACE);
1847     }
1848       }
1849       current_object=o;
1850     }
1851     ret=0;
1852   }
1853 
1854   view *vw;
1855   for (vw=player_list; vw; vw=vw->next)
1856   {
1857     if (total_weapons && !vw->has_weapon(vw->current_weapon))
1858     {
1859       vw->suggest.send_weapon_change=1;
1860       vw->suggest.new_weapon=0;
1861     }
1862   }
1863 
1864   return ret;
1865 }
1866 
1867 
write_objects(bFILE * fp,object_node * save_list)1868 void level::write_objects(bFILE *fp, object_node *save_list)
1869 {
1870   // record information in the file about what the data structures look like
1871   // right now, so if they change later, they don't get get screwed up
1872   fp->write_uint16(total_objects);   // mark how many objects we know about right now
1873 
1874   int i=0;
1875   for (; i<total_objects; i++)   // loop through all the object types we know of
1876   {
1877     fp->write_uint8(strlen(object_names[i])+1);                    // sizeof name
1878     fp->write(object_names[i],strlen(object_names[i])+1);      // write object name
1879   }
1880 
1881 
1882   // write state numbers and names for each object
1883   for (i=0; i<total_objects; i++)
1884   {
1885     int total=0;
1886     int j=0;
1887     for (; j<figures[i]->ts; j++)
1888       if (figures[i]->seq[j]) total++;
1889     fp->write_uint16(total);
1890 
1891     for (j=0; j<figures[i]->ts; j++)
1892       if (figures[i]->seq[j])
1893       {
1894     char *state_name=lstring_value(((LSymbol *)figures[i]->seq_syms[j])->GetName());
1895     fp->write_uint8(strlen(state_name)+1);
1896     fp->write(state_name,strlen(state_name)+1);
1897       }
1898   }
1899 
1900 
1901   // write object lvar names
1902   for (i=0; i<total_objects; i++)
1903   {
1904     fp->write_uint16(figures[i]->tv);
1905     int j,x;
1906 
1907     for (x=0; x<figures[i]->tv; x++)
1908     {
1909       for (j=0; j<figures[i]->tiv; j++)
1910       {
1911         if (figures[i]->vars[j] && figures[i]->var_index[j]==x)
1912     {
1913       char *var_name=lstring_value(((LSymbol *)figures[i]->vars[j])->GetName());
1914       fp->write_uint8(strlen(var_name)+1);
1915       fp->write(var_name,strlen(var_name)+1);
1916     }
1917       }
1918     }
1919   }
1920 
1921   int32_t t=0;
1922   object_node *o=save_list;
1923   for (; o; o=o->next) t++;
1924   fp->write_uint32(t);
1925 
1926 
1927   fp->write_uint8(RC_16);                                    // save type info for each record
1928   for (o=save_list; o; o=o->next) fp->write_uint16(o->me->type());
1929 
1930   fp->write_uint8(RC_16);                                    // save state info for each record
1931   for (o=save_list; o; o=o->next) fp->write_uint16(o->me->reduced_state());
1932 
1933   for (o=save_list; o; o=o->next)                            // save lvars
1934   {
1935     fp->write_uint16(figures[o->me->otype]->tv);
1936     for (i=0; i<figures[o->me->otype]->tv; i++)
1937     {
1938       fp->write_uint8(RC_32);                           // for now the only type allowed is int32_t
1939       fp->write_uint32(o->me->lvars[i]);
1940     }
1941   }
1942 
1943   for (i=0; i<default_simple.total_vars(); i++)
1944   {
1945     int t=object_descriptions[i].type;
1946     fp->write_uint8(t);
1947     for (o=save_list; o; o=o->next)
1948     {
1949       switch (t)
1950       {
1951     case RC_8 :
1952     { fp->write_uint8(o->me->get_var(i)); } break;
1953     case RC_16 :
1954     { fp->write_uint16(o->me->get_var(i)); } break;
1955     case RC_32 :
1956     { fp->write_uint32(o->me->get_var(i)); } break;
1957       }
1958     }
1959   }
1960 }
1961 
1962 
total_object_links(object_node * list)1963 int32_t level::total_object_links(object_node *list)
1964 {
1965   int32_t tl=0;
1966   for (object_node *o=list; o; o=o->next)
1967     tl+=o->me->total_objects();
1968   return tl;
1969 }
1970 
total_light_links(object_node * list)1971 int32_t level::total_light_links(object_node *list)
1972 {
1973   int32_t tl=0;
1974   for (object_node *o=list; o; o=o->next)
1975     tl+=o->me->total_lights();
1976   return tl;
1977 }
1978 
write_links(bFILE * fp,object_node * save_list,object_node * exclude_list)1979 void level::write_links(bFILE *fp, object_node *save_list, object_node *exclude_list)
1980 {
1981   fp->write_uint8(RC_32);
1982   fp->write_uint32(total_object_links(save_list));
1983 
1984   int x=1;
1985   object_node *o=save_list;
1986 
1987   for (; o; o=o->next,x++)
1988   {
1989     int i=0;
1990     for (; i<o->me->total_objects(); i++)
1991     {
1992       fp->write_uint32(x);
1993       int32_t x=object_to_number_in_list(o->me->get_object(i),save_list);
1994       if (x)
1995         fp->write_uint32(x);
1996       else                            // save links to excluded items as negative
1997         fp->write_uint32((int32_t)(-(object_to_number_in_list(o->me,exclude_list))));
1998     }
1999   }
2000 
2001   fp->write_uint8(RC_32);
2002   fp->write_uint32(total_light_links(save_list));
2003 
2004   x=1;
2005   for (o=save_list; o; o=o->next,x++)
2006   {
2007     int i=0;
2008     for (; i<o->me->total_lights(); i++)
2009     {
2010       fp->write_uint32(x);
2011       fp->write_uint32(light_to_number(o->me->get_light(i)));
2012     }
2013   }
2014 
2015 }
2016 
2017 
load_links(bFILE * fp,spec_directory * sd,object_node * save_list,object_node * exclude_list)2018 void level::load_links(bFILE *fp, spec_directory *sd,
2019                object_node *save_list, object_node *exclude_list)
2020 {
2021   spec_entry *se=sd->find("object_links");
2022   if (se)
2023   {
2024     fp->seek(se->offset,0);
2025     if (fp->read_uint8()==RC_32)
2026     {
2027       int32_t t=fp->read_uint32();
2028       while (t)
2029       {
2030     int32_t x1=fp->read_uint32();
2031     CONDITION(x1>=0,"expected x1 for object link to be > 0\n");
2032     int32_t x2=fp->read_uint32();
2033     game_object *p,*q=number_to_object_in_list(x1,save_list);
2034     if (x2>0)
2035       p=number_to_object_in_list(x2,save_list);
2036     else p=number_to_object_in_list(-x2,exclude_list);
2037     if (q)
2038       q->add_object(p);
2039     else dprintf("bad object link\n");
2040 
2041     t--;
2042       }
2043     }
2044   }
2045 
2046   se=sd->find("light_links");
2047   if (se)
2048   {
2049     fp->seek(se->offset,0);
2050     if (fp->read_uint8()==RC_32)
2051     {
2052       int32_t t=fp->read_uint32();
2053       while (t)
2054       {
2055     int32_t x1=fp->read_uint32();
2056     int32_t x2=fp->read_uint32();
2057     game_object *p=number_to_object_in_list(x1,save_list);
2058     if (p)
2059       p->add_light(number_to_light(x2));
2060     else dprintf("bad object/light link\n");
2061     t--;
2062       }
2063     }
2064   }
2065 
2066 }
2067 
2068 
write_options(bFILE * fp)2069 void level::write_options(bFILE *fp)
2070 {
2071   // save background scroll rate
2072   fp->write_uint8(RC_32);
2073   fp->write_uint32(bg_xmul);
2074   fp->write_uint32(bg_xdiv);
2075   fp->write_uint32(bg_ymul);
2076   fp->write_uint32(bg_ydiv);
2077 
2078   fp->write_uint8(RC_32);
2079   int ta=0;
2080   area_controller *a=area_list;
2081   for (; a; a=a->next) ta++;
2082   fp->write_uint32(ta);
2083   for (a=area_list; a; a=a->next)
2084   {
2085     fp->write_uint32(a->x);
2086     fp->write_uint32(a->y);
2087     fp->write_uint32(a->w);
2088     fp->write_uint32(a->h);
2089     fp->write_uint32(a->active);
2090 
2091     fp->write_uint32(a->ambient);
2092     fp->write_uint32(a->view_xoff);
2093     fp->write_uint32(a->view_yoff);
2094     fp->write_uint32(a->ambient_speed);
2095     fp->write_uint32(a->view_xoff_speed);
2096     fp->write_uint32(a->view_yoff_speed);
2097   }
2098   fp->write_uint8(RC_32);
2099   fp->write_uint32(tick_counter());
2100 }
2101 
load_options(spec_directory * sd,bFILE * fp)2102 void level::load_options(spec_directory *sd, bFILE *fp)
2103 {
2104   spec_entry *se=sd->find("bg_scroll_rate");
2105   if (se)
2106   {
2107     fp->seek(se->offset,0);
2108     if (fp->read_uint8()!=RC_32)
2109     { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2110     else
2111     {
2112       bg_xmul=fp->read_uint32();
2113       bg_xdiv=fp->read_uint32();
2114       bg_ymul=fp->read_uint32();
2115       bg_ydiv=fp->read_uint32();
2116     }
2117   } else { bg_xmul=bg_ymul=1; bg_xdiv=bg_ydiv=8; }
2118 
2119   se=sd->find("area_list.v1");
2120   if (se)
2121   {
2122     fp->seek(se->offset,0);
2123     if (fp->read_uint8()==RC_32)
2124     {
2125       area_controller *l=NULL,*p;
2126       int32_t ta=fp->read_uint32();
2127       int i=0;
2128       for (; i<ta; i++)
2129       {
2130     int32_t x,y,w,h;
2131     x=fp->read_uint32();
2132     y=fp->read_uint32();
2133     w=fp->read_uint32();
2134     h=fp->read_uint32();
2135     p=new area_controller(x,y,w,h,NULL);
2136     if (l) l->next=p;
2137     else area_list=p;
2138     l=p;
2139     p->active=fp->read_uint32();
2140     p->ambient=fp->read_uint32();
2141     p->view_xoff=fp->read_uint32();
2142     p->view_yoff=fp->read_uint32();
2143     p->ambient_speed=fp->read_uint32();
2144     p->view_xoff_speed=fp->read_uint32();
2145     p->view_yoff_speed=fp->read_uint32();
2146       }
2147     }
2148   }
2149 
2150   se=sd->find("tick_counter");
2151   if (se)
2152   {
2153     fp->seek(se->offset,0);
2154     if (fp->read_uint8()==RC_32)
2155       set_tick_counter(fp->read_uint32());
2156     else set_tick_counter(0);
2157   } else set_tick_counter(0);
2158 }
2159 
2160 
write_cache_prof_info()2161 void level::write_cache_prof_info()
2162 {
2163   if (cache.prof_is_on())
2164   {
2165     char pf_name[100];
2166     if (first_name)
2167       get_prof_assoc_filename(first_name,pf_name);
2168     else
2169       get_prof_assoc_filename(Name,pf_name);
2170 
2171 
2172     spec_directory sd;
2173     sd.add_by_hand(new spec_entry(SPEC_DATA_ARRAY,"cache profile info",NULL,cache.prof_size(),0));
2174     sd.calc_offsets();
2175     jFILE *fp2=sd.write(pf_name);
2176     if (!fp2)
2177       the_game->show_help("Unable to open cache profile output file");
2178     else
2179     {
2180       cache.prof_write(fp2);
2181       delete fp2;
2182     }
2183     sd.delete_entries();
2184   }
2185 
2186 }
2187 
load_cache_info(spec_directory * sd,bFILE * fp)2188 void level::load_cache_info(spec_directory *sd, bFILE *fp)
2189 {
2190   if (!DEFINEDP(symbol_value(l_empty_cache)) || !symbol_value(l_empty_cache))
2191   {
2192     char pf_name[100];
2193     if (first_name)
2194       get_prof_assoc_filename(first_name,pf_name);  // get cache info from orignal filename if this is a savegame
2195     else
2196       get_prof_assoc_filename(Name,pf_name);
2197 
2198 
2199     cache.load_cache_prof_info(pf_name,this);
2200   }
2201 }
2202 
2203 
save(char const * filename,int save_all)2204 int level::save(char const *filename, int save_all)
2205 {
2206     char name[255], bkname[255];
2207 
2208     sprintf( name, "%s%s", get_save_filename_prefix(), filename );
2209     sprintf( bkname, "%slevsave.bak", get_save_filename_prefix() );
2210     if( !save_all && DEFINEDP( symbol_value( l_keep_backup ) ) &&
2211         symbol_value( l_keep_backup ) )   // make a backup
2212     {
2213         bFILE *fp = open_file( name, "rb" );    // does file already exist?
2214         if( !fp->open_failure() )
2215         {
2216             unlink( bkname );
2217             bFILE *bk = open_file( bkname, "wb" );
2218             if( bk->open_failure() )
2219                 dprintf("unable to open backup file %s\n", bkname );
2220             else
2221             {
2222                 uint8_t buf[0x1000];
2223                 int32_t size = fp->file_size();
2224                 int tr = 1;
2225                 while( size && tr )
2226                 {
2227                     int tr = fp->read(buf,0x1000);
2228                     if( tr )
2229                     tr = bk->write(buf,tr);
2230                     size -= tr;
2231                 }
2232             }
2233             delete bk;
2234 #if (defined(__MACH__) || !defined(__APPLE__))
2235             chmod( bkname, S_IRWXU | S_IRWXG | S_IRWXO );
2236 #endif
2237         }
2238         delete fp;
2239     }
2240 
2241     // if we are not doing a savegame then change the first_name to this name
2242     if( !save_all )
2243     {
2244         if( first_name )
2245             free(first_name);
2246         first_name = strdup(name);
2247     }
2248 
2249     object_node *players, *objs;
2250     if( save_all )
2251         players = NULL;
2252     else
2253         players = make_player_onodes();
2254 
2255     objs = make_not_list(players);     // negate the above list
2256 
2257     bFILE *fp = create_dir( name, save_all, objs, players);
2258     if( fp != NULL )
2259     {
2260         if( !fp->open_failure() )
2261         {
2262             if( first_name )
2263             {
2264                 fp->write_uint8( strlen( first_name ) + 1 );
2265                 fp->write( first_name, strlen( first_name ) + 1 );
2266             }
2267             else
2268             {
2269                 fp->write_uint8( 1 );
2270                 fp->write_uint8( 0 );
2271             }
2272 
2273             fp->write_uint32( fg_width );
2274             fp->write_uint32( fg_height );
2275 
2276             int t  = fg_width * fg_height;
2277             uint16_t *rm = map_fg;
2278             for (; t; t--,rm++)
2279             {
2280                 uint16_t x = *rm;
2281                 x = lstl(x);            // convert to intel endianess
2282                 *rm = x;
2283             }
2284 
2285             fp->write( (char *)map_fg, 2 * fg_width * fg_height );
2286             t = fg_width * fg_height;
2287             rm = map_fg;
2288             for (; t; t--,rm++)
2289             {
2290                 uint16_t x = *rm;
2291                 x = lstl( x );            // convert to intel endianess
2292                 *rm = x;
2293             }
2294 
2295             fp->write_uint32( bg_width );
2296             fp->write_uint32( bg_height );
2297             t = bg_width * bg_height;
2298             rm = map_bg;
2299 
2300             for (; t; t--,rm++)
2301             {
2302                 uint16_t x=*rm;
2303                 x = lstl( x );        // convert to intel endianess
2304                 *rm = x;
2305             }
2306 
2307             fp->write( (char *)map_bg, 2 * bg_width * bg_height );
2308             rm = map_bg;
2309             t = bg_width*bg_height;
2310 
2311             for (; t; t--,rm++)
2312             {
2313                 uint16_t x = *rm;
2314                 x = lstl( x );        // convert to intel endianess
2315                 *rm = x;
2316             }
2317 
2318             write_options( fp );
2319             write_objects( fp, objs );
2320             write_lights( fp );
2321             write_links( fp, objs, players );
2322             if( save_all )
2323             {
2324                 write_player_info( fp, objs );
2325                 write_thumb_nail( fp,screen );
2326             }
2327 
2328             delete fp;
2329 #if (defined(__MACH__) || !defined(__APPLE__))
2330             chmod( name, S_IRWXU | S_IRWXG | S_IRWXO );
2331 #endif
2332             write_cache_prof_info();
2333         }
2334         else
2335         {
2336             the_game->show_help( "Unable to open file for saving\n" );
2337             delete fp;
2338             return 0;
2339         }
2340     }
2341     else
2342     {
2343         the_game->show_help( "Unable to open file for saving.\n" );
2344         printf( "\nFailed to save game.\n" );
2345         printf( "I was trying to save to: '%s'\n\tPath: '%s'\n\tFile: '%s'\n", name, get_save_filename_prefix(), filename );
2346         printf( "\nPlease send an email to:\n\ttrandor@labyrinth.net.au\nwith these details.\nThanks.\n" );
2347         return 0;
2348     }
2349 
2350     delete_object_list(players);
2351     delete_object_list(objs);
2352 
2353     return 1;
2354 }
2355 
level(int width,int height,char const * name)2356 level::level(int width, int height, char const *name)
2357 {
2358   the_game->need_refresh();
2359   area_list=NULL;
2360   set_tick_counter(0);
2361 
2362   attack_list=NULL;
2363   attack_list_size=attack_total=0;
2364 
2365   target_list=NULL;
2366   target_list_size=target_total=0;
2367 
2368   block_list=NULL;
2369   block_list_size=block_total=0;
2370 
2371   all_block_list=NULL;
2372   all_block_list_size=all_block_total=0;
2373 
2374   Name=NULL;
2375   first_name=NULL;
2376 
2377   set_name(name);
2378   first=first_active=NULL;
2379 
2380   fg_width=width;
2381   fg_height=height;
2382   calc_bgsize(fg_width,fg_height,bg_width,bg_height);
2383 
2384   map_bg=(uint16_t *)malloc(sizeof(int16_t)*bg_width*bg_height);
2385   map_fg=(uint16_t *)malloc(sizeof(int16_t)*fg_width*fg_height);
2386 
2387 
2388 
2389   memset(map_bg,0,sizeof(int16_t)*bg_width*bg_height);
2390   memset(map_fg,0,sizeof(int16_t)*fg_width*fg_height);
2391 
2392   int i;
2393   for (i=0; i<fg_width; i++)
2394   {
2395     map_fg[i]=1;
2396     map_fg[fg_width*(fg_height-1)+i]=1;
2397   }
2398   for (i=0; i<fg_height; i++)
2399   {
2400     map_fg[fg_width*i]=1;
2401     map_fg[fg_width*i+fg_width-1]=1;
2402   }
2403 
2404   total_objs=0;
2405   insert_players();
2406 }
2407 
2408 
add_object(game_object * new_guy)2409 void level::add_object(game_object *new_guy)
2410 {
2411   total_objs++;
2412   new_guy->next=NULL;
2413   if (figures[new_guy->otype]->get_cflag(CFLAG_ADD_FRONT))
2414   {
2415     if (!first)
2416       first=new_guy;
2417     else
2418       last->next=new_guy;
2419     last=new_guy;
2420   } else
2421   {
2422     if (!first)
2423       last=first=new_guy;
2424     else
2425     {
2426       new_guy->next=first;
2427       first=new_guy;
2428     }
2429   }
2430 }
2431 
add_object_after(game_object * new_guy,game_object * who)2432 void level::add_object_after(game_object *new_guy,game_object *who)
2433 {
2434   if (!who) add_object(new_guy);
2435   else
2436   {
2437     total_objs++;
2438     if (who==last) last=new_guy;
2439     new_guy->next=who->next;
2440     who->next=new_guy;
2441   }
2442 }
2443 
delete_object(game_object * who)2444 void level::delete_object(game_object *who)
2445 {
2446   remove_object(who);
2447   delete who;
2448 }
2449 
remove_block(game_object * who)2450 void level::remove_block(game_object *who)
2451 {
2452   int i=0,j;
2453   game_object **o=block_list;
2454   for (; i<block_total; i++)
2455   {
2456     if (*o==who)        // is this object in the block list?
2457     {
2458       block_total--;    // squish the block list in
2459       o++;
2460       for (j=i; j<block_total; j++)
2461         block_list[j]=block_list[j+1];
2462     } else o++;
2463   }
2464 }
2465 
2466 
2467 // searches through the all_block list for who and if it finds it deletes it
remove_all_block(game_object * who)2468 void level::remove_all_block(game_object *who)
2469 {
2470   int i=0,j;
2471   game_object **o=all_block_list;
2472   for (; i<all_block_total; i++)
2473   {
2474     if (*o==who)        // is this object in the block list?
2475     {
2476       all_block_total--;    // squish the block list in
2477       o++;
2478       for (j=i; j<all_block_total; j++)
2479         all_block_list[j]=all_block_list[j+1];
2480     } else o++;
2481   }
2482 }
2483 
remove_object(game_object * who)2484 void level::remove_object(game_object *who)
2485 {
2486   if (dev_cont)
2487     dev_cont->notify_deleted_object(who);
2488 
2489   if (who==first)
2490   {
2491     if (who==last) last=NULL;
2492     first=first->next;
2493   }
2494   else
2495   {
2496     game_object *o=first;
2497     for (; o && o->next!=who; o=o->next);
2498     if (o)
2499     {
2500       o->next=who->next;
2501       if (!o->next) last=o;
2502     }
2503     else return ;     // if object is not in level, don't try to do anything else
2504   }
2505   total_objs--;
2506 
2507 
2508   if (first_active==who)
2509     first_active=who->next_active;
2510   else
2511   {
2512     game_object *o=first_active;
2513     for (; o && o->next_active!=who; o=o->next_active);
2514     if (o)
2515       o->next_active=who->next_active;
2516   }
2517 
2518   if (who->flags()&KNOWN_FLAG)
2519   {
2520     game_object *o=first;
2521     for (; o; o=o->next)
2522     {
2523       int t=o->total_objects();
2524       int i=0;
2525       for (; i<t; i++)
2526         if (o->get_object(i)==who)
2527     {
2528       o->remove_object(who);
2529       t=o->total_objects();
2530     }
2531     }
2532   }
2533 
2534   if (who->otype<0xffff)
2535   {
2536     if (who->can_block())  // remove object from block list and all_block if nessasary
2537     {
2538       remove_block(who);
2539       remove_all_block(who);
2540     } else if (who->hurtable())
2541       remove_all_block(who);
2542   }
2543 
2544 
2545   int t=who->total_objects();
2546   while (t) { who->remove_object(who->get_object(0)); t--; }
2547 
2548   t=who->total_lights();
2549   while (t) { who->remove_light(who->get_light(0)); t--; }
2550 }
2551 
to_front(game_object * o)2552 void level::to_front(game_object *o)  // move to end of list, so we are drawn last, therefore top
2553 {
2554   if (o==last) return ;
2555   first_active=NULL;     // make sure nothing goes screwy with the active list
2556 
2557   if (o==first)
2558     first=first->next;
2559   else
2560   {
2561     game_object *w=first;
2562     for (; w && w->next!=o; w=w->next);
2563     if (!w) return ;
2564     w->next=o->next;
2565   }
2566 
2567   last->next=o;
2568   o->next=NULL;
2569   last=o;
2570 }
2571 
to_back(game_object * o)2572 void level::to_back(game_object *o)   // to make the character drawn in back, put at front of list
2573 {
2574   if (o==first) return;
2575   first_active=NULL;     // make sure nothing goes screwy with the active list
2576 
2577   game_object *w=first;
2578   for (; w && w->next!=o; w=w->next);
2579   if (!w) return;
2580   if (last==o)
2581     last=w;
2582   w->next=o->next;
2583   o->next=first;
2584   first=o;
2585 }
2586 
2587 
find_self(game_object * me)2588 game_object *level::find_self(game_object *me)
2589 {
2590   return me;
2591 }
2592 
find_object(int32_t x,int32_t y)2593 game_object *level::find_object(int32_t x, int32_t y)
2594 {
2595   int32_t x1,y1,x2,y2;
2596   game_object *o=first;
2597   for (; o; o=o->next)
2598   {
2599     o->picture_space(x1,y1,x2,y2);
2600     if (x<x2 && x>=x1 && y<y2 && y>=y1)
2601       return o;
2602   }
2603   return NULL;
2604 }
2605 
2606 int32_t last_tile_hit_x,last_tile_hit_y;
2607 
2608 #define remapx(x) (x==0 ? -1 : x==tl-1 ? tl+1 : x)
2609 #define remapy(y) (y==0 ? -1 : y==th-1 ? th+1 : y)
2610 
foreground_intersect(int32_t x1,int32_t y1,int32_t & x2,int32_t & y2)2611 void level::foreground_intersect(int32_t x1, int32_t y1, int32_t &x2, int32_t &y2)
2612 {
2613 /*  if (x1==x2)
2614   { vforeground_intersect(x1,y1,y2);
2615     return ;
2616   }  */
2617 
2618   int32_t tl=the_game->ftile_width(),th=the_game->ftile_height(),
2619     j,
2620     xp1,yp1,xp2,yp2,    // starting and ending points of block line segment
2621     swap;               // temp var
2622   int32_t blockx1,blocky1,blockx2,blocky2,block,bx,by;
2623   point_list *block_list;
2624   unsigned char *bdat;
2625 
2626   blockx1=x1;
2627   blocky1=y1;
2628   blockx2=x2;
2629   blocky2=y2;
2630   if (blockx1>blockx2) { swap=blockx1; blockx1=blockx2; blockx2=swap; }
2631   if (blocky1>blocky2) { swap=blocky1; blocky1=blocky2; blocky2=swap; }
2632   blockx1=(blockx1-2)/tl-1;
2633   blockx2=(blockx2+tl+2)/tl+1;
2634   blocky1=(blocky1-2)/th-1;
2635   blocky2=(blocky2+th+2)/th+1;
2636 
2637 
2638   if (blockx2>=foreground_width()) { x2=tl*foreground_width()-1; }
2639   if (blocky2>=foreground_height()) { y2=th*foreground_height()-1; }
2640   blockx1=Max(blockx1,0);
2641   blocky1=Max(blocky1,0);
2642 
2643   if ((blockx1>blockx2) || (blocky1>blocky2)) return ;
2644 
2645   // now check all the map positions this line could intersect
2646   for (bx=blockx1; bx<=blockx2; bx++)
2647   {
2648     for (by=blocky1; by<=blocky2; by++)
2649     {
2650       block=the_game->get_map_fg(bx,by);
2651       if (block>BLACK)        // don't check BLACK, should be no points in it
2652       {
2653         // now check the all the line segments in the block
2654         foretile *f=the_game->get_fg(block);
2655         block_list=f->points;
2656         unsigned char total=block_list->tot;
2657         bdat=block_list->data;
2658         unsigned char *ins=f->points->inside;
2659     int32_t xo=bx*tl,yo=by*th;
2660         for (j=0; j<total-1; j++,ins++)
2661         {
2662           // find the starting and ending points for this segment
2663       xp1=xo+remapx(*bdat);
2664       bdat++;
2665 
2666       yp1=yo+remapy(*bdat);
2667       bdat++;
2668 
2669       xp2=xo+remapx(*bdat);
2670       yp2=yo+remapy(bdat[1]);
2671 
2672 
2673       int32_t ox2=x2,oy2=y2;
2674           if (*ins)
2675             setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,1);
2676           else
2677             setback_intersect(x1,y1,x2,y2,xp1,yp1,xp2,yp2,-1);
2678       if (ox2!=x2 || oy2!=y2)
2679       {
2680         last_tile_hit_x=bx;
2681         last_tile_hit_y=by;
2682       }
2683 
2684         }
2685       }
2686     }
2687   }
2688 }
2689 
2690 
vforeground_intersect(int32_t x1,int32_t y1,int32_t & y2)2691 void level::vforeground_intersect(int32_t x1, int32_t y1, int32_t &y2)
2692 {
2693   int32_t tl=f_wid,th=f_hi,
2694     j,
2695     xp1,yp1,xp2,yp2;    // starting and ending points of block line segment temp var
2696   int32_t blocky1,blocky2,block,bx,by,checkx;
2697   point_list *block_list;
2698   unsigned char *bdat;
2699 
2700   int y_addback;
2701   if (y1>y2)
2702   {
2703     blocky1=y2/th;
2704     blocky2=y1/th;
2705     y_addback=blocky2*f_hi;
2706   } else
2707   {
2708     blocky1=y1/th;
2709     blocky2=y2/th;
2710     y_addback=blocky1*f_hi;
2711   }
2712 
2713   y1-=y_addback;
2714   y2-=y_addback;
2715 
2716   bx=x1/f_wid;
2717   checkx=x1-bx*f_wid;
2718 
2719 
2720   // now check all the map positions this line could intersect
2721 
2722   for (by=blocky1; by<=blocky2; by++,y1-=f_hi,y2-=f_hi,y_addback+=f_hi)
2723   {
2724     block=the_game->get_map_fg(bx,by);
2725 
2726     // now check the all the line segments in the block
2727     foretile *f=the_game->get_fg(block);
2728     block_list=f->points;
2729 
2730     unsigned char total=block_list->tot;
2731     bdat=block_list->data;
2732     unsigned char *ins=f->points->inside;
2733 
2734 //    int32_t xo=bx*tl,yo=by*th;
2735     for (j=0; j<total-1; j++,ins++)
2736     {
2737       // find the starting and ending points for this segment
2738       xp1=remapx(*bdat);
2739       bdat++;
2740 
2741       yp1=remapy(*bdat);
2742       bdat++;
2743 
2744       xp2=remapx(*bdat);
2745       yp2=remapy(bdat[1]);
2746 
2747 
2748       int32_t oy2=y2;
2749       if (*ins)
2750         setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,1);
2751       else
2752         setback_intersect(checkx,y1,checkx,y2,xp1,yp1,xp2,yp2,-1);
2753       if (oy2!=y2)
2754       {
2755     last_tile_hit_x=bx;
2756     last_tile_hit_y=by;
2757       }
2758     }
2759   }
2760   y2+=y_addback;
2761 }
2762 
2763 
2764 
send_signal(int32_t signal)2765 void level::send_signal(int32_t signal)
2766 {
2767   if (signal)   // signal 0 is never sent!
2768   {
2769     game_object *o=first_active;
2770     for (; o; o=o->next_active)
2771       o->recieve_signal(signal);
2772   }
2773 }
2774 
2775 
crush(game_object * by_who,int xamount,int yamount)2776 int level::crush(game_object *by_who, int xamount, int yamount)
2777 {
2778   int32_t xv,yv,crushed=0;
2779   game_object *o=first_active;
2780   for (; o; o=o->next_active)
2781   {
2782     if (o->hurtable() && o!=by_who)
2783     {
2784       xv=-xamount;
2785       yv=-yamount;
2786       if (o->try_move(o->x,o->y,xv,yv,3)==by_who)
2787       {
2788     xv=xamount;
2789     yv=yamount;
2790     o->try_move(o->x,o->y,xv,yv,3);
2791     if (xv==0 && yv==0)
2792     {
2793       if (o->state!=dead && o->state!=dieing)
2794         o->do_damage(by_who->current_figure()->hit_damage,by_who,o->x,o->y,0,0);
2795 
2796 /*      {
2797         if (o->has_sequence(dieing))
2798           o->set_state(dieing);
2799         else o->set_state(dead);
2800           o->hp=0;
2801       }        */
2802       crushed=1;
2803     }
2804       }
2805     }
2806   }
2807 
2808   return crushed;
2809 }
2810 
2811 
platform_push(game_object * by_who,int xamount,int yamount)2812 int level::platform_push(game_object *by_who, int xamount, int yamount)
2813 {
2814   int failed=0;
2815   int32_t xv,yv;
2816   game_object *o=first_active;
2817   for (; o; o=o->next_active)
2818   {
2819     if (o->is_playable() && o->state!=dieing && o->state!=dead)
2820     {
2821       // check to see if the platform is going up and will run into us.
2822       int32_t tvx,tvy;
2823       if (yamount<0)
2824       {
2825     tvx=-xamount;
2826     tvy=-yamount;
2827     if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)
2828     {
2829       o->x+=tvx;
2830       o->y+=tvy;
2831     }
2832       }
2833 
2834 /*      xv=xamount;
2835       yv=yamount;
2836       tvx,tvy;
2837       if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2838       if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2839       if (o->try_move(o->x,o->y,tvx,tvy,1)==by_who)  // we the platform hit us?
2840       {
2841     o->x+=tvx;
2842     o->y+=tvy;
2843       }*/
2844 
2845       xv=0;
2846       yv=2;
2847       if (o->try_move(o->x,o->y,xv,yv,1)==by_who)  // are we standing on the platform?
2848       {
2849     by_who->x=-by_who->x;
2850     xv=xamount;
2851     yv=yamount;
2852     o->try_move(o->x,o->y,xv,yv,3);
2853     if (xv!=xamount || yv!=yamount) failed=1;
2854     o->x+=xv;
2855     o->y+=yv;
2856     by_who->x=-by_who->x;
2857       }
2858     }
2859   }
2860   return !failed;
2861 }
2862 
push_characters(game_object * by_who,int xamount,int yamount)2863 int level::push_characters(game_object *by_who, int xamount, int yamount)
2864 {
2865   int32_t xv,yv;
2866   int failed=0;
2867   game_object *o=first_active;
2868   for (; o; o=o->next_active)
2869   {
2870     if ((o->is_playable() || o->pushable()) && o->state!=dieing && o->state!=dead)
2871     {
2872       xv=-xamount;
2873       yv=-yamount;
2874       int32_t tvx,tvy;
2875       if (xv>0) tvx=xv+1; else if (xv<0) tvx=xv-1; else tvx=0;
2876       if (yv>0) tvy=yv+1; else if (yv<0) tvx=yv-1; else tvy=0;
2877       if (o->try_move(o->x+xamount,o->y+yamount,tvx,tvy,3)==by_who)
2878       {
2879     xv=(xamount-tvx);
2880     yv=(yamount-tvy);
2881     o->try_move(o->x,o->y,xv,yv,3);
2882     o->x+=xv;
2883     o->y+=yv;
2884     if (xv!=xamount-tvx || yv!=yamount-tvy)
2885       failed=1;
2886       }
2887     }
2888   }
2889   return !failed;
2890 }
2891 
find_xrange(int x,int y,int type,int xd)2892 game_object *level::find_xrange(int x, int y, int type, int xd)
2893 {
2894   int32_t find_ydist=100000;
2895   game_object *find=NULL;
2896   game_object *o=first_active;
2897   for (; o; o=o->next_active)
2898   {
2899     if (o->otype==type)
2900     {
2901       int x_dist=abs(x-o->x);
2902       int y_dist=abs(y-o->y);
2903 
2904       if (x_dist<xd  && y_dist<find_ydist)
2905       {
2906     find_ydist=y_dist;
2907     find=o;
2908       }
2909     }
2910   }
2911   return find;
2912 }
2913 
2914 
find_xclosest(int x,int y,int type,game_object * who)2915 game_object *level::find_xclosest(int x, int y, int type, game_object *who)
2916 {
2917   int32_t find_ydist=100000,find_xdist=0xffffff;
2918   game_object *find=NULL;
2919   game_object *o=first_active;
2920   for (; o; o=o->next_active)
2921   {
2922     if (o->otype==type && o!=who)
2923     {
2924       int x_dist=abs(x-o->x);
2925       if (x_dist<find_xdist)
2926       {
2927     find_xdist=x_dist;
2928     find_ydist=abs(y-o->y);
2929     find=o;
2930       }
2931       else if (x_dist==find_xdist)
2932       {
2933     int y_dist=abs(y-o->y);
2934     if (y_dist<find_ydist)
2935     {
2936       find_ydist=y_dist;
2937       find=o;
2938     }
2939       }
2940     }
2941   }
2942   return find;
2943 }
2944 
find_closest(int x,int y,int type,game_object * who)2945 game_object *level::find_closest(int x, int y, int type, game_object *who)
2946 {
2947   int32_t find_dist=100000;
2948   game_object *find=NULL;
2949   game_object *o=first_active;
2950   for (; o; o=o->next_active)
2951   {
2952     if (o->otype==type && o!=who)
2953     {
2954       int d=(x-o->x)*(x-o->x)+(y-o->y)*(y-o->y);
2955       if (d<find_dist)
2956       {
2957     find=o;
2958     find_dist=d;
2959       }
2960     }
2961   }
2962   return find;
2963 }
2964 
2965 
2966 
remove_light(light_source * which)2967 void level::remove_light(light_source *which)
2968 {
2969   if (which->known)
2970   {
2971     game_object *o=first;
2972     for (; o; o=o->next)
2973     {
2974       int t=o->total_lights();
2975       int i=0;
2976       for (; i<t; i++)
2977         if (o->get_light(i)==which)
2978       o->remove_light(o->get_light(i));
2979     }
2980   }
2981   delete_light(which);
2982 }
2983 
2984 
find_type(int type,int skip)2985 game_object *level::find_type(int type, int skip)
2986 {
2987   game_object *l=NULL;
2988   game_object *o=first;
2989   for (; o; o=o->next)
2990   {
2991     if (o->otype==type)
2992     {
2993       if (!skip)
2994         return o;
2995       skip--;
2996       l=o;
2997     }
2998   }
2999   return l;
3000 }
3001 
hurt_radius(int32_t x,int32_t y,int32_t r,int32_t m,game_object * from,game_object * exclude,int max_push)3002 void level::hurt_radius(int32_t x, int32_t y,int32_t r, int32_t m, game_object *from, game_object *exclude,
3003             int max_push)
3004 {
3005   if (r<1) return ;   // avoid dev vy zero
3006   game_object *o=first_active;
3007   for (; o; o=o->next_active)
3008   {
3009     if (o!=exclude && o->hurtable())
3010     {
3011       int32_t y1=o->y,y2=o->y-o->picture()->Size().y;
3012       int32_t cx=abs(o->x-x),cy1=abs(y1-y),d1,d2,cy2=abs(y2-y);
3013       if (cx<cy1)
3014         d1=cx+cy1-(cx>>1);
3015       else d1=cx+cy1-(cy1>>1);
3016 
3017       if (cx<cy2)
3018         d2=cx+cy2-(cx>>1);
3019       else d2=cx+cy2-(cy2>>1);
3020       if (d2<d1)
3021         d1=d2;
3022 
3023 
3024 
3025       if (d1<r)
3026       {
3027 
3028     int px=(r-cx)*max_push/r,py=(r-cy1)*max_push/r;
3029     if (o->x<x)
3030           px=-px;
3031     if (o->y<y)
3032           py=-py;
3033     o->do_damage((r-d1)*m/r,from,x,y1,px,py);
3034       }
3035 
3036 
3037     }
3038   }
3039 
3040 }
3041 
3042 
3043 
get_random_start(int min_player_dist,view * exclude)3044 game_object *level::get_random_start(int min_player_dist, view *exclude)
3045 {
3046   int t=0;
3047   game_object *o=first;
3048   for (; o; o=o->next)
3049     if (o->otype==start_position_type) t++;    // count how many starts there are in the level
3050 
3051   if (t==0) return NULL;                       // there aren't any starts in level!
3052 
3053   int retries=t;
3054   do
3055   {
3056     int ctry=jrandom(t)+1;
3057     game_object *n=first;
3058     for (n=first; ctry && n; n=n->next)
3059     {
3060       if (n->otype==start_position_type)
3061       {
3062     o=n;
3063         ctry--;
3064       }
3065     }
3066 
3067     int too_close=0;
3068     view *v=player_list;
3069     for (; v; v=v->next)
3070     {
3071       if (v!=exclude)
3072       {
3073     int32_t cx=abs(v->x_center()-o->x),cy=abs(v->y_center()-o->y),d;
3074     if (cx<cy)
3075           d=cx+cy-(cx>>1);
3076     else d=cx+cy-(cy>>1);
3077     if (d<min_player_dist) too_close=1;
3078       }
3079     }
3080     if (too_close) retries--;
3081     else retries=0;
3082   } while (retries);
3083 
3084   return o;
3085 }
3086 
3087 
3088 
3089 
3090 
insert_players()3091 void level::insert_players()
3092 {
3093 
3094   int start=0;
3095   int i=0;
3096   for (; i<total_objects; i++)
3097     if (!strcmp(object_names[i],"START"))
3098       start=i;
3099 
3100   view *f=player_list;
3101   for (; f; f=f->next)
3102   {
3103     game_object *st=find_type(start,f->player_number);
3104     if (st)
3105     {
3106       f->focus->x=st->x;
3107       f->focus->y=st->y;
3108     }
3109     add_object_after(f->focus,st);
3110   }
3111 
3112 }
3113 
3114 
add_attacker(game_object * who)3115 void level::add_attacker(game_object *who)
3116 {
3117   if (attack_total>=attack_list_size)  // see if we need to grow the list size..
3118   {
3119     attack_list_size++;
3120     attack_list=(game_object **)realloc(attack_list,sizeof(game_object *)*attack_list_size);
3121   }
3122   attack_list[attack_total]=who;
3123   attack_total++;
3124 }
3125 
3126 
3127 
add_target(game_object * who)3128 void level::add_target(game_object *who)
3129 {
3130   if (target_total>=target_list_size)  // see if we need to grow the list size..
3131   {
3132     target_list_size++;
3133     target_list=(game_object **)realloc(target_list,sizeof(game_object *)*target_list_size);
3134   }
3135   target_list[target_total]=who;
3136   target_total++;
3137 }
3138 
3139 
3140 
add_block(game_object * who)3141 void level::add_block(game_object *who)
3142 {
3143   if (block_total>=block_list_size)  // see if we need to grow the list size..
3144   {
3145     block_list_size++;
3146     block_list=(game_object **)realloc(block_list,sizeof(game_object *)*block_list_size);
3147   }
3148   block_list[block_total]=who;
3149   block_total++;
3150 }
3151 
3152 
add_all_block(game_object * who)3153 void level::add_all_block(game_object *who)
3154 {
3155   if (all_block_total>=all_block_list_size)  // see if we need to grow the list size..
3156   {
3157     all_block_list_size++;
3158     all_block_list=(game_object **)realloc(all_block_list,sizeof(game_object *)*all_block_list_size);
3159   }
3160   all_block_list[all_block_total]=who;
3161   all_block_total++;
3162 }
3163 
3164 
find_object_in_area(int32_t x,int32_t y,int32_t x1,int32_t y1,int32_t x2,int32_t y2,Cell * list,game_object * exclude)3165 game_object *level::find_object_in_area(int32_t x, int32_t y, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
3166                      Cell *list, game_object *exclude)
3167 {
3168   game_object *closest=NULL;
3169   int32_t closest_distance=0xfffffff,distance,xo,yo;
3170   game_object *o=first_active;
3171   for (; o; o=o->next_active)
3172   {
3173     int32_t xp1,yp1,xp2,yp2;
3174     o->picture_space(xp1,yp1,xp2,yp2);
3175 
3176 
3177     if (!(xp1>x2 || xp2<x1 || yp1>y2 || yp2<y1) && o!=exclude)
3178     {
3179       // check to see if the type is in the list
3180       Cell *v=list;
3181       for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3182       if (!NILP(v))
3183       {
3184     xo=abs(o->x-x);
3185     yo=abs(o->y-y);
3186     distance=xo*xo+yo*yo;
3187     if (distance<closest_distance)
3188     {
3189       closest_distance=distance;
3190       closest=o;
3191     }
3192       }
3193     }
3194   }
3195   return closest;
3196 }
3197 
3198 
3199 
3200 
find_object_in_angle(int32_t x,int32_t y,int32_t start_angle,int32_t end_angle,void * list,game_object * exclude)3201 game_object *level::find_object_in_angle(int32_t x, int32_t y, int32_t start_angle, int32_t end_angle,
3202                     void *list, game_object *exclude)
3203 {
3204   game_object *closest=NULL;
3205   int32_t closest_distance=0xfffffff,distance,xo,yo;
3206   game_object *o=first_active;
3207   for (; o; o=o->next_active)
3208   {
3209     int32_t angle=lisp_atan2(o->y-y,o->x-x);
3210     if (((start_angle<=end_angle && (angle>=start_angle && angle<=end_angle))
3211     || (start_angle>end_angle && (angle>=start_angle || angle<=end_angle)))
3212     && o!=exclude)
3213     {
3214       // check to see if the type is in the list
3215       Cell *v=(Cell *)list;
3216       for (; !NILP(v) && lnumber_value(CAR(v))!=o->otype; v=CDR(v));
3217       if (!NILP(v))
3218       {
3219     xo=abs(o->x-x);
3220     yo=abs(o->y-y);
3221     distance=xo*xo+yo*yo;
3222     if (distance<closest_distance)
3223     {
3224       closest_distance=distance;
3225       closest=o;
3226     }
3227       }
3228     }
3229   }
3230   return closest;
3231 }
3232 
3233 
make_not_list(object_node * list)3234 object_node *level::make_not_list(object_node *list)
3235 {
3236   object_node *f=NULL,*l=NULL;
3237   game_object *o=first;
3238   for (; o; o=o->next)
3239   {
3240     if (!object_to_number_in_list(o,list))
3241     {
3242       object_node *q=new object_node(o,NULL);
3243       if (f)
3244         l->next=q;
3245       else f=q;
3246       l=q;
3247     }
3248   }
3249   return f;
3250 }
3251 
write_object_info(char * filename)3252 void level::write_object_info(char *filename)
3253 {
3254   FILE *fp=open_FILE(filename,"wb");
3255   if (fp)
3256   {
3257     int i=0;
3258     game_object *o=first;
3259     for (; o; o=o->next)
3260     {
3261       fprintf(fp,"%3d %s %4ld %4ld %4ld %4ld %04d\n",i++,object_names[o->otype],(long)o->x,(long)o->y,
3262           (long)o->xvel(),(long)o->yvel(),o->current_frame);
3263     }
3264     fclose(fp);
3265   }
3266 }
3267 
3268 
area_controller(int32_t X,int32_t Y,int32_t W,int32_t H,area_controller * Next)3269 area_controller::area_controller(int32_t X, int32_t Y, int32_t W, int32_t H, area_controller *Next)
3270 {
3271   x=X; y=Y; w=W; h=H;
3272   next=Next; active=0;
3273 
3274   ambient=-1;
3275   view_xoff=-1;
3276   view_yoff=-1;
3277   ambient_speed=2;
3278   view_xoff_speed=4;
3279   view_yoff_speed=4;
3280 }
3281