1 /*
2
3 *************************************************************************
4
5 ArmageTron -- Just another Tron Lightcycle Game in 3D.
6 Copyright (C) 2000 Manuel Moos (manuel@moosnet.de)
7
8 **************************************************************************
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 ***************************************************************************
25
26 */
27
28 #include "uInput.h"
29 #include "tMemManager.h"
30 #include "rScreen.h"
31 #include "tInitExit.h"
32 #include "tConfiguration.h"
33 #include "rConsole.h"
34 #include "uMenu.h"
35 #include "tSysTime.h"
36
37 bool su_mouseGrab = false;
38
39 static uAction* su_allActions[uMAX_ACTIONS];
40 static int su_allActionsLen = 0;
41
uAction(uAction * & anchor,const char * name,int priority_,uInputType t)42 uAction::uAction(uAction *&anchor,const char* name,
43 int priority_,
44 uInputType t)
45 :tListItem<uAction>(anchor),type(t),priority(priority_),internalName(name){
46 globalID = localID = su_allActionsLen++;
47
48 tASSERT(localID < uMAX_ACTIONS);
49
50 su_allActions[localID] = this;
51
52 tString descname;
53 descname << "input_" << name << "_text";
54 tToLower( descname );
55
56 const_cast<tOutput&>(description).AddLocale(descname);
57
58 tString helpname;
59 helpname << "input_" << name << "_help";
60 tToLower( helpname );
61
62 const_cast<tOutput&>(helpText).AddLocale(helpname);
63 }
64
uAction(uAction * & anchor,const char * name,const tOutput & desc,const tOutput & help,int priority_,uInputType t)65 uAction::uAction(uAction *&anchor,const char* name,
66 const tOutput& desc,
67 const tOutput& help,
68 int priority_,
69 uInputType t)
70 :tListItem<uAction>(anchor),type(t),priority(priority_),internalName(name), description(desc), helpText(help){
71 globalID = localID = su_allActionsLen++;
72
73 tASSERT(localID < uMAX_ACTIONS);
74
75 su_allActions[localID] = this;
76 }
77
~uAction()78 uAction::~uAction(){
79 su_allActions[localID] = NULL;
80 }
81
Find(char const * name)82 uAction * uAction::Find( char const * name )
83 {
84 for(int i=su_allActionsLen-1;i>=0;i--)
85 if(!strcmp(name,su_allActions[i]->internalName))
86 return su_allActions[i];
87
88 return 0;
89 }
90
91 // ****************************************
92 // a configuration class for keyboard binds
93 // ****************************************
94
95 class tConfItem_key:public tConfItemBase{
96 public:
tConfItem_key()97 tConfItem_key():tConfItemBase("KEYBOARD"){}
~tConfItem_key()98 ~tConfItem_key(){}
99
100 // write the complete keymap
WriteVal(std::ostream & s)101 virtual void WriteVal(std::ostream &s){
102 int first=1;
103 for(int keysym=SDLK_NEWLAST-1;keysym>=0;keysym--){
104 if (keymap[keysym]){
105
106 if (!first)
107 s << "\nKEYBOARD\t";
108 else
109 first=0;
110
111 s << keysym << '\t';
112 keymap[keysym]->Write(s);
113 }
114 }
115 if (first)
116 s << "-1";
117 }
118
119 // read one keybind
ReadVal(std::istream & s)120 virtual void ReadVal(std::istream &s){
121 tString in;
122 int keysym;
123 s >> keysym;
124 if (keysym>=0){
125 tASSERT(keysym < SDLK_NEWLAST);
126 s >> in;
127 if (uBindPlayer::IsKeyWord(in))
128 {
129 keymap[keysym] = NULL;
130 keymap[keysym]=uBindPlayer::NewBind(s);
131 if (!keymap[keysym]->act)
132 {
133 keymap[keysym]=NULL;
134 }
135 /* if (global_bind::IsKeyWord(in))
136 keymap[keysym]=new global_bind(s); */
137 }
138 }
139 char c=' ';
140 while(c!='\n' && s.good() && !s.eof()) c=s.get();
141 }
142 };
143
144 // we need just one
145 static tConfItem_key x;
146
147 static uAction *s_playerActions;
148 static uAction *s_cameraActions;
149 static uAction *s_globalActions;
150
uActionPlayer(const char * name,int priority,uInputType t)151 uActionPlayer::uActionPlayer(const char *name,
152 int priority,
153 uInputType t)
154 :uAction(s_playerActions,name,priority,t){}
155
uActionPlayer(const char * name,const tOutput & desc,const tOutput & help,int priority,uInputType t)156 uActionPlayer::uActionPlayer(const char *name,
157 const tOutput& desc,
158 const tOutput& help,
159 int priority,
160 uInputType t)
161 :uAction(s_playerActions,name,desc,help,priority,t){}
162
~uActionPlayer()163 uActionPlayer::~uActionPlayer(){}
164
operator ==(const uActionPlayer & x)165 bool uActionPlayer::operator==(const uActionPlayer &x){
166 return x.globalID == globalID;}
167
Find(int id)168 uActionPlayer *uActionPlayer::Find(int id){
169 uAction *run = s_playerActions;
170
171 while (run){
172 if (run->ID() == id)
173 return static_cast<uActionPlayer*>(run);
174 run = run->Next();
175 }
176
177 return NULL;
178 }
179
180
uActionCamera(const char * name,int priority,uInputType t)181 uActionCamera::uActionCamera(const char *name,
182 int priority,
183 uInputType t)
184 :uAction(s_cameraActions,name,priority,t){}
185
~uActionCamera()186 uActionCamera::~uActionCamera(){}
187
operator ==(const uActionCamera & x)188 bool uActionCamera::operator==(const uActionCamera &x){
189 return x.globalID == globalID;}
190
191
192 // global actions
uActionGlobal(const char * name,int priority,uInputType t)193 uActionGlobal::uActionGlobal(const char *name,
194 int priority,
195 uInputType t)
196 :uAction(s_globalActions,name,priority,t){}
197
~uActionGlobal()198 uActionGlobal::~uActionGlobal(){}
199
operator ==(const uActionGlobal & x)200 bool uActionGlobal::operator==(const uActionGlobal &x){
201 return x.globalID == globalID;}
202
IsBreakingGlobalBind(int sym)203 bool uActionGlobal::IsBreakingGlobalBind(int sym){
204 if (!keymap[sym])
205 return false;
206 uAction *act=keymap[sym]->act;
207 if (!act)
208 return false;
209
210 return uActionGlobalFunc::IsBreakingGlobalBind(act);
211 }
212
213 // ***************************
214 // the generic keymaps
215 // ***************************
216
217 tJUST_CONTROLLED_PTR< uBind > keymap[SDLK_NEWLAST];
218 bool pressed[SDLK_NEWLAST];
219
keyboard_init()220 static void keyboard_init(){
221 for(int i=0;i<SDLK_NEWLAST;i++)
222 keymap[i]=NULL;
223 //uBindPlayer::Init();
224 //global_bind::Init();
225 }
226
keyboard_exit()227 static void keyboard_exit(){
228 for(int i=0;i<SDLK_NEWLAST;i++)
229 keymap[i] = 0;
230 //uBindPlayer::Init();
231 //global_bind::Init();
232 }
233
234 static tInitExit keyboard_ie(&keyboard_init, &keyboard_exit);
235
236 // *********************************************
237 // generic keypress/mouse movement binding class
238 // *********************************************
239
~uBind()240 uBind::~uBind(){}
241
uBind(uAction * a)242 uBind::uBind(uAction *a ):lastValue_(0), delayedValue_(0), lastSym_(-1), lastTime_(-1), act(a){}
243
uBind(std::istream & s)244 uBind::uBind(std::istream &s): lastValue_(0), delayedValue_(0), lastSym_(-1), lastTime_(-1), act(NULL)
245 {
246 std::string name;
247 s >> name;
248 act = uAction::Find( name.c_str() );
249 }
250
Write(std::ostream & s)251 void uBind::Write(std::ostream &s){
252 s << act->internalName << '\t';
253 }
254
GlobalAct(uAction * act,REAL x)255 bool GlobalAct(uAction *act,REAL x){
256 return uActionGlobalFunc::GlobalAct(act,x);
257 }
258
Activate(REAL x,bool delayed)259 bool uBind::Activate(REAL x, bool delayed )
260 {
261 delayedValue_ = x;
262
263 if ( !delayed || !Delayable() )
264 {
265 lastValue_ = x;
266 return this->DoActivate( x );
267 }
268
269 return true;
270 }
271
HanldeDelayed()272 void uBind::HanldeDelayed()
273 {
274 if ( lastValue_ != delayedValue_ )
275 {
276 lastValue_ = delayedValue_;
277 this->DoActivate( delayedValue_ );
278 }
279 }
280
281 REAL su_doubleBindTimeout=-10.0f;
282
IsDoubleBind(int sym)283 bool uBind::IsDoubleBind( int sym )
284 {
285 double currentTime = tSysTimeFloat();
286
287 // if a different key was used for this action a short while ago, give alarm.
288 bool ret = ( su_doubleBindTimeout > 0 && sym != lastSym_ && currentTime - lastTime_ < su_doubleBindTimeout );
289
290 // store last usage
291 lastSym_ = sym;
292 lastTime_ = currentTime;
293
294 // return result
295 return ret;
296 }
297
298 // *******************
299 // player config
300 // *******************
301
302 static int nextid = 0;
303
PlayerConfig(int i)304 uPlayerPrototype* uPlayerPrototype::PlayerConfig(int i){
305 tASSERT(i>=0 && i<uMAX_PLAYERS);
306 return playerConfig[i];
307 }
308
309
uPlayerPrototype()310 uPlayerPrototype::uPlayerPrototype(){
311 static bool inited=false;
312 if (!inited)
313 {
314 for(int i=uMAX_PLAYERS-1; i >=0; i--)
315 playerConfig[i] = NULL;
316
317 inited = true;
318 }
319
320 id = nextid++;
321 tASSERT(id < uMAX_PLAYERS);
322 playerConfig[id] = this;
323
324
325 }
326
~uPlayerPrototype()327 uPlayerPrototype::~uPlayerPrototype(){
328 playerConfig[id] = NULL;
329 }
330
331 uPlayerPrototype* uPlayerPrototype::playerConfig[uMAX_PLAYERS];
332
Num()333 int uPlayerPrototype::Num(){return nextid;}
334
335 // *******************
336 // Input configuration
337 // *******************
338
339
340 // *****************************************************
341 // Menuitem for input selection
342 // *****************************************************
343
keyname(int sym)344 static char const * keyname(int sym){
345 #ifndef DEDICATED
346 if (sym<=SDLK_LAST)
347 return SDL_GetKeyName(static_cast<SDLKey>(sym));
348 else switch (sym){
349 case SDLK_MOUSE_X_PLUS: return "Mouse right";
350 case SDLK_MOUSE_X_MINUS: return "Mouse left";
351 case SDLK_MOUSE_Y_PLUS: return "Mouse up";
352 case SDLK_MOUSE_Y_MINUS: return "Mouse down";
353 case SDLK_MOUSE_Z_PLUS: return "Mouse z up";
354 case SDLK_MOUSE_Z_MINUS: return "Mouse z down";
355 case SDLK_MOUSE_BUTTON_1: return "Mousebutton 1";
356 case SDLK_MOUSE_BUTTON_2: return "Mousebutton 2";
357 case SDLK_MOUSE_BUTTON_3: return "Mousebutton 3";
358 case SDLK_MOUSE_BUTTON_4: return "Mousebutton 4";
359 case SDLK_MOUSE_BUTTON_5: return "Mousebutton 5";
360 case SDLK_MOUSE_BUTTON_6: return "Mousebutton 6";
361 case SDLK_MOUSE_BUTTON_7: return "Mousebutton 7";
362 }
363 #endif
364 return "";
365 }
366
367 class uMenuItemInput: uMenuItem{
368 uAction *act;
369 int ePlayer;
370 bool active;
371 public:
uMenuItemInput(uMenu * M,uAction * a,int p)372 uMenuItemInput(uMenu *M,uAction *a,int p)
373 :uMenuItem(M,a->helpText),act(a),ePlayer(p),active(0){
374 }
375
~uMenuItemInput()376 virtual ~uMenuItemInput(){}
377
Render(REAL x,REAL y,REAL alpha=1,bool selected=0)378 virtual void Render(REAL x,REAL y,REAL alpha=1,bool selected=0){
379 DisplayText(REAL(x-.02),y,act->description,selected,alpha,1);
380
381 if (active)
382 {
383 tString s;
384 s << tOutput("$input_press_any_key");
385 DisplayText(REAL(x+.02),y,s,selected,alpha,-1);
386 }
387 else{
388 tString s;
389
390 bool first=1;
391
392 for(int keysym=SDLK_NEWLAST-1;keysym>=0;keysym--)
393 if(keymap[keysym] &&
394 keymap[keysym]->act==act &&
395 keymap[keysym]->CheckPlayer(ePlayer)){
396 if (!first)
397 s << ", ";
398 else
399 first=0;
400
401 s << keyname(keysym);
402 }
403 if(!first)
404 DisplayText(REAL(x+.02),y,s,selected,alpha,-1);
405 else
406 DisplayText(REAL(x+.02),y,tOutput("$input_items_unbound"),selected,alpha,-1);
407 }
408 }
409
Enter()410 virtual void Enter(){
411 active=1;
412 }
413
414 #define MTHRESH 5
415 #define MREL 2
416
417 #ifndef DEDICATED
418
Event(SDL_Event & e)419 virtual bool Event(SDL_Event &e){
420 int sym=-1;
421 switch (e.type){
422 case SDL_MOUSEMOTION:
423 if(active){
424 REAL xrel=e.motion.xrel;
425 REAL yrel=-e.motion.yrel;
426
427 if (fabs(xrel)>MREL*fabs(yrel)){ // x motion
428 if (xrel>MTHRESH) // left
429 sym=SDLK_MOUSE_X_PLUS;
430 if (xrel<-MTHRESH) // left
431 sym=SDLK_MOUSE_X_MINUS;
432 }
433
434 if (fabs(yrel)>MREL*fabs(xrel)){ // x motion
435 if (yrel>MTHRESH) // left
436 sym=SDLK_MOUSE_Y_PLUS;
437 if (yrel<-MTHRESH) // left
438 sym=SDLK_MOUSE_Y_MINUS;
439 }
440
441 if (sym>0)
442 active=0;
443 }
444
445 break;
446 case SDL_MOUSEBUTTONDOWN:
447 if(active){
448 int button=e.button.button;
449 if (button<=MOUSE_BUTTONS)
450 sym=SDLK_MOUSE_BUTTON_1+button-1;
451
452 active=0;
453 }
454 break;
455
456 case SDL_KEYDOWN:{
457 SDL_keysym &c=e.key.keysym;
458 if(!active){
459 if (c.sym==SDLK_DELETE || c.sym==SDLK_BACKSPACE)
460 {
461 for(int keysym=SDLK_NEWLAST-1;keysym>=0;keysym--)
462 if(keymap[keysym] &&
463 keymap[keysym]->act==act &&
464 keymap[keysym]->CheckPlayer(ePlayer)){
465 keymap[keysym]=NULL;
466 }
467 return true;
468 }
469 return false;
470 }
471
472 active=0;
473
474 if (c.sym!=SDLK_ESCAPE)
475 sym=c.sym;
476 else
477 return true;
478 }
479 break;
480 default:
481 return(false);
482 }
483
484 if(sym>=0){
485 if(keymap[sym] &&
486 keymap[sym]->act==act &&
487 keymap[sym]->CheckPlayer(ePlayer)){
488 keymap[sym]=NULL;
489 }
490 else{
491 keymap[sym]=NULL;
492 keymap[sym]=uBindPlayer::NewBind(act,ePlayer);
493 }
494 return true;
495 }
496 return false;
497 }
498 #endif
499
Help()500 virtual tString Help(){
501 tString ret;
502 ret << helpText << "\n";
503 ret << tOutput("$input_item_help");
504 return ret;
505 }
506 };
507
508 namespace
509 {
510 class Input_Comparator
511 {
512 public:
Compare(const uAction * a,const uAction * b)513 static int Compare( const uAction* a, const uAction* b )
514 {
515 if ( a->priority < b->priority )
516 return 1;
517 else if ( a->priority > b->priority )
518 return -1;
519 return tString::CompareAlphaNumerical( a->internalName, b->internalName );
520 }
521 };
522 }
523
Input_Compare(const tListItemBase * a,const tListItemBase * b)524 static int Input_Compare( const tListItemBase* a, const tListItemBase* b)
525
526 {
527 return Input_Comparator::Compare( (const uAction*)a, (const uAction*)b );
528 }
529
530
s_InputConfigGeneric(int ePlayer,uAction * & actions,const tOutput & title)531 static void s_InputConfigGeneric(int ePlayer, uAction *&actions,const tOutput &title){
532 uMenuItemInput **input;
533
534 uMenu input_menu(title);
535
536 if(actions)
537 actions->tListItemBase::Sort(&Input_Compare);
538
539 int len = actions->Len();
540
541 input=tNEW(uMenuItemInput*)[len];
542 int a=0;
543 for(uAction *A=actions;A; A = A->Next()){
544 input[a++]=new uMenuItemInput(&input_menu,
545 A,
546 ePlayer+1);
547
548 }
549
550 input_menu.ReverseItems();
551 input_menu.Enter();
552
553 for(int b=a-1;b>=0;b--)
554 delete input[b];
555 delete[] input;
556 }
557
su_InputConfig(int ePlayer)558 void su_InputConfig(int ePlayer){
559
560 tOutput name;
561 name.SetTemplateParameter(1, ePlayer+1);
562 name.SetTemplateParameter(2, uPlayerPrototype::PlayerConfig(ePlayer)->Name());
563 name << "$input_for_player";
564
565 s_InputConfigGeneric(ePlayer,s_playerActions,name);
566 }
567
su_InputConfigCamera(int player)568 void su_InputConfigCamera(int player){
569
570 tOutput name;
571 name.SetTemplateParameter(1, uPlayerPrototype::PlayerConfig(player)->Name());
572 name << "$camera_controls";
573
574 s_InputConfigGeneric(player,s_cameraActions,name);
575 }
576
su_InputConfigGlobal()577 void su_InputConfigGlobal(){
578 s_InputConfigGeneric(-1,s_globalActions,"$input_items_global");
579 }
580
581
582 REAL mouse_sensitivity=REAL(.1);
583 REAL key_sensitivity=40;
584 static double lastTime=0;
585 static REAL ts=0;
586
587 static bool su_delayed = false;
588
su_HandleDelayedEvents()589 void su_HandleDelayedEvents ()
590 {
591 // nothing to do
592 if ( !su_delayed )
593 {
594 return;
595 }
596
597 su_delayed = false;
598
599 for ( int i = SDLK_NEWLAST - 1; i>=0; --i )
600 {
601 if ( keymap[i] )
602 {
603 keymap[i]->HanldeDelayed();
604 }
605 }
606 }
607
su_HandleEvent(SDL_Event & e,bool delayed)608 bool su_HandleEvent(SDL_Event &e, bool delayed ){
609 #ifndef DEDICATED
610 int sym=-1;
611 REAL pm=0;
612
613 if ( su_delayed && !delayed )
614 {
615 su_HandleDelayedEvents();
616 }
617
618 su_delayed = delayed;
619
620 // there is nearly alllways a mouse motion tEvent:
621 int xrel=e.motion.xrel;
622 int yrel=-e.motion.yrel;
623
624
625 switch (e.type){
626 case SDL_MOUSEMOTION:
627 if ( !su_mouseGrab ||
628 e.motion.x!=sr_screenWidth/2 || e.motion.x!=sr_screenHeight/2)
629 {
630 if (keymap[SDLK_MOUSE_X_PLUS])
631 keymap[SDLK_MOUSE_X_PLUS]->Activate(xrel*mouse_sensitivity, delayed );
632
633 if (keymap[SDLK_MOUSE_X_MINUS])
634 keymap[SDLK_MOUSE_X_MINUS]->Activate(-xrel*mouse_sensitivity, delayed );
635
636 if (keymap[SDLK_MOUSE_Y_PLUS])
637 keymap[SDLK_MOUSE_Y_PLUS]->Activate(yrel*mouse_sensitivity, delayed );
638
639 if (keymap[SDLK_MOUSE_Y_MINUS])
640 keymap[SDLK_MOUSE_Y_MINUS]->Activate(-yrel*mouse_sensitivity, delayed );
641 }
642
643
644 return true; // no fuss: allways pretend to have handled this.
645 break;
646
647 case SDL_MOUSEBUTTONDOWN:
648 case SDL_MOUSEBUTTONUP:{
649 int button=e.button.button;
650 if (button<=MOUSE_BUTTONS){
651 sym=SDLK_MOUSE_BUTTON_1+button-1;
652 }
653 }
654 if (e.type==SDL_MOUSEBUTTONDOWN)
655 pm=1;
656 else
657 pm=-1;
658 break;
659
660 case SDL_KEYDOWN:
661 sym=e.key.keysym.sym;
662 pm=1;
663 break;
664
665 case SDL_KEYUP:
666 sym=e.key.keysym.sym;
667 pm=-1;
668 break;
669
670 default:
671 break;
672 }
673 if (sym>=0 && keymap[sym]){
674 REAL realpm=pm;
675 if (keymap[sym]->act->type==uAction::uINPUT_ANALOG)
676 pm*=ts*key_sensitivity;
677 pressed[sym]=(realpm>0);
678 if ( pm > 0 && keymap[sym]->IsDoubleBind( sym ) )
679 return true;
680 return (keymap[sym]->Activate(pm, delayed ));
681
682 }
683 else
684 #endif
685 return false;
686 }
687
su_InputSync()688 void su_InputSync(){
689 double time=tSysTimeFloat();
690 ts=REAL(time-lastTime);
691
692 //static REAL tsSmooth=0;
693 //tsSmooth+=REAL(ts*.1);
694 //tsSmooth/=REAL(1.1);
695 lastTime=time;
696
697 for(int sym=SDLK_NEWLAST-1;sym>=0;sym--)
698 if (pressed[sym] && keymap[sym] &&
699 keymap[sym]->act->type==uAction::uINPUT_ANALOG)
700 keymap[sym]->Activate(ts*key_sensitivity, su_delayed );
701 }
702
su_ClearKeys()703 void su_ClearKeys()
704 {
705 for(int sym=SDLK_NEWLAST-1;sym>=0;sym--)
706 {
707 if (pressed[sym] && keymap[sym] )
708 keymap[sym]->Activate(-1, su_delayed );
709 pressed[sym] = false;
710 }
711 }
712
713 // *****************
714 // Player binds
715 // *****************
716
717 static char const * Player_keyword="PLAYER_BIND";
718
uBindPlayer(uAction * a,int p)719 uBindPlayer::uBindPlayer(uAction *a,int p):uBind(a),ePlayer(p){}
720
~uBindPlayer()721 uBindPlayer::~uBindPlayer(){}
722
NewBind(std::istream & s)723 uBindPlayer * uBindPlayer::NewBind(std::istream &s)
724 {
725 // read action
726 std::string actionName;
727 s >> actionName;
728 uAction * act = uAction::Find( actionName.c_str() );
729
730 // read player ID
731 int player;
732 s >> player;
733
734 // delegate
735 return NewBind( act, player );
736 }
737
NewBind(uAction * action,int player)738 uBindPlayer * uBindPlayer::NewBind( uAction * action, int player )
739 {
740 // see if the bind has an alias
741 for ( int i = SDLK_NEWLAST-1; i >= 0; --i )
742 {
743 // compare action
744 uBind * old = keymap[i];
745 if ( old && old->act == action )
746 {
747 uBindPlayer * oldPlayer = dynamic_cast< uBindPlayer * >( old );
748 if ( oldPlayer && oldPlayer->ePlayer == player )
749 return oldPlayer;
750 }
751 }
752
753 // no alias found, return new bind
754 return tNEW(uBindPlayer)( action, player );
755 }
756
IsKeyWord(const char * n)757 bool uBindPlayer::IsKeyWord(const char *n){
758 return !strcmp(n,Player_keyword);
759 }
760
CheckPlayer(int p)761 bool uBindPlayer::CheckPlayer(int p){
762 return p==ePlayer;
763 }
764
Write(std::ostream & s)765 void uBindPlayer::Write(std::ostream &s){
766 s << Player_keyword << '\t';
767 uBind::Write(s);
768 s << ePlayer;
769 }
770
Delayable()771 bool uBindPlayer::Delayable()
772 {
773 return ( ePlayer!=0 );
774 }
775
DoActivate(REAL x)776 bool uBindPlayer::DoActivate(REAL x){
777 if (ePlayer==0)
778 return GlobalAct(act,x);
779 else
780 return uPlayerPrototype::PlayerConfig(ePlayer-1)->Act(act,x);
781 }
782
783
784 // *****************
785 // Global actions
786 // *****************
787
788 static uActionGlobalFunc *uActionGlobal_anchor=NULL;
789
uActionGlobalFunc(uActionGlobal * a,ACTION_FUNC * f,bool rebind)790 uActionGlobalFunc::uActionGlobalFunc(uActionGlobal *a, ACTION_FUNC *f,
791 bool rebind )
792 :tListItem<uActionGlobalFunc>(uActionGlobal_anchor), func (f), act(a),
793 rebindable(rebind){}
794
IsBreakingGlobalBind(uAction * act)795 bool uActionGlobalFunc::IsBreakingGlobalBind(uAction *act){
796 for(uActionGlobalFunc *run = uActionGlobal_anchor; run ; run = run->Next())
797 if (run->act == act && !run->rebindable)
798 return true;
799
800 return false;
801 }
802
GlobalAct(uAction * act,REAL x)803 bool uActionGlobalFunc::GlobalAct(uAction *act, REAL x){
804 for(uActionGlobalFunc *run = uActionGlobal_anchor; run ; run = run->Next())
805 if (run->act == act && run->func(x))
806 return true;
807
808 return false;
809 }
810
811 static uActionGlobal mess_up("MESS_UP");
812
813 static uActionGlobal mess_down("MESS_DOWN");
814
messup_func(REAL x)815 static bool messup_func(REAL x){
816 if (x>0){
817 sr_con.Scroll(-1);
818 }
819 return true;
820 }
821
messdown_func(REAL x)822 static bool messdown_func(REAL x){
823 if (x>0){
824 sr_con.Scroll(1);
825 }
826 return true;
827 }
828
829 static uActionGlobalFunc mu(&mess_up,&messup_func);
830 static uActionGlobalFunc md(&mess_down,&messdown_func);
831