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