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 #include <unistd.h>
16
17 #include "common.h"
18
19 #include "game.h"
20
21 #include "view.h"
22 #include "lisp.h"
23 #include "jwindow.h"
24 #include "configuration.h"
25 #include "scroller.h"
26 #include "id.h"
27 #include "dev.h"
28 #include "jrand.h"
29 #include "dprint.h"
30 #include "transp.h"
31 #include "clisp.h"
32 #include "demo.h"
33 #include "sbar.h"
34 #include "nfserver.h"
35 #include "chat.h"
36
37 #define SHIFT_DOWN_DEFAULT 15
38 #define SHIFT_RIGHT_DEFAULT 0
39
40 extern int get_key_binding( char const *dir, int i );
41 view *player_list=NULL;
42 int morph_sel_frame_color;
43
~view()44 view::~view()
45 {
46 if (local_player())
47 sbar.associate(NULL);
48
49 if (total_weapons)
50 {
51 free(weapons);
52 free(last_weapons);
53 }
54 }
55
56
57 extern uint8_t bright_tint[256];
58
add_ammo(int weapon_type,int total)59 void view::add_ammo(int weapon_type, int total)
60 {
61 if (weapon_type>=total_weapons || weapon_type<0)
62 {
63 printf("weapon out of range\n");
64 return ;
65 }
66 if (weapons[weapon_type]==-1) return ; // don't have weapon yet, can't give ammo
67
68 weapons[weapon_type]+=total;
69 if (weapons[weapon_type]<0)
70 weapons[weapon_type]=0;
71
72 if (weapons[weapon_type]>999)
73 weapons[weapon_type]=999;
74
75 if (weapon_total(current_weapon)==0 && current_weapon)
76 {
77 suggest.send_weapon_change=1;
78 if (DEFINEDP(symbol_value(l_switch_to_powerful)) && symbol_value(l_switch_to_powerful))
79 {
80 int x=total_weapons-1;
81 while (x>0 && (x==3 || weapons[x]<=0)) x--;
82 suggest.new_weapon=x;
83 } else
84 suggest.new_weapon=0;
85 }
86
87 }
88
give_weapon(int type)89 void view::give_weapon(int type)
90 {
91 if (type>=total_weapons || type<0)
92 {
93 printf("weapon out of range\n");
94 return ;
95 }
96 if (weapons[type]==-1)
97 {
98 weapons[type]=0;
99 sbar.need_refresh();
100 }
101 }
102
weapon_total(int type)103 int view::weapon_total(int type)
104 {
105 if (type>=total_weapons || type<0)
106 {
107 printf("weapon out of range\n");
108 return 0;
109 }
110 if (god) return 100;
111 else if (weapons[type]==-1) return 0;
112 else return weapons[type];
113 }
114
115
xoff()116 int32_t view::xoff()
117 {
118 if (focus)
119 {
120 int x=last_x-(cx2-cx1+1)/2+shift_right+pan_x;
121 if (x<0) return 0;
122 else return x;
123 } else return pan_x;
124 }
125
interpolated_xoff()126 int32_t view::interpolated_xoff()
127 {
128 if (focus)
129 {
130 int x=(last_last_x+last_x)/2-(cx2-cx1+1)/2+shift_right+pan_x;
131 if (x<0) return 0;
132 else return x;
133 } else return pan_x;
134 }
135
136
yoff()137 int32_t view::yoff()
138 {
139 if (focus)
140 {
141 int y=last_y-(cy2-cy1+1)/2-shift_down+pan_y;
142 if (y<0) return 0;
143 else return y;
144 } else return pan_y;
145 }
146
147
interpolated_yoff()148 int32_t view::interpolated_yoff()
149 {
150 if (focus)
151 {
152 int y=(last_y+last_last_y)/2-(cy2-cy1+1)/2-shift_down+pan_y;
153 if (y<0) return 0;
154 else return y;
155 } else return pan_y;
156 }
157
158
update_scroll()159 void view::update_scroll()
160 {
161 if (focus)
162 {
163 last_last_x=last_x;
164 last_last_y=last_y;
165 if (focus->x>last_x)
166 {
167 if (focus->x-last_x>=no_xright)
168 last_x=focus->x-no_xright;
169 } else if (focus->x<last_x)
170 {
171 if (last_x-focus->x>=no_xleft)
172 last_x=focus->x+no_xleft;
173 }
174 if (focus->y>last_y)
175 {
176 if (focus->y-last_y>=no_ybottom)
177 last_y=focus->y-no_ybottom;
178 } else if (focus->y<last_y)
179 {
180 if (last_y-focus->y>=no_ytop)
181 last_y=focus->y+no_ytop;
182 }
183 }
184 }
185
186 static char cur_user_name[20] = { 0 };
187
get_login()188 char const *get_login()
189 {
190 if (cur_user_name[0])
191 return cur_user_name;
192
193 #if defined __CELLOS_LV2__
194 /* FIXME: retrieve login name */
195 return "Player";
196 #else
197 char const *login = getlogin();
198 return login ? login : "unknown";
199 #endif
200 }
201
set_login(char const * name)202 void set_login(char const *name)
203 {
204 strncpy(cur_user_name, name, 20);
205 }
206
view(game_object * Focus,view * Next,int number)207 view::view(game_object *Focus, view *Next, int number)
208 {
209 chat_buf[0]=0;
210
211 draw_solid=-1;
212 no_xleft=0;
213 no_xright=0;
214 no_ytop=0;
215 no_ybottom=0;
216 if (Focus)
217 {
218 last_x=Focus->x;
219 last_y=Focus->y;
220 } else
221 {
222 last_x=last_y=0;
223 }
224
225 last_last_x=last_x;
226 last_last_y=last_y;
227 last_hp=last_ammo=-1;
228 last_type=-1;
229 tsecrets=secrets=0;
230 tkills=kills=0;
231
232 reset_keymap();
233
234 ambient=32;
235 current_weapon=0;
236
237 strcpy(name,get_login());
238 suggest.send_view=0;
239 suggest.send_weapon_change=0;
240
241
242 god=0;
243
244 player_number=number;
245 cx1=0;
246 cy1=0;
247 cx2=100;
248 cy2=100;
249 focus=Focus;
250 next=Next;
251 shift_down=SHIFT_DOWN_DEFAULT;
252 shift_right=SHIFT_RIGHT_DEFAULT;
253 x_suggestion=0;
254 y_suggestion=0;
255 b1_suggestion=0;
256 b2_suggestion=0;
257 b3_suggestion=0;
258 b4_suggestion=0;
259 pointer_x=0;
260 pointer_y=0;
261
262 pan_x=0;
263 pan_y=0;
264 last_type=0;
265 freeze_time=0;
266
267 if (total_weapons)
268 {
269 weapons=(int32_t *)malloc(total_weapons*sizeof(int32_t));
270 last_weapons=(int32_t *)malloc(total_weapons*sizeof(int32_t));
271 memset(weapons,0xff,total_weapons*sizeof(int32_t)); // set all to -1
272 memset(last_weapons,0xff,total_weapons*sizeof(int32_t)); // set all to -1
273 }
274
275 if (total_weapons)
276 weapons[0]=0;
277 if (local_player())
278 sbar.associate(this);
279 set_tint(number);
280 set_team(-1);
281 sbar.need_refresh();
282 }
283
x_center()284 int32_t view::x_center()
285 {
286 if (!focus)
287 return (cx1+cx2)/2;
288 else
289 return focus->x;
290 }
291
y_center()292 int32_t view::y_center()
293 {
294 if (!focus)
295 return (cy1+cy2)/2;
296 else
297 return focus->y;
298 }
299
draw_character_damage()300 void view::draw_character_damage()
301 {
302 if (focus && drawable())
303 {
304 if (last_hp!=focus->hp()) draw_hp();
305 int i;
306 for (i=0; i<total_weapons; i++)
307 if (weapons[i]!=last_weapons[i])
308 {
309 last_weapons[i]=weapons[i];
310 sbar.draw_ammo(screen,i,weapons[i],current_weapon==i);
311 }
312 }
313 }
314
315
316
make_sync()317 uint16_t make_sync()
318 {
319 uint16_t x=0;
320 if (!current_level) return 0;
321 if (current_level)
322 {
323 view *f=player_list;
324 for (; f; f=f->next)
325 {
326 if (f->focus)
327 {
328 x^=(f->focus->x&0xffff);
329 x^=(f->focus->y&0xffff);
330 }
331 }
332 }
333 x^=rand_on;
334
335 return x;
336 }
337
338
339
get_input()340 void view::get_input()
341 {
342 int sug_x,sug_y,sug_b1,sug_b2,sug_b3,sug_b4;
343 int32_t sug_px,sug_py;
344
345 // NOTE:(AK) I have commented this out so we don't use the lisp
346 // file "input.lsp" to get our key mappings.
347 /* if( DEFINEDP( symbol_function( l_get_local_input ) ) )
348 {
349 void *ret = ((LSymbol *)l_get_local_input->EvalFunction(NULL);
350 sug_x = lnumber_value( CAR( ret ) );
351 ret = CDR( ret );
352 sug_y = lnumber_value( CAR( ret ) );
353 ret = CDR( ret );
354 if( CAR( ret ) )
355 sug_b1 = 1;
356 else
357 sug_b1 = 0;
358 ret = CDR( ret );
359 if( CAR( ret ) )
360 sug_b2 = 1;
361 else
362 sug_b2 = 0;
363 ret = CDR( ret );
364 int x = lnumber_value( CAR( ret ) );
365 ret = CDR( ret );
366 if( x < 0 )
367 sug_b3 = 1;
368 else
369 sug_b3 = 0;
370 if( x > 0 )
371 sug_b4 = 1;
372 else sug_b4 = 0;
373
374 int32_t bx = lnumber_value( CAR( ret ) );
375 ret = CDR( ret );
376 int32_t by = lnumber_value( CAR( ret ) );
377 ret = CDR( ret );
378 the_game->mouse_to_game( bx, by, sug_px, sug_py, this );
379
380 }
381 else*/
382 {
383 get_movement( 0, sug_x, sug_y, sug_b1, sug_b2, sug_b3, sug_b4 );
384 if( focus )
385 {
386 the_game->mouse_to_game( last_demo_mx, last_demo_my, sug_px, sug_py, this );
387 if( last_demo_mbut & 1 )
388 sug_b2 = 1;
389 if( last_demo_mbut & 2 )
390 sug_b1 = 1;
391 }
392 else
393 sug_px = sug_py = 0;
394 }
395
396 #if !defined __CELLOS_LV2__
397 if( view_changed() )
398 {
399 base->packet.write_uint8( SCMD_VIEW_RESIZE );
400 base->packet.write_uint8( player_number );
401 base->packet.write_uint32( suggest.cx1 );
402 base->packet.write_uint32( suggest.cy1 );
403 base->packet.write_uint32( suggest.cx2 );
404 base->packet.write_uint32( suggest.cy2 );
405
406 base->packet.write_uint32( suggest.pan_x );
407 base->packet.write_uint32( suggest.pan_y );
408 base->packet.write_uint32( suggest.shift_down );
409 base->packet.write_uint32( suggest.shift_right );
410 }
411
412 if( weapon_changed() )
413 {
414 base->packet.write_uint8( SCMD_WEAPON_CHANGE );
415 base->packet.write_uint8( player_number );
416 base->packet.write_uint32( suggest.new_weapon );
417 }
418
419 base->packet.write_uint8( SCMD_SET_INPUT );
420 base->packet.write_uint8( player_number );
421
422 uint8_t mflags = 0;
423 if( sug_x > 0 )
424 mflags |= 1;
425 else if ( sug_x < 0 )
426 mflags |= 2;
427
428 if( sug_y > 0 )
429 mflags |= 4;
430 else if( sug_y < 0 )
431 mflags |= 8;
432
433 if( sug_b1 )
434 mflags |= 16;
435 if( sug_b2 )
436 mflags |= 32;
437 if( sug_b3 )
438 mflags |= 64;
439 if( sug_b4 )
440 mflags |= 128;
441
442 base->packet.write_uint8( mflags );
443 base->packet.write_uint16((uint16_t)((int16_t)sug_px));
444 base->packet.write_uint16((uint16_t)((int16_t)sug_py));
445 #endif
446 }
447
448
add_chat_key(int key)449 void view::add_chat_key(int key) // return string if buf is complete
450 {
451 int len=strlen(chat_buf);
452 if (key==JK_BACKSPACE)
453 {
454 if (len)
455 {
456 chat_buf[len-1]=0;
457 if (local_player() && chat)
458 chat->draw_user(chat_buf);
459 }
460 } else if (key!=JK_ENTER)
461 {
462 chat_buf[len]=key;
463 chat_buf[len+1]=0;
464 if (local_player() && chat)
465 chat->draw_user(chat_buf);
466 }
467
468 if (len>38 || key==JK_ENTER)
469 {
470 if (DEFINEDP(l_chat_input->GetFunction()))
471 {
472 game_object *o=current_object;
473 current_object=focus;
474
475 void *m=mark_heap(TMP_SPACE);
476 void *list=NULL;
477 push_onto_list(LString::Create(chat_buf),list);
478 ((LSymbol *)l_chat_input)->EvalFunction(list);
479 restore_heap(m,TMP_SPACE);
480
481 current_object=o;
482
483 } else
484 {
485 if (chat)
486 chat->put_all(chat_buf);
487 }
488 chat_buf[0]=0;
489 if (local_player() && chat)
490 chat->draw_user(chat_buf);
491 }
492 }
493
process_input(char cmd,uint8_t * & pk)494 int view::process_input(char cmd, uint8_t *&pk) // return 0 if something went wrong
495 {
496 #if !defined __CELLOS_LV2__
497 switch (cmd)
498 {
499 case SCMD_CHAT_KEYPRESS :
500 {
501 add_chat_key(*(pk++));
502 } break;
503 case SCMD_VIEW_RESIZE :
504 {
505 int32_t x[8];
506 memcpy(x,pk,8*4); pk+=8*4;
507 cx1=lltl(x[0]);
508 cy1=lltl(x[1]);
509 cx2=lltl(x[2]);
510 cy2=lltl(x[3]);
511
512 pan_x=lltl(x[4]);
513 pan_y=lltl(x[5]);
514 shift_down=lltl(x[6]);
515 shift_right=lltl(x[7]);
516 if (small_render)
517 {
518 small_render->Scale(vec2i(cx2 - cx1 + 1, cy2 - cy1 + 1));
519 }
520
521 suggest.send_view=0;
522 if (local_player())
523 the_game->draw();
524 return 1;
525 }
526 case SCMD_WEAPON_CHANGE :
527 {
528 int32_t x;
529 memcpy(&x,pk,4); pk+=4;
530 current_weapon=lltl(x);
531
532 if (local_player())
533 sbar.need_refresh();
534 suggest.send_weapon_change=0;
535 return 1;
536 } break;
537
538 case SCMD_SET_INPUT :
539 {
540 uint8_t x=*(pk++);
541
542 if (x&1) x_suggestion=1;
543 else if (x&2) x_suggestion=-1;
544 else x_suggestion=0;
545
546 if (x&4) y_suggestion=1;
547 else if (x&8) y_suggestion=-1;
548 else y_suggestion=0;
549
550 if (x&16) b1_suggestion=1; else b1_suggestion=0;
551 if (x&32) b2_suggestion=1; else b2_suggestion=0;
552 if (x&64) b3_suggestion=1; else b3_suggestion=0;
553 if (x&128) b4_suggestion=1; else b4_suggestion=0;
554
555 uint16_t p[2];
556 memcpy(p,pk,2*2); pk+=2*2;
557
558 pointer_x=(int16_t)(lstl(p[0]));
559 pointer_y=(int16_t)(lstl(p[1]));
560
561 return 1;
562 } break;
563 case SCMD_KEYPRESS : set_key_down(*(pk++),1); break;
564 case SCMD_EXT_KEYPRESS : set_key_down(*(pk++)+256,1); break;
565 case SCMD_KEYRELEASE : set_key_down(*(pk++),0); break;
566 case SCMD_EXT_KEYRELEASE : set_key_down(*(pk++)+256,0); break;
567 }
568 #endif
569 return 1;
570 }
571
local_player()572 int view::local_player()
573 {
574 #if defined __CELLOS_LV2__
575 return 1;
576 #else
577 return player_number==client_number();
578 #endif
579 }
580
next_weapon()581 void view::next_weapon()
582 {
583 int c=current_weapon;
584
585 while (c<total_weapons-1)
586 {
587 c++;
588 if (weapon_total(c)>0)
589 {
590 suggest.send_weapon_change=1;
591 suggest.new_weapon=c;
592 return ;
593 }
594 }
595
596 c=0;
597 while (c!=current_weapon)
598 {
599 if (weapon_total(c)>0)
600 {
601 suggest.send_weapon_change=1;
602 suggest.new_weapon=c;
603 return ;
604 }
605 c++;
606 }
607 }
608
last_weapon()609 void view::last_weapon()
610 {
611
612 int c=current_weapon;
613
614 while (c>=1)
615 {
616 c--;
617 if (weapon_total(c)>0 || c==0)
618 {
619 suggest.send_weapon_change=1;
620 suggest.new_weapon=c;
621 return ;
622 }
623 }
624
625 c=total_weapons-1;
626 while (c!=current_weapon)
627 {
628 if (weapon_total(c)>0 || c==0)
629 {
630 suggest.send_weapon_change=1;
631 suggest.new_weapon=c;
632 return ;
633 }
634 c--;
635 }
636
637 }
638
handle_event(event & ev)639 int view::handle_event(event &ev)
640 {
641 if( ev.type == EV_KEY )
642 {
643 if( ev.key == (int)',' )
644 {
645 if( total_weapons )
646 {
647 last_weapon();
648 }
649 return 1;
650 }
651 else if( ev.key == (int)'.' )
652 {
653 if( total_weapons )
654 {
655 next_weapon();
656 }
657 return 1;
658 }
659 else if( ev.key == get_key_binding( "b3", 0 ) )
660 {
661 if( total_weapons )
662 {
663 last_weapon();
664 }
665 return 1;
666 }
667 else if( ev.key == get_key_binding( "b4", 0 ) )
668 {
669 if( total_weapons )
670 {
671 next_weapon();
672 }
673 return 1;
674 }
675
676 switch( ev.key )
677 {
678 case '1':
679 case '2':
680 case '3':
681 case '4':
682 case '5':
683 case '6':
684 case '7':
685 {
686 if((( dev & EDIT_MODE ) == 0 ) && ( weapon_total( ev.key - '1' ) > 0 ))
687 {
688 suggest.send_weapon_change = 1;
689 suggest.new_weapon=ev.key - '1';
690 }
691 } break;
692
693 case JK_HOME:
694 case JK_CTRL_L:
695 case JK_CTRL_R:
696 {
697 if( total_weapons )
698 {
699 last_weapon();
700 }
701 return 1;
702 } break;
703 case JK_PAGEUP:
704 case JK_INSERT:
705 {
706 if( total_weapons )
707 {
708 next_weapon();
709 }
710 return 1;
711 } break;
712 }
713 }
714 return 0;
715 }
716
draw_hp()717 void view::draw_hp()
718 {
719 if (focus)
720 {
721 int h = focus->hp();
722 last_hp=h;
723 sbar.draw_health( screen, focus->hp() );
724 }
725 else
726 {
727 sbar.draw_health( screen, 0 );
728 }
729 }
730
drawable()731 int view::drawable()
732 {
733 return local_player();
734 }
735
736
recalc_local_view_space()737 void recalc_local_view_space() // calculates view areas for local players, should be called
738 // when adding or deleting local players
739 {
740 if (screen)
741 {
742 int t=total_local_players();
743 if (!t) return ;
744
745 int Xres=small_render ? xres/2 : xres;
746 int Yres=small_render ? yres/2 : yres;
747
748 int h=Yres/t;
749 int w=h*320/200,y=5;
750 if (w<300) w=300;
751
752 for (view *f=player_list; f; f=f->next)
753 {
754 if (f->local_player())
755 {
756 f->suggest.cx1=Xres/2-w/2;
757 f->suggest.cx2=Xres/2+w/2;
758 if (f->suggest.cx1<2) f->suggest.cx1=2;
759 if (f->suggest.cx2>Xres-2) f->suggest.cx2=Xres-2;
760
761 f->suggest.cy1=y;
762 f->suggest.cy2=h-(total_weapons ? 33 : 0);
763
764 f->suggest.shift_down=f->shift_down;
765 f->suggest.shift_right=f->shift_right;
766 f->suggest.pan_x=f->pan_x;
767 f->suggest.pan_y=f->pan_y;
768 f->suggest.send_view=1;
769
770 if (!player_list->next)
771 {
772 f->cx1=f->suggest.cx1;
773 f->cy1=f->suggest.cy1;
774 f->cx2=f->suggest.cx2;
775 f->cy2=f->suggest.cy2;
776 f->suggest.send_view=0;
777 }
778 y+=h;
779 }
780 }
781 }
782
783 }
784
785
set_local_players(int total)786 void set_local_players(int total)
787 {
788 int rdw=0;
789 if (total<1) return ;
790
791 view *last=NULL;
792 for (view *f=player_list; f; f=f->next)
793 {
794 if (total && f->local_player())
795 total--;
796 else if (!total && f->local_player()) // too many local players, delete this one
797 {
798 view *n=last->next;
799 while (n && !n->local_player()) n=n->next; // find next local player
800
801 if (last)
802 last->next=n;
803 else
804 {
805 if (n) // make sure we have at least one local player
806 player_list=n;
807 }
808 last=f;
809 rdw=1;
810 }
811 }
812
813 while (total) // see if we need to add new players
814 {
815 game_object *o=create(current_start_type,50,50);
816 view *v;
817 if (!player_list)
818 {
819 player_list=new view(o,NULL,0);
820 v=player_list;
821 }
822 else
823 {
824 view *f=player_list;
825 for (; f && f->next; f=f->next);
826 f->next=new view(o,NULL,f->player_number+1);
827 v=f->next;
828 }
829 v->cx1=320/2-155; v->cy1=200/2-95; v->cx2=320/2+155; v->cy2=200/2+(total_weapons ? 60 : 95);
830 v->focus->set_controller(v);
831 total--;
832 rdw=1;
833 }
834 if (rdw)
835 recalc_local_view_space();
836 }
837
838
total_local_players()839 int total_local_players()
840 {
841 int t=0;
842 for (view *f=player_list; f; f=f->next)
843 if (f->local_player()) t++;
844 return t;
845 }
846
847
resize_view(int32_t Cx1,int32_t Cy1,int32_t Cx2,int32_t Cy2)848 void view::resize_view(int32_t Cx1, int32_t Cy1, int32_t Cx2, int32_t Cy2)
849 {
850 if (cx1!=Cx1 || cx2!=Cx2 || cy1!=Cy1 || cy2!=Cy2)
851 {
852 cx1=Cx1; cy1=Cy1;
853 cx2=Cx2; cy2=Cy2;
854 if (playing_state(the_game->state) && local_player())
855 the_game->draw(0);
856 }
857 }
858
859
set_input(int cx,int cy,int b1,int b2,int b3,int b4,int px,int py)860 void view::set_input(int cx, int cy, int b1, int b2, int b3, int b4, int px, int py)
861 {
862 x_suggestion=cx;
863 y_suggestion=cy;
864 b1_suggestion=b1;
865 b2_suggestion=b2;
866 b3_suggestion=b3;
867 b4_suggestion=b4;
868 pointer_x=px;
869 pointer_y=py;
870 }
871
872
873
reset_player()874 void view::reset_player()
875 {
876 if (focus)
877 {
878
879 game_object *start=current_level ? current_level->get_random_start(320,focus->controller()) : 0;
880 focus->defaults();
881 if (start)
882 {
883 focus->x=start->x;
884 focus->y=start->y;
885 dprintf("reset player position to %d %d\n",start->x,start->y);
886 }
887 focus->set_state(stopped);
888 focus->set_tint(_tint);
889 focus->set_team(_team);
890 memset(weapons,0xff,total_weapons*sizeof(int32_t));
891 memset(last_weapons,0xff,total_weapons*sizeof(int32_t));
892
893 shift_down=SHIFT_DOWN_DEFAULT;
894 shift_right=SHIFT_RIGHT_DEFAULT;
895
896 if (total_weapons)
897 weapons[0]=0; // give him the first weapon
898 current_weapon=0;
899
900 memset(focus->lvars,0,figures[focus->otype]->tv*4);
901 focus->set_aistate(0);
902 if (figures[focus->otype]->get_fun(OFUN_CONSTRUCTOR))
903 {
904 game_object *o=current_object;
905 current_object=focus;
906 ((LSymbol *)figures[focus->otype]->get_fun(OFUN_CONSTRUCTOR))->EvalUserFunction(NULL);
907 current_object=o;
908 }
909 sbar.redraw(screen);
910
911 int i;
912 for (i=0; i<focus->total_objects(); i++) // reset the vars for the attached objects
913 {
914 game_object *o=focus->get_object(i);
915 memset(o->lvars,0,figures[o->otype]->tv*4);
916 }
917
918 }
919 }
920
921
922
923
924
make_player_onodes(int player_num)925 object_node *make_player_onodes(int player_num)
926 {
927 object_node *first=NULL,*last=NULL;
928 for (view *o=player_list; o; o=o->next)
929 {
930 if (o->focus && (player_num==-1 || o->player_number==player_num))
931 {
932 if (!object_to_number_in_list(o->focus,first))
933 {
934 object_node *q=new object_node(o->focus,NULL);
935 if (first)
936 last->next=q;
937 else first=q;
938 last=q;
939 }
940 for (int i=0; i<o->focus->total_objects(); i++)
941 {
942 game_object *p=o->focus->get_object(i);
943
944 if (!object_to_number_in_list(p,first))
945 {
946 object_node *q=new object_node(p,NULL);
947 if (first)
948 last->next=q;
949 else first=q;
950 last=q;
951 }
952 }
953 }
954 }
955 return first;
956 }
957
958
959
960
961 enum { V_CX1, V_CY1, V_CX2, V_CY2,
962 V_SHIFT_DOWN, V_SHIFT_RIGHT,
963 V_GOD,
964 V_PLAYER_NUMBER,
965 V_DRAW_SOLID,
966 V_LIVES,
967 V_CURRENT_WEAPON,
968 V_X_SUGGESTION, V_Y_SUGGESTION, V_B1_SUGGESTION, V_B2_SUGGESTION, V_B3_SUGGESTION, V_B4_SUGGESTION,
969 V_PAN_X, V_PAN_Y,
970 V_NO_XLEFT, V_NO_XRIGHT, V_NO_YTOP, V_NO_YBOTTOM,
971 V_LAST_X, V_LAST_Y, V_LAST_LEFT, V_LAST_RIGHT, V_LAST_UP, V_LAST_DOWN,
972 V_LAST_B1, V_LAST_B2, V_LAST_B3, V_LAST_B4,
973 V_LAST_HP,
974 V_SECRETS, V_KILLS, V_TSECRETS, V_TKILLS,
975 V_AMBIENT,
976 V_POINTER_X, V_POINTER_Y,
977 V_LAST_LAST_X, V_LAST_LAST_Y,
978 V_FREEZE_TIME };
979
980 #define TVV (V_FREEZE_TIME+1)
981
982 static char const *vv_names[TVV] =
983 {
984 "view.cx1", "view.cy1", "view.cx2", "view.cy2",
985 "view.shift_down", "view.shift_right",
986 "view.god",
987 "view.player_number",
988 "view.draw_solid",
989 "view.lives",
990 "view.current_weapon",
991 "view.x_suggestion", "view.y_suggestion",
992 "view.b1_suggestion", "view.b2_suggestion", "view.b3_suggestion", "view.b4_suggestion",
993 "view.pan_x", "view.pan_y",
994 "view.no_xleft", "view.no_xright", "view.no_ytop", "view.no_ybottom",
995 "view.last_x", "view.last_y", "view.last_left", "view.last_right", "view.last_up", "view.last_down",
996 "view.last_b1", "view.last_b2", "view.last_b3", "view.last_b4",
997 "view.last_hp",
998 "view.secrets", "view.kills", "view.tsecrets", "view.tkills",
999 "view.ambient",
1000 "view.pointer_x", "view.pointer_y",
1001 "view.last_last_x", "view.last_last_y",
1002 "view.freeze_time"
1003 };
1004
1005
total_view_vars()1006 int total_view_vars()
1007 { return TVV;
1008 }
1009
get_view_var_name(int num)1010 char const *get_view_var_name(int num)
1011 { return vv_names[num]; }
1012
get_view_var_value(int num)1013 int32_t view::get_view_var_value(int num)
1014 {
1015 switch (num)
1016 {
1017 case V_CX1 : return cx1; break;
1018 case V_CY1 : return cy1; break;
1019 case V_CX2 : return cx2; break;
1020 case V_CY2 : return cy2; break;
1021 case V_SHIFT_DOWN : return shift_down; break;
1022 case V_SHIFT_RIGHT : return shift_right; break;
1023 case V_GOD : return god; break;
1024 case V_PLAYER_NUMBER : return player_number; break;
1025
1026 case V_DRAW_SOLID : return draw_solid; break;
1027 case V_CURRENT_WEAPON : return current_weapon; break;
1028 case V_X_SUGGESTION : return x_suggestion; break;
1029 case V_Y_SUGGESTION : return y_suggestion; break;
1030 case V_B1_SUGGESTION : return b1_suggestion; break;
1031 case V_B2_SUGGESTION : return b2_suggestion; break;
1032 case V_B3_SUGGESTION : return b3_suggestion; break;
1033 case V_B4_SUGGESTION : return b4_suggestion; break;
1034
1035 case V_PAN_X : return pan_x; break;
1036 case V_PAN_Y : return pan_y; break;
1037 case V_NO_XLEFT : return no_xleft; break;
1038 case V_NO_XRIGHT : return no_xright; break;
1039 case V_NO_YTOP : return no_ytop; break;
1040 case V_NO_YBOTTOM : return no_ybottom; break;
1041 case V_LAST_X : return last_x; break;
1042 case V_LAST_Y : return last_y; break;
1043 case V_LAST_LEFT : return last_left; break;
1044 case V_LAST_RIGHT : return last_right; break;
1045 case V_LAST_UP : return last_up; break;
1046 case V_LAST_DOWN : return last_down; break;
1047 case V_LAST_B1 : return last_b1; break;
1048 case V_LAST_B2 : return last_b2; break;
1049 case V_LAST_B3 : return last_b3; break;
1050 case V_LAST_B4 : return last_b4; break;
1051 case V_LAST_HP : return last_hp; break;
1052 case V_SECRETS : return secrets; break;
1053 case V_KILLS : return kills; break;
1054 case V_TSECRETS : return tsecrets; break;
1055 case V_TKILLS : return tkills; break;
1056 case V_AMBIENT : return ambient; break;
1057 case V_POINTER_X : return pointer_x; break;
1058 case V_POINTER_Y : return pointer_y; break;
1059 case V_LAST_LAST_X : return last_last_x; break;
1060 case V_LAST_LAST_Y : return last_last_y; break;
1061 case V_FREEZE_TIME : return freeze_time; break;
1062 }
1063 return 0;
1064 }
1065
1066
1067
set_view_var_value(int num,int32_t x)1068 int32_t view::set_view_var_value(int num, int32_t x)
1069 {
1070 switch (num)
1071 {
1072 case V_CX1 : cx1=x; break;
1073 case V_CY1 : cy1=x; break;
1074 case V_CX2 : cx2=x; break;
1075 case V_CY2 : cy2=x; break;
1076 case V_SHIFT_DOWN : shift_down=x; break;
1077 case V_SHIFT_RIGHT : shift_right=x; break;
1078 case V_GOD : god=x; break;
1079 case V_PLAYER_NUMBER : { player_number=x; if (local_player()) sbar.associate(this); } break;
1080
1081 case V_DRAW_SOLID : draw_solid=x; break;
1082 case V_CURRENT_WEAPON : { current_weapon=x; sbar.need_refresh(); } break;
1083 case V_X_SUGGESTION : x_suggestion=x; break;
1084 case V_Y_SUGGESTION : y_suggestion=x; break;
1085 case V_B1_SUGGESTION : b1_suggestion=x; break;
1086 case V_B2_SUGGESTION : b2_suggestion=x; break;
1087 case V_B3_SUGGESTION : b3_suggestion=x; break;
1088 case V_B4_SUGGESTION : b4_suggestion=x; break;
1089
1090 case V_PAN_X : pan_x=x; break;
1091 case V_PAN_Y : pan_y=x; break;
1092 case V_NO_XLEFT : no_xleft=x; break;
1093 case V_NO_XRIGHT : no_xright=x; break;
1094 case V_NO_YTOP : no_ytop=x; break;
1095 case V_NO_YBOTTOM : no_ybottom=x; break;
1096 case V_LAST_X : last_x=x; break;
1097 case V_LAST_Y : last_y=x; break;
1098 case V_LAST_LEFT : last_left=x; break;
1099 case V_LAST_RIGHT : last_right=x; break;
1100 case V_LAST_UP : last_up=x; break;
1101 case V_LAST_DOWN : last_down=x; break;
1102 case V_LAST_B1 : last_b1=x; break;
1103 case V_LAST_B2 : last_b2=x; break;
1104 case V_LAST_B3 : last_b3=x; break;
1105 case V_LAST_B4 : last_b4=x; break;
1106
1107 case V_LAST_HP : last_hp=x; break;
1108 case V_SECRETS : secrets=x; break;
1109 case V_KILLS : kills=x; break;
1110 case V_TSECRETS : tsecrets=x; break;
1111 case V_TKILLS : tkills=x; break;
1112 case V_AMBIENT : ambient=x; break;
1113 case V_POINTER_X : pointer_x=x; break;
1114 case V_POINTER_Y : pointer_y=x; break;
1115 case V_LAST_LAST_X : last_last_x=x; break;
1116 case V_LAST_LAST_Y : last_last_y=x; break;
1117 case V_FREEZE_TIME : freeze_time=x; break;
1118 }
1119 return 1;
1120 }
1121
1122
configure_for_area(area_controller * a)1123 void view::configure_for_area(area_controller *a)
1124 {
1125 if (a->ambient>=0 && a->ambient!=ambient)
1126 {
1127 if (ambient>a->ambient)
1128 {
1129 ambient-=a->ambient_speed;
1130 if (ambient<a->ambient)
1131 ambient=a->ambient;
1132 }
1133 else
1134 {
1135 ambient+=a->ambient_speed;
1136 if (ambient>a->ambient)
1137 ambient=a->ambient;
1138 }
1139 }
1140
1141 if (!view_shift_disabled)
1142 {
1143 if (a->view_xoff!=pan_x)
1144 {
1145 if (pan_x>a->view_xoff)
1146 {
1147 pan_x-=a->view_xoff_speed;
1148 if (pan_x<a->view_xoff)
1149 pan_x=a->view_xoff;
1150 }
1151 else
1152 {
1153 pan_x+=a->view_xoff_speed;
1154 if (pan_x>a->view_xoff)
1155 pan_x=a->view_xoff;
1156 }
1157 }
1158
1159 if (a->view_yoff!=pan_y)
1160 {
1161 if (pan_y>a->view_yoff)
1162 {
1163 pan_y-=a->view_yoff_speed;
1164 if (pan_y<a->view_yoff)
1165 pan_y=a->view_yoff;
1166 }
1167 else
1168 {
1169 pan_y+=a->view_yoff_speed;
1170 if (pan_y>a->view_yoff)
1171 pan_y=a->view_yoff;
1172 }
1173 }
1174 }
1175 }
1176
1177
process_packet_commands(uint8_t * pk,int size)1178 void process_packet_commands(uint8_t *pk, int size)
1179 {
1180 #if !defined __CELLOS_LV2__
1181 int32_t sync_uint16=-1;
1182
1183 if (!size) return ;
1184 pk[size]=SCMD_END_OF_PACKET;
1185
1186 uint8_t cmd;
1187 int already_reloaded=0;
1188
1189
1190 do
1191 {
1192 cmd=*(pk++);
1193 switch (cmd)
1194 {
1195 case SCMD_WEAPON_CHANGE :
1196 case SCMD_SET_INPUT :
1197 case SCMD_VIEW_RESIZE :
1198 case SCMD_KEYPRESS :
1199 case SCMD_KEYRELEASE :
1200 case SCMD_EXT_KEYPRESS :
1201 case SCMD_EXT_KEYRELEASE :
1202 case SCMD_CHAT_KEYPRESS :
1203 {
1204 uint8_t player_num=*(pk++);
1205
1206 view *v=player_list;
1207 for (; v && v->player_number!=player_num; v=v->next);
1208 if (v)
1209 {
1210 if (v->player_number==player_num)
1211 v->process_input(cmd,pk);
1212 }
1213 else
1214 {
1215 dprintf("Evil error : bad player number in packet\n");
1216 return ;
1217 }
1218 } break;
1219 case SCMD_RELOAD :
1220 {
1221 if (!already_reloaded)
1222 {
1223 net_reload();
1224 already_reloaded=1;
1225 }
1226 } break;
1227
1228 case SCMD_SYNC :
1229 {
1230 uint16_t x;
1231 memcpy(&x,pk,2); pk+=2;
1232 x=lstl(x);
1233 if (demo_man.current_state()==demo_manager::PLAYING)
1234 sync_uint16=make_sync();
1235
1236 if (sync_uint16==-1)
1237 sync_uint16=x;
1238 else if (x!=sync_uint16 && !already_reloaded)
1239 {
1240 dprintf("out of sync %d (packet=%d, calced=%d)\n",current_level->tick_counter(),x,sync_uint16);
1241 if (demo_man.current_state()==demo_manager::NORMAL)
1242 net_reload();
1243 already_reloaded=1;
1244 }
1245 } break;
1246 case SCMD_DELETE_CLIENT :
1247 {
1248 uint8_t player_num=*(pk++);
1249 view *v=player_list,*last=NULL;
1250 for (; v && v->player_number!=player_num; v=v->next)
1251 last=v;
1252 if (!v)
1253 dprintf("evil : delete client %d, but no such client\n");
1254 else
1255 {
1256
1257 // make a list of all objects associated with this player
1258 object_node *on=make_player_onodes(player_num);
1259 while (on)
1260 {
1261 current_level->delete_object(on->me);
1262 object_node *last=on;
1263 on=on->next;
1264 delete last;
1265 }
1266
1267 v->focus=NULL;
1268 if (last)
1269 last->next=v->next;
1270 else player_list=player_list->next;
1271
1272 delete v;
1273 }
1274 } break;
1275 default :
1276 dprintf("Unknown net command %d\n",cmd);
1277
1278 }
1279 } while (cmd!=SCMD_END_OF_PACKET);
1280 #endif
1281 }
1282
set_tint(int tint)1283 void view::set_tint(int tint)
1284 {
1285 if(tint < 0)
1286 tint = 0;
1287 _tint = tint;
1288 focus->set_tint(tint);
1289 }
1290
get_tint()1291 int view::get_tint()
1292 {
1293 return _tint;
1294 }
1295
set_team(int team)1296 void view::set_team(int team)
1297 {
1298 if(team < 0)
1299 team = 0;
1300 _team = team;
1301 focus->set_team(team);
1302 }
1303
get_team()1304 int view::get_team()
1305 {
1306 return _team;
1307 }
1308
1309