1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: draw.cpp
5 Desc: contains various definitions for player code
6
7 Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 See LICENSE for details.
9
10 -------------------------------------------------------------------------------*/
11
12 #include "player.hpp"
13 #include "game.hpp"
14 #include "main.hpp"
15 #include "interface/interface.hpp"
16 #include "items.hpp"
17 #include "shops.hpp"
18
19 Player** players = nullptr;
20
21 Entity* selectedEntity = nullptr;
22 int current_player = 0;
23 Sint32 mousex = 0, mousey = 0;
24 Sint32 omousex = 0, omousey = 0;
25 Sint32 mousexrel = 0, mouseyrel = 0;
26
27 bool splitscreen = false;
28
29 int gamepad_deadzone = 8000;
30 int gamepad_trigger_deadzone = 18000;
31 int gamepad_leftx_sensitivity = 1400;
32 int gamepad_lefty_sensitivity = 1400;
33 int gamepad_rightx_sensitivity = 500;
34 int gamepad_righty_sensitivity = 600;
35 int gamepad_menux_sensitivity = 1400;
36 int gamepad_menuy_sensitivity = 1400;
37
38 bool gamepad_leftx_invert = false;
39 bool gamepad_lefty_invert = false;
40 bool gamepad_rightx_invert = false;
41 bool gamepad_righty_invert = false;
42 bool gamepad_menux_invert = false;
43 bool gamepad_menuy_invert = false;
44
45
46 GameController* game_controller = nullptr;
47
GameController()48 GameController::GameController()
49 {
50 sdl_device = nullptr;
51 id = -1;
52 name = "";
53
54 oldLeftTrigger = 0;
55 oldRightTrigger = 0;
56 }
57
~GameController()58 GameController::~GameController()
59 {
60 if (sdl_device)
61 {
62 close();
63 }
64 }
65
close()66 void GameController::close()
67 {
68 if (sdl_device)
69 {
70 SDL_GameControllerClose(sdl_device);
71 sdl_device = nullptr;
72 }
73 }
74
open(int c)75 bool GameController::open(int c)
76 {
77 if (sdl_device)
78 {
79 close();
80 }
81
82 if (c < 0 || c >= SDL_NumJoysticks())
83 {
84 return false;
85 }
86
87 if (!SDL_IsGameController(c))
88 {
89 return false;
90 }
91
92 sdl_device = SDL_GameControllerOpen(c);
93
94 if (sdl_device == nullptr)
95 {
96 printlog("Error: Failed to open game controller! SDL Error: %s\n", SDL_GetError());
97 }
98 else
99 {
100 id = c;
101 printlog("Successfully initialized game controller!\n");
102 name = (SDL_GameControllerNameForIndex(c));
103 printlog("Controller name is \"%s\"", name.c_str());
104 }
105
106
107 return (sdl_device != nullptr);
108 }
109
isActive()110 bool GameController::isActive()
111 {
112 return (sdl_device != nullptr);
113 }
114
handleAnalog()115 void GameController::handleAnalog()
116 {
117 if (!isActive())
118 {
119 return;
120 }
121
122 //Right analog stick = look.
123
124 if (!shootmode || gamePaused)
125 {
126 int rightx = getRawRightXMove() / gamepad_menux_sensitivity;
127 int righty = getRawRightYMove() / gamepad_menuy_sensitivity;
128
129
130
131 //The right stick's inversion and the menu's inversion should be independent of eachother. This just undoes any inversion.
132 if (gamepad_rightx_invert)
133 {
134 rightx = -rightx;
135 }
136 if (gamepad_righty_invert)
137 {
138 righty = -righty;
139 }
140
141 if (gamepad_menux_invert)
142 {
143 rightx = -rightx;
144 }
145 if (gamepad_menuy_invert)
146 {
147 righty = -righty;
148 }
149
150 if (rightx || righty)
151 {
152 SDL_WarpMouseInWindow(screen, std::max(0, std::min(xres, mousex + rightx)), std::max(0, std::min(yres, mousey + righty)));
153 }
154 }
155 else
156 {
157 int rightx = getRightXMove();
158 int righty = getRightYMove();
159
160 if (rightx || righty)
161 {
162 SDL_Event e;
163
164 e.type = SDL_MOUSEMOTION;
165 e.motion.x = mousex + rightx;
166 e.motion.y = mousey + righty;
167 e.motion.xrel = rightx;
168 e.motion.yrel = righty;
169 SDL_PushEvent(&e);
170 }
171 }
172
173 if (getLeftTrigger())
174 {
175 if ( !oldLeftTrigger )
176 {
177 oldLeftTrigger = 1;
178 joy_trigger_status[0] = 1;
179 lastkeypressed = 299;
180 }
181 }
182 else
183 {
184 oldLeftTrigger = 0;
185 joy_trigger_status[0] = 0;
186 }
187
188 if (getRightTrigger())
189 {
190 if ( !oldRightTrigger )
191 {
192 oldRightTrigger = 1;
193 joy_trigger_status[1] = 1;
194 lastkeypressed = 300;
195 }
196 }
197 else
198 {
199 oldRightTrigger = 0;
200 joy_trigger_status[1] = 0;
201 }
202 }
203
getLeftXMove()204 int GameController::getLeftXMove()
205 {
206 if (!isActive())
207 {
208 return 0;
209 }
210
211 int x = getRawLeftXMove();
212
213 x /= gamepad_leftx_sensitivity;
214
215 return x;
216 }
217
getLeftYMove()218 int GameController::getLeftYMove()
219 {
220 if (!isActive())
221 {
222 return 0;
223 }
224
225 int y = -getRawLeftYMove();
226
227 y /= gamepad_lefty_sensitivity;
228
229 return y;
230 }
231
getRightXMove()232 int GameController::getRightXMove()
233 {
234 if (!isActive())
235 {
236 return 0;
237 }
238
239 int x = getRawRightXMove();
240
241 x /= gamepad_rightx_sensitivity;
242
243 return x;
244 }
245
getRightYMove()246 int GameController::getRightYMove()
247 {
248 if (!isActive())
249 {
250 return 0;
251 }
252
253 int y = getRawRightYMove();
254
255 y /= gamepad_righty_sensitivity;
256
257 return y;
258 }
259
260
261
getLeftTrigger()262 int GameController::getLeftTrigger()
263 {
264 return getRawLeftTrigger(); //No sensitivity taken into account (yet)
265 }
266
getRightTrigger()267 int GameController::getRightTrigger()
268 {
269 return getRawRightTrigger(); //No sensitivity taken into account (yet)
270 }
271
272
getRawLeftXMove()273 int GameController::getRawLeftXMove()
274 {
275 if (!isActive())
276 {
277 return 0;
278 }
279
280 int x = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_LEFTX);
281
282 if (x < gamepad_deadzone && x > -gamepad_deadzone)
283 {
284 return 0;
285 }
286
287 if (x < -gamepad_deadzone) //TODO: Give each controller a deadzone setting? Or maybe on a player by player basis? And/or each analog stick its own deadzone setting?
288 {
289 x += gamepad_deadzone;
290 }
291 else
292 {
293 x -= gamepad_deadzone;
294 }
295
296 return (!gamepad_leftx_invert) ? x : -x;
297 }
298
getRawLeftYMove()299 int GameController::getRawLeftYMove()
300 {
301 if (!isActive())
302 {
303 return 0;
304 }
305
306 int y = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_LEFTY);
307
308 if (y < gamepad_deadzone && y > -gamepad_deadzone)
309 {
310 return 0;
311 }
312
313 if (y < -gamepad_deadzone)
314 {
315 y += gamepad_deadzone;
316 }
317 else
318 {
319 y -= gamepad_deadzone;
320 }
321
322 return (!gamepad_lefty_invert) ? -y : y;
323 }
324
getRawRightXMove()325 int GameController::getRawRightXMove()
326 {
327 if (!isActive())
328 {
329 return 0;
330 }
331
332 int x = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_RIGHTX);
333
334 if (x < gamepad_deadzone && x > -gamepad_deadzone)
335 {
336 return 0;
337 }
338
339 if (x < -gamepad_deadzone)
340 {
341 x += gamepad_deadzone;
342 }
343 else
344 {
345 x -= gamepad_deadzone;
346 }
347
348 return (!gamepad_rightx_invert) ? x : -x;
349 }
350
getRawRightYMove()351 int GameController::getRawRightYMove()
352 {
353 if (!isActive())
354 {
355 return 0;
356 }
357
358 int y = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_RIGHTY);
359
360 if (y < gamepad_deadzone && y > -gamepad_deadzone)
361 {
362 return 0;
363 }
364
365 if (y < -gamepad_deadzone)
366 {
367 y += gamepad_deadzone;
368 }
369 else
370 {
371 y -= gamepad_deadzone;
372 }
373
374 return (!gamepad_righty_invert) ? y : -y;
375 }
376
377
378
getRawLeftTrigger()379 int GameController::getRawLeftTrigger()
380 {
381 if (!isActive())
382 {
383 return 0;
384 }
385
386 int n = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_TRIGGERLEFT);
387
388 if (n < gamepad_trigger_deadzone)
389 {
390 return 0;
391 }
392
393 n -= gamepad_trigger_deadzone;
394
395 return n;
396 }
397
getRawRightTrigger()398 int GameController::getRawRightTrigger()
399 {
400 if (!isActive())
401 {
402 return 0;
403 }
404
405 int n = SDL_GameControllerGetAxis(sdl_device, SDL_CONTROLLER_AXIS_TRIGGERRIGHT);
406
407 if (n < gamepad_trigger_deadzone)
408 {
409 return 0;
410 }
411
412 n -= gamepad_trigger_deadzone;
413
414 return n;
415 }
416
417
418
getLeftXPercent()419 float GameController::getLeftXPercent()
420 {
421 return (float)getRawLeftXMove() / (float)maxLeftXMove();
422 }
423
getLeftYPercent()424 float GameController::getLeftYPercent()
425 {
426 return (float)getRawLeftYMove() / (float)maxLeftYMove();
427 }
428
getRightXPercent()429 float GameController::getRightXPercent()
430 {
431 return (float)getRawRightXMove() / (float)maxRightXMove();
432 }
433
getRightYPercent()434 float GameController::getRightYPercent()
435 {
436 return (float)getRawRightYMove() / (float)maxRightYMove();
437 }
438
439
getLeftTriggerPercent()440 float GameController::getLeftTriggerPercent()
441 {
442 return (float)getRawLeftTrigger() / (float)maxLeftTrigger();
443 }
444
getRightTriggerPercent()445 float GameController::getRightTriggerPercent()
446 {
447 return (float)getRawRightTrigger() / (float)maxRightTrigger();
448 }
449
450
maxLeftXMove()451 int GameController::maxLeftXMove()
452 {
453 return 32767 - gamepad_deadzone;
454 }
455
maxLeftYMove()456 int GameController::maxLeftYMove()
457 {
458 return 32767 - gamepad_deadzone;
459 }
460
maxRightXMove()461 int GameController::maxRightXMove()
462 {
463 return 32767 - gamepad_deadzone;
464 }
465
maxRightYMove()466 int GameController::maxRightYMove()
467 {
468 return 32767 - gamepad_deadzone; //Ya, it's pretty constant in SDL2.
469 }
470
471
maxLeftTrigger()472 int GameController::maxLeftTrigger()
473 {
474 return 32767 - gamepad_deadzone;
475 }
476
maxRightTrigger()477 int GameController::maxRightTrigger()
478 {
479 return 32767 - gamepad_deadzone;
480 }
481
handleInventoryMovement()482 bool GameController::handleInventoryMovement()
483 {
484 bool dpad_moved = false;
485
486 if (itemMenuOpen)
487 {
488 return false;
489 }
490
491 if ( hotbarHasFocus && !hotbarGamepadControlEnabled() )
492 {
493 hotbarHasFocus = false;
494 }
495
496 if (*inputPressed(joyimpulses[INJOY_DPAD_LEFT]))
497 {
498 if ( hotbarHasFocus && hotbarGamepadControlEnabled() )
499 {
500 //If hotbar is focused and chest, etc, not opened, navigate hotbar.
501 selectHotbarSlot(current_hotbar - 1);
502 warpMouseToSelectedHotbarSlot();
503 }
504 else
505 {
506 //Navigate inventory.
507 select_inventory_slot(selected_inventory_slot_x - 1, selected_inventory_slot_y);
508 }
509 *inputPressed(joyimpulses[INJOY_DPAD_LEFT]) = 0;
510
511 dpad_moved = true;
512 }
513
514 if (*inputPressed(joyimpulses[INJOY_DPAD_RIGHT]))
515 {
516 if ( hotbarHasFocus && hotbarGamepadControlEnabled() )
517 {
518 //If hotbar is focused and chest, etc, not opened, navigate hotbar.
519 selectHotbarSlot(current_hotbar + 1);
520 warpMouseToSelectedHotbarSlot();
521 }
522 else
523 {
524 //Navigate inventory.
525 select_inventory_slot(selected_inventory_slot_x + 1, selected_inventory_slot_y);
526 }
527 *inputPressed(joyimpulses[INJOY_DPAD_RIGHT]) = 0;
528
529 dpad_moved = true;
530 }
531
532 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
533 {
534 if ( hotbarHasFocus && hotbarGamepadControlEnabled() )
535 {
536 //Warp back to top of inventory.
537 hotbarHasFocus = false;
538 float percentage = static_cast<float>(current_hotbar + 1) / static_cast<float>(NUM_HOTBAR_SLOTS);
539 select_inventory_slot((percentage) * INVENTORY_SIZEX - 1, INVENTORY_SIZEY - 1);
540 }
541 else
542 {
543 select_inventory_slot(selected_inventory_slot_x, selected_inventory_slot_y - 1); //Will handle warping to hotbar.
544 }
545 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
546
547 dpad_moved = true;
548 }
549
550 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
551 {
552 if ( hotbarHasFocus && hotbarGamepadControlEnabled() )
553 {
554 //Warp back to bottom of inventory.
555 hotbarHasFocus = false;
556 float percentage = static_cast<float>(current_hotbar + 1) / static_cast<float>(NUM_HOTBAR_SLOTS);
557 select_inventory_slot((percentage) * INVENTORY_SIZEX - 1, 0);
558 }
559 else
560 {
561 select_inventory_slot(selected_inventory_slot_x, selected_inventory_slot_y + 1);
562 }
563 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
564
565 dpad_moved = true;
566 }
567
568 if (dpad_moved)
569 {
570 dpad_moved = false;
571 draw_cursor = false;
572
573 return true;
574 }
575
576 return false;
577 }
578
handleChestMovement()579 bool GameController::handleChestMovement()
580 {
581 bool dpad_moved = false;
582
583 if ( itemMenuOpen )
584 {
585 return false;
586 }
587
588 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
589 {
590 selectChestSlot(selectedChestSlot - 1);
591 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
592
593 dpad_moved = true;
594 }
595
596 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
597 {
598 selectChestSlot(selectedChestSlot + 1);
599 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
600
601 dpad_moved = true;
602 }
603
604 if (dpad_moved)
605 {
606 dpad_moved = false;
607 draw_cursor = false;
608
609 return true;
610 }
611
612 return false;
613 }
614
handleShopMovement()615 bool GameController::handleShopMovement()
616 {
617 bool dpad_moved = false;
618
619 if ( itemMenuOpen )
620 {
621 return false;
622 }
623
624 /*
625 //I would love to just do these, but it just wouldn't work with the way the code is set up.
626 if (*inputPressed(joyimpulses[INJOY_DPAD_LEFT]))
627 {
628 cycleShopCategories(-1);
629 *inputPressed(joyimpulses[INJOY_DPAD_LEFT]) = 0;
630
631 dpad_moved = true;
632 }
633
634 if (*inputPressed(joyimpulses[INJOY_DPAD_RIGHT]))
635 {
636 cycleShopCategories(1);
637 *inputPressed(joyimpulses[INJOY_DPAD_RIGHT]) = 0;
638
639 dpad_moved = true;
640 }*/
641
642 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
643 {
644 selectShopSlot(selectedShopSlot - 1);
645 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
646
647 dpad_moved = true;
648 }
649
650 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
651 {
652 selectShopSlot(selectedShopSlot + 1);
653 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
654
655 dpad_moved = true;
656 }
657
658 if (dpad_moved)
659 {
660 dpad_moved = false;
661 draw_cursor = false;
662
663 return true;
664 }
665
666 return false;
667 }
668
handleIdentifyMovement()669 bool GameController::handleIdentifyMovement()
670 {
671 bool dpad_moved = false;
672
673 if ( itemMenuOpen )
674 {
675 return false;
676 }
677
678 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
679 {
680 selectIdentifySlot(selectedIdentifySlot - 1);
681 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
682
683 dpad_moved = true;
684 }
685
686 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
687 {
688 selectIdentifySlot(selectedIdentifySlot + 1);
689 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
690
691 dpad_moved = true;
692 }
693
694 if (dpad_moved)
695 {
696 dpad_moved = false;
697 draw_cursor = false;
698
699 return true;
700 }
701
702 return false;
703 }
704
handleRemoveCurseMovement()705 bool GameController::handleRemoveCurseMovement()
706 {
707 bool dpad_moved = false;
708
709 if ( itemMenuOpen )
710 {
711 return false;
712 }
713
714 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
715 {
716 selectRemoveCurseSlot(selectedRemoveCurseSlot - 1);
717 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
718
719 dpad_moved = true;
720 }
721
722 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
723 {
724 selectRemoveCurseSlot(selectedRemoveCurseSlot + 1);
725 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
726
727 dpad_moved = true;
728 }
729
730 if (dpad_moved)
731 {
732 dpad_moved = false;
733 draw_cursor = false;
734
735 return true;
736 }
737
738 return false;
739 }
740
handleRepairGUIMovement()741 bool GameController::handleRepairGUIMovement()
742 {
743 bool dpad_moved = false;
744
745 if ( itemMenuOpen )
746 {
747 return false;
748 }
749
750 if ( *inputPressed(joyimpulses[INJOY_DPAD_UP]) )
751 {
752 GenericGUI.selectSlot(GenericGUI.selectedSlot - 1);
753 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
754
755 dpad_moved = true;
756 }
757
758 if ( *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) )
759 {
760 GenericGUI.selectSlot(GenericGUI.selectedSlot + 1);
761 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
762
763 dpad_moved = true;
764 }
765
766 if ( dpad_moved )
767 {
768 dpad_moved = false;
769 draw_cursor = false;
770
771 return true;
772 }
773
774 return false;
775 }
776
handleItemContextMenu(const Item & item)777 bool GameController::handleItemContextMenu(const Item& item)
778 {
779 bool dpad_moved = false;
780
781 if (!itemMenuOpen)
782 {
783 return false;
784 }
785
786 if (*inputPressed(joyimpulses[INJOY_DPAD_UP]))
787 {
788 selectItemMenuSlot(item, itemMenuSelected - 1);
789 *inputPressed(joyimpulses[INJOY_DPAD_UP]) = 0;
790
791 dpad_moved = true;
792 }
793
794 if (*inputPressed(joyimpulses[INJOY_DPAD_DOWN]))
795 {
796 selectItemMenuSlot(item, itemMenuSelected + 1);
797 *inputPressed(joyimpulses[INJOY_DPAD_DOWN]) = 0;
798
799 dpad_moved = true;
800 }
801
802 if (dpad_moved)
803 {
804 dpad_moved = false;
805 draw_cursor = false;
806
807 return true;
808 }
809
810 return false;
811 }
812
813
initGameControllers()814 void initGameControllers()
815 {
816 SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
817
818 int c = 0;
819 bool found = false; //TODO: Bugger this and implement multi-controller support.
820 game_controller = new GameController();
821 for (c = 0; c < SDL_NumJoysticks() && !found; ++c) //TODO: Bugger this and implement multi-controller support on a player-by-player basis.
822 {
823 if (SDL_IsGameController(c) && game_controller->open(c))
824 {
825 printlog("(Device %d successfully initialized as game controller.)\n", c);
826 found = true; //TODO: Bugger this and implement multi-controller support.
827 }
828 else
829 {
830 printlog("Info: device %d is not a game controller! Joysticks are not supported.\n", c);
831 }
832 }
833 if (!found)
834 {
835 printlog("Info: No game controller detected!");
836 }
837 }
838
Player(int in_playernum,bool in_local_host)839 Player::Player(int in_playernum, bool in_local_host)
840 {
841 screen = nullptr;
842 local_host = in_local_host;
843 playernum = in_playernum;
844 entity = nullptr;
845 }
846
~Player()847 Player::~Player()
848 {
849 if (screen)
850 {
851 SDL_FreeSurface(screen);
852 }
853
854 if (entity)
855 {
856 delete entity;
857 }
858 }
859
initIdentifyGUIControllerCode()860 void initIdentifyGUIControllerCode()
861 {
862 if ( identify_items[0] )
863 {
864 selectedIdentifySlot = 0;
865 warpMouseToSelectedIdentifySlot();
866 }
867 else
868 {
869 selectedIdentifySlot = -1;
870 }
871 }
872
initRemoveCurseGUIControllerCode()873 void initRemoveCurseGUIControllerCode()
874 {
875 if ( removecurse_items[0] )
876 {
877 selectedRemoveCurseSlot = 0;
878 warpMouseToSelectedRemoveCurseSlot();
879 }
880 else
881 {
882 selectedRemoveCurseSlot = -1;
883 }
884 }
885
886