]> git.jsancho.org Git - lugaru.git/blob - Source/GameTick.cpp
Removed ctrl+q binding. All OS have their own binding for window closing.
[lugaru.git] / Source / GameTick.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2016 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 // Enable full math definitions
22 #define _USE_MATH_DEFINES
23
24 #if PLATFORM_UNIX
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #else
29 #include <direct.h>
30 #endif
31
32
33 #include <limits>
34 #include <ctime>
35 #include <cmath>
36 #include <dirent.h>
37 #include "Game.h"
38 #include "openal_wrapper.h"
39 #include "Settings.h"
40 #include "Input.h"
41 #include "Animation.h"
42 #include "Awards.h"
43 #include "Menu.h"
44 #include "ConsoleCmds.h"
45
46 #include <algorithm>
47 #include <set>
48
49 using namespace std;
50 using namespace Game;
51
52 // Added more evilness needed for MSVC
53 #ifdef _MSC_VER
54 #define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
55 #define snprintf(buf, size, format, ...) _sprintf_p(buf, size, format)
56 #endif
57
58
59 extern float multiplier;
60 extern XYZ viewer;
61 extern int environment;
62 extern Terrain terrain;
63 extern float screenwidth, screenheight;
64 extern float gravity;
65 extern int detail;
66 extern float texdetail;
67 extern Objects objects;
68 extern int slomo;
69 extern float slomodelay;
70 extern bool floatjump;
71 extern float volume;
72 extern Light light;
73 extern float camerashake;
74 extern float woozy;
75 extern float blackout;
76 extern bool cellophane;
77 extern bool musictoggle;
78 extern int difficulty;
79 extern int bloodtoggle;
80 extern bool invertmouse;
81 extern float windvar;
82 extern float precipdelay;
83 extern XYZ viewerfacing;
84 extern bool ambientsound;
85 extern bool mousejump;
86 extern float viewdistance;
87 extern bool freeze;
88 extern bool keyboardfrozen;
89 extern bool loadingstuff;
90 extern XYZ windvector;
91 extern bool debugmode;
92 static int leveltheme;
93 extern int mainmenu;
94 extern int oldmainmenu;
95 extern bool visibleloading;
96 extern XYZ envsound[30];
97 extern float envsoundvol[30];
98 extern int numenvsounds;
99 extern float envsoundlife[30];
100 extern float usermousesensitivity;
101 extern bool ismotionblur;
102 extern bool showdamagebar; // (des)activate the damage bar
103 extern bool decals;
104 extern bool skyboxtexture;
105 extern float skyboxr;
106 extern float skyboxg;
107 extern float skyboxb;
108 extern float skyboxlightr;
109 extern float skyboxlightg;
110 extern float skyboxlightb;
111 extern float fadestart;
112 extern float slomospeed;
113 extern float slomofreq;
114 extern int tutoriallevel;
115 extern float smoketex;
116 extern float tutorialstagetime;
117 extern int tutorialstage;
118 extern float tutorialmaxtime;
119 extern float tutorialsuccess;
120 extern bool againbonus;
121 extern bool reversaltrain;
122 extern bool canattack;
123 extern bool cananger;
124 extern float damagedealt;
125 extern int maptype;
126 extern int editoractive;
127 extern int editorpathtype;
128
129 extern float hostiletime;
130
131 extern bool gamestarted;
132
133 extern int numhotspots;
134 extern int killhotspot;
135 extern XYZ hotspot[40];
136 extern int hotspottype[40];
137 extern float hotspotsize[40];
138 extern char hotspottext[40][256];
139 extern int currenthotspot;
140
141 extern int hostile;
142
143 extern bool stillloading;
144 extern bool winfreeze;
145
146 extern bool campaign;
147
148 extern void toggleFullscreen();
149
150 class CampaignLevel
151 {
152 private:
153     int width;
154     struct Position {
155         int x, y;
156     };
157 public:
158     std::string mapname;
159     std::string description;
160     int choosenext;
161     /*
162     0 = Immediately load next level at the end of this one.
163     1 = Go back to the world map.
164     2 = Don't bring up the Fiery loading screen. Maybe other things, I've not investigated.
165     */
166     //int numnext; // 0 on final level. As David said: he meant to add story branching, but he eventually hadn't.
167     std::vector<int> nextlevel;
168     Position location;
169     CampaignLevel() : width(10) {
170         choosenext = 1;
171         location.x = 0;
172         location.y = 0;
173     }
174     int getStartX() {
175         return 30 + 120 + location.x * 400 / 512;
176     }
177     int getStartY() {
178         return 30 + 30 + (512 - location.y) * 400 / 512;
179     }
180     int getEndX() {
181         return getStartX() + width;
182     }
183     int getEndY() {
184         return getStartY() + width;
185     }
186     XYZ getCenter() {
187         XYZ center;
188         center.x = getStartX() + width / 2;
189         center.y = getStartY() + width / 2;
190         return center;
191     }
192     int getWidth() {
193         return width;
194     }
195     istream& operator<< (istream& is) {
196         is.ignore(256, ':');
197         is.ignore(256, ':');
198         is.ignore(256, ' ');
199         is >> mapname;
200         is.ignore(256, ':');
201         is >> description;
202         for (size_t pos = description.find('_'); pos != string::npos; pos = description.find('_', pos)) {
203             description.replace(pos, 1, 1, ' ');
204         }
205         is.ignore(256, ':');
206         is >> choosenext;
207         is.ignore(256, ':');
208         int numnext, next;
209         is >> numnext;
210         for (int j = 0; j < numnext; j++) {
211             is.ignore(256, ':');
212             is >> next;
213             nextlevel.push_back(next - 1);
214         }
215         is.ignore(256, ':');
216         is >> location.x;
217         is.ignore(256, ':');
218         is >> location.y;
219         return is;
220     }
221     friend istream& operator>> (istream& is, CampaignLevel& cl) {
222         return cl << is;
223     }
224 };
225
226 bool won = false;
227 int entername = 0;
228 vector<CampaignLevel> campaignlevels;
229 int whichchoice = 0;
230 int actuallevel = 0;
231 bool winhotspot = false;
232 bool windialogue = false;
233 bool realthreat = 0;
234 XYZ cameraloc;
235 float cameradist = 0;
236 bool oldattackkey = 0;
237 int whichlevel = 0;
238 float musicvolume[4] = {};
239 float oldmusicvolume[4] = {};
240 int musicselected = 0;
241
242 const char *rabbitskin[] = {
243     ":Data:Textures:Fur3.jpg",
244     ":Data:Textures:Fur.jpg",
245     ":Data:Textures:Fur2.jpg",
246     ":Data:Textures:Lynx.jpg",
247     ":Data:Textures:Otter.jpg",
248     ":Data:Textures:Opal.jpg",
249     ":Data:Textures:Sable.jpg",
250     ":Data:Textures:Chocolate.jpg",
251     ":Data:Textures:BW2.jpg",
252     ":Data:Textures:WB2.jpg"
253 };
254
255 const char *wolfskin[] = {
256     ":Data:Textures:Wolf.jpg",
257     ":Data:Textures:Darkwolf.jpg",
258     ":Data:Textures:Snowwolf.jpg"
259 };
260
261 const char **creatureskin[] = {rabbitskin, wolfskin};
262
263 #define STATIC_ASSERT(x) extern int s_a_dummy[2 * (!!(x)) - 1];
264 STATIC_ASSERT (rabbittype == 0 && wolftype == 1)
265
266 // utility functions
267
268 // TODO: this is slightly incorrect
269 inline float roughDirection(XYZ vec)
270 {
271     Normalise(&vec);
272     float angle = -asin(-vec.x) * 180 / M_PI;
273     if (vec.z < 0)
274         angle = 180 - angle;
275     return angle;
276 }
277 inline float roughDirectionTo(XYZ start, XYZ end)
278 {
279     return roughDirection(end - start);
280 }
281 inline float pitchOf(XYZ vec)
282 {
283     Normalise(&vec);
284     return -asin(vec.y) * 180 / M_PI;
285 }
286 inline float pitchTo(XYZ start, XYZ end)
287 {
288     return pitchOf(end - start);
289 }
290 inline float sq(float n)
291 {
292     return n * n;
293 }
294 inline float stepTowardf(float from, float to, float by)
295 {
296     if (fabs(from - to) < by)
297         return to;
298     else if (from > to)
299         return from - by;
300     else
301         return from + by;
302 }
303
304 void Game::playdialogueboxsound()
305 {
306     XYZ temppos;
307     temppos = Person::players[participantfocus[whichdialogue][indialogue]]->coords;
308     temppos = temppos - viewer;
309     Normalise(&temppos);
310     temppos += viewer;
311
312     int sound = -1;
313     switch (dialogueboxsound[whichdialogue][indialogue]) {
314     case -6:
315         sound = alarmsound;
316         break;
317     case -4:
318         sound = consolefailsound;
319         break;
320     case -3:
321         sound = consolesuccesssound;
322         break;
323     case -2:
324         sound = firestartsound;
325         break;
326     case -1:
327         sound = fireendsound;
328         break;
329     case 1:
330         sound = rabbitchitter;
331         break;
332     case 2:
333         sound = rabbitchitter2;
334         break;
335     case 3:
336         sound = rabbitpainsound;
337         break;
338     case 4:
339         sound = rabbitpain1sound;
340         break;
341     case 5:
342         sound = rabbitattacksound;
343         break;
344     case 6:
345         sound = rabbitattack2sound;
346         break;
347     case 7:
348         sound = rabbitattack3sound;
349         break;
350     case 8:
351         sound = rabbitattack4sound;
352         break;
353     case 9:
354         sound = growlsound;
355         break;
356     case 10:
357         sound = growl2sound;
358         break;
359     case 11:
360         sound = snarlsound;
361         break;
362     case 12:
363         sound = snarl2sound;
364         break;
365     case 13:
366         sound = barksound;
367         break;
368     case 14:
369         sound = bark2sound;
370         break;
371     case 15:
372         sound = bark3sound;
373         break;
374     case 16:
375         sound = barkgrowlsound;
376         break;
377     default:
378         break;
379     }
380     if (sound != -1)
381         emit_sound_at(sound, temppos);
382 }
383
384 // ================================================================
385
386 int Game::findClosestPlayer()
387 {
388     int closest = -1;
389     float closestdist = std::numeric_limits<float>::max();
390
391     for (unsigned i = 1; i < Person::players.size(); i++) {
392         float distance = distsq(&Person::players[i]->coords, &Person::players[0]->coords);
393         if (distance < closestdist) {
394             closestdist = distance;
395             closest = i;
396         }
397     }
398     return closest;
399 }
400
401 static int findClosestObject()
402 {
403     int closest = -1;
404     float closestdist = std::numeric_limits<float>::max();
405
406     for (int i = 0; i < objects.numobjects; i++) {
407         float distance = distsq(&objects.position[i], &Person::players[0]->coords);
408         if (distance < closestdist) {
409             closestdist = distance;
410             closest = i;
411         }
412     }
413     return closest;
414 }
415
416 static void cmd_dispatch(const string cmd)
417 {
418     int i, n_cmds = sizeof(cmd_names) / sizeof(cmd_names[0]);
419
420     for (i = 0; i < n_cmds; i++)
421         if (cmd.substr(0, cmd.find(' ')) == string(cmd_names[i])) {
422             cout << "|" << cmd.substr(cmd.find(' ') + 1) << "|" << endl;
423             cmd_handlers[i](cmd.substr(cmd.find(' ') + 1).c_str());
424             break;
425         }
426     emit_sound_np(i < n_cmds ? consolesuccesssound : consolefailsound);
427 }
428
429 /********************> Tick() <*****/
430 extern bool save_screenshot(const char * fname);
431 void Screenshot (void)
432 {
433     char filename[1024];
434     time_t t = time(NULL);
435     struct tm *tme = localtime(&t);
436     sprintf(filename, "Screenshots/Screenshot-%04d%02d%02d-%02d%02d%02d.png",
437             tme->tm_year + 1900, tme->tm_mon + 1, tme->tm_mday, tme->tm_hour, tme->tm_min, tme->tm_sec);
438
439 #if defined(_WIN32)
440     mkdir("Screenshots");
441 #endif
442
443     save_screenshot(filename);
444 }
445
446 void Game::SetUpLighting()
447 {
448     if (environment == snowyenvironment)
449         light.setColors(.65, .65, .7, .4, .4, .44);
450     if (environment == desertenvironment)
451         light.setColors(.95, .95, .95, .4, .35, .3);
452     if (environment == grassyenvironment)
453         light.setColors(.95, .95, 1, .4, .4, .44);
454     if (!skyboxtexture)
455         light.setColors(1, 1, 1, .4, .4, .4);
456     float average;
457     average = (skyboxlightr + skyboxlightg + skyboxlightb) / 3;
458     light.color[0] *= (skyboxlightr + average) / 2;
459     light.color[1] *= (skyboxlightg + average) / 2;
460     light.color[2] *= (skyboxlightb + average) / 2;
461     light.ambient[0] *= (skyboxlightr + average) / 2;
462     light.ambient[1] *= (skyboxlightg + average) / 2;
463     light.ambient[2] *= (skyboxlightb + average) / 2;
464 }
465
466 int findPathDist(int start, int end)
467 {
468     int smallestcount, count, connected;
469     int last, last2, last3, last4;
470     int closest;
471
472     smallestcount = 1000;
473     for (int i = 0; i < 50; i++) {
474         count = 0;
475         last = start;
476         last2 = -1;
477         last3 = -1;
478         last4 = -1;
479         while (last != end && count < 30) {
480             closest = -1;
481             for (int j = 0; j < numpathpoints; j++) {
482                 if (j != last && j != last2 && j != last3 && j != last4) {
483                     connected = 0;
484                     if (numpathpointconnect[j])
485                         for (int k = 0; k < numpathpointconnect[j]; k++) {
486                             if (pathpointconnect[j][k] == last)connected = 1;
487                         }
488                     if (!connected)
489                         if (numpathpointconnect[last])
490                             for (int k = 0; k < numpathpointconnect[last]; k++) {
491                                 if (pathpointconnect[last][k] == j)connected = 1;
492                             }
493                     if (connected)
494                         if (closest == -1 || Random() % 2 == 0) {
495                             closest = j;
496                         }
497                 }
498             }
499             last4 = last3;
500             last3 = last2;
501             last2 = last;
502             last = closest;
503             count++;
504         }
505         if (count < smallestcount)
506             smallestcount = count;
507     }
508     return smallestcount;
509 }
510
511 int Game::checkcollide(XYZ startpoint, XYZ endpoint)
512 {
513     static XYZ colpoint, colviewer, coltarget;
514     static float minx, minz, maxx, maxz, miny, maxy;
515
516     minx = min(startpoint.x, endpoint.x) - 1;
517     miny = min(startpoint.y, endpoint.y) - 1;
518     minz = min(startpoint.z, endpoint.z) - 1;
519     maxx = max(startpoint.x, endpoint.x) + 1;
520     maxy = max(startpoint.y, endpoint.y) + 1;
521     maxz = max(startpoint.z, endpoint.z) + 1;
522
523     for (int i = 0; i < objects.numobjects; i++) {
524         if (     objects.position[i].x > minx - objects.model[i].boundingsphereradius &&
525                  objects.position[i].x < maxx + objects.model[i].boundingsphereradius &&
526                  objects.position[i].y > miny - objects.model[i].boundingsphereradius &&
527                  objects.position[i].y < maxy + objects.model[i].boundingsphereradius &&
528                  objects.position[i].z > minz - objects.model[i].boundingsphereradius &&
529                  objects.position[i].z < maxz + objects.model[i].boundingsphereradius) {
530             if (     objects.type[i] != treeleavestype &&
531                      objects.type[i] != bushtype &&
532                      objects.type[i] != firetype) {
533                 colviewer = startpoint;
534                 coltarget = endpoint;
535                 if (objects.model[i].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
536                     return i;
537             }
538         }
539     }
540
541     return -1;
542 }
543
544 int Game::checkcollide(XYZ startpoint, XYZ endpoint, int what)
545 {
546     static XYZ colpoint, colviewer, coltarget;
547     static float minx, minz, maxx, maxz, miny, maxy;
548     static int i; //FIXME: see below
549
550     minx = min(startpoint.x, endpoint.x) - 1;
551     miny = min(startpoint.y, endpoint.y) - 1;
552     minz = min(startpoint.z, endpoint.z) - 1;
553     maxx = max(startpoint.x, endpoint.x) + 1;
554     maxy = max(startpoint.y, endpoint.y) + 1;
555     maxz = max(startpoint.z, endpoint.z) + 1;
556
557     if (what != 1000) {
558         if (     objects.position[what].x > minx - objects.model[what].boundingsphereradius &&
559                  objects.position[what].x < maxx + objects.model[what].boundingsphereradius &&
560                  objects.position[what].y > miny - objects.model[what].boundingsphereradius &&
561                  objects.position[what].y < maxy + objects.model[what].boundingsphereradius &&
562                  objects.position[what].z > minz - objects.model[what].boundingsphereradius &&
563                  objects.position[what].z < maxz + objects.model[what].boundingsphereradius) {
564             if (     objects.type[what] != treeleavestype &&
565                      objects.type[what] != bushtype &&
566                      objects.type[what] != firetype) {
567                 colviewer = startpoint;
568                 coltarget = endpoint;
569                 //FIXME: i/what
570                 if (objects.model[what].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[what], &objects.yaw[what]) != -1)
571                     return i;
572             }
573         }
574     }
575
576     if (what == 1000)
577         if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1)
578             return 1000;
579
580     return -1;
581 }
582
583 void Setenvironment(int which)
584 {
585     LOGFUNC;
586
587     LOG(" Setting environment...");
588
589     float temptexdetail;
590     environment = which;
591
592     pause_sound(stream_snowtheme);
593     pause_sound(stream_grasstheme);
594     pause_sound(stream_deserttheme);
595     pause_sound(stream_wind);
596     pause_sound(stream_desertambient);
597
598
599     if (environment == snowyenvironment) {
600         windvector = 0;
601         windvector.z = 3;
602         if (ambientsound)
603             emit_stream_np(stream_wind);
604
605         objects.treetextureptr.load(":Data:Textures:snowtree.png", 0, 1);
606         objects.bushtextureptr.load(":Data:Textures:bushsnow.png", 0, 1);
607         objects.rocktextureptr.load(":Data:Textures:bouldersnow.jpg", 1, 0);
608         objects.boxtextureptr.load(":Data:Textures:snowbox.jpg", 1, 0);
609
610         footstepsound = footstepsn1;
611         footstepsound2 = footstepsn2;
612         footstepsound3 = footstepst1;
613         footstepsound4 = footstepst2;
614
615         terraintexture.load(":Data:Textures:snow.jpg", 1, 0);
616         terraintexture2.load(":Data:Textures:rock.jpg", 1, 0);
617
618
619         temptexdetail = texdetail;
620         if (texdetail > 1)
621             texdetail = 4;
622         skybox->load(   ":Data:Textures:Skybox(snow):Front.jpg",
623                         ":Data:Textures:Skybox(snow):Left.jpg",
624                         ":Data:Textures:Skybox(snow):Back.jpg",
625                         ":Data:Textures:Skybox(snow):Right.jpg",
626                         ":Data:Textures:Skybox(snow):Up.jpg",
627                         ":Data:Textures:Skybox(snow):Down.jpg");
628
629
630
631
632         texdetail = temptexdetail;
633     } else if (environment == desertenvironment) {
634         windvector = 0;
635         windvector.z = 2;
636         objects.treetextureptr.load(":Data:Textures:deserttree.png", 0, 1);
637         objects.bushtextureptr.load(":Data:Textures:bushdesert.png", 0, 1);
638         objects.rocktextureptr.load(":Data:Textures:boulderdesert.jpg", 1, 0);
639         objects.boxtextureptr.load(":Data:Textures:desertbox.jpg", 1, 0);
640
641
642         if (ambientsound)
643             emit_stream_np(stream_desertambient);
644
645         footstepsound = footstepsn1;
646         footstepsound2 = footstepsn2;
647         footstepsound3 = footstepsn1;
648         footstepsound4 = footstepsn2;
649
650         terraintexture.load(":Data:Textures:sand.jpg", 1, 0);
651         terraintexture2.load(":Data:Textures:sandslope.jpg", 1, 0);
652
653
654         temptexdetail = texdetail;
655         if (texdetail > 1)
656             texdetail = 4;
657         skybox->load(   ":Data:Textures:Skybox(sand):Front.jpg",
658                         ":Data:Textures:Skybox(sand):Left.jpg",
659                         ":Data:Textures:Skybox(sand):Back.jpg",
660                         ":Data:Textures:Skybox(sand):Right.jpg",
661                         ":Data:Textures:Skybox(sand):Up.jpg",
662                         ":Data:Textures:Skybox(sand):Down.jpg");
663
664
665
666
667         texdetail = temptexdetail;
668     } else if (environment == grassyenvironment) {
669         windvector = 0;
670         windvector.z = 2;
671         objects.treetextureptr.load(":Data:Textures:tree.png", 0, 1);
672         objects.bushtextureptr.load(":Data:Textures:bush.png", 0, 1);
673         objects.rocktextureptr.load(":Data:Textures:boulder.jpg", 1, 0);
674         objects.boxtextureptr.load(":Data:Textures:grassbox.jpg", 1, 0);
675
676         if (ambientsound)
677             emit_stream_np(stream_wind, 100.);
678
679         footstepsound = footstepgr1;
680         footstepsound2 = footstepgr2;
681         footstepsound3 = footstepst1;
682         footstepsound4 = footstepst2;
683
684         terraintexture.load(":Data:Textures:grassdirt.jpg", 1, 0);
685         terraintexture2.load(":Data:Textures:mossrock.jpg", 1, 0);
686
687
688         temptexdetail = texdetail;
689         if (texdetail > 1)
690             texdetail = 4;
691         skybox->load(   ":Data:Textures:Skybox(grass):Front.jpg",
692                         ":Data:Textures:Skybox(grass):Left.jpg",
693                         ":Data:Textures:Skybox(grass):Back.jpg",
694                         ":Data:Textures:Skybox(grass):Right.jpg",
695                         ":Data:Textures:Skybox(grass):Up.jpg",
696                         ":Data:Textures:Skybox(grass):Down.jpg");
697
698
699
700         texdetail = temptexdetail;
701     }
702     temptexdetail = texdetail;
703     texdetail = 1;
704     terrain.load(":Data:Textures:heightmap.png");
705
706     texdetail = temptexdetail;
707 }
708
709 void LoadCampaign()
710 {
711     if (!accountactive)
712         return;
713     ifstream ipstream(ConvertFileName((":Data:Campaigns:" + accountactive->getCurrentCampaign() + ".txt").c_str()));
714     if (!ipstream.good()) {
715         if (accountactive->getCurrentCampaign() == "main") {
716             cerr << "Could not found main campaign!" << endl;
717             return;
718         }
719         cerr << "Could not found campaign \"" << accountactive->getCurrentCampaign() << "\", falling back to main." << endl;
720         accountactive->setCurrentCampaign("main");
721         return LoadCampaign();
722     }
723     ipstream.ignore(256, ':');
724     int numlevels;
725     ipstream >> numlevels;
726     campaignlevels.clear();
727     for (int i = 0; i < numlevels; i++) {
728         CampaignLevel cl;
729         ipstream >> cl;
730         campaignlevels.push_back(cl);
731     }
732     ipstream.close();
733
734     ifstream test(ConvertFileName((":Data:Textures:" + accountactive->getCurrentCampaign() + ":World.png").c_str()));
735     if (test.good()) {
736         Mainmenuitems[7].load((":Data:Textures:" + accountactive->getCurrentCampaign() + ":World.png").c_str(), 0, 0);
737     } else {
738         Mainmenuitems[7].load(":Data:Textures:World.png", 0, 0);
739     }
740
741     if (accountactive->getCampaignChoicesMade() == 0) {
742         accountactive->setCampaignScore(0);
743         accountactive->resetFasttime();
744     }
745 }
746
747 vector<string> ListCampaigns()
748 {
749     DIR *campaigns = opendir(ConvertFileName(":Data:Campaigns"));
750     struct dirent *campaign = NULL;
751     if (!campaigns) {
752         perror("Problem while loading campaigns");
753         cerr << "campaign folder was : " << ConvertFileName(":Data:Campaigns") << endl;
754         exit(EXIT_FAILURE);
755     }
756     vector<string> campaignNames;
757     while ((campaign = readdir(campaigns)) != NULL) {
758         string name(campaign->d_name);
759         if (name.length() < 5)
760             continue;
761         if (!name.compare(name.length() - 4, 4, ".txt")) {
762             campaignNames.push_back(name.substr(0, name.length() - 4));
763         }
764     }
765     closedir(campaigns);
766     return campaignNames;
767 }
768
769 void Game::Loadlevel(int which)
770 {
771     stealthloading = 0;
772     whichlevel = which;
773
774     if (which == -1) {
775         tutoriallevel = -1;
776         Loadlevel("tutorial");
777     } else if (which >= 0 && which <= 15) {
778         char buf[32];
779         snprintf(buf, 32, "map%d", which + 1); // challenges
780         Loadlevel(buf);
781     } else
782         Loadlevel("mapsave");
783 }
784
785 void Game::Loadlevel(const char *name)
786 {
787     int indemo; // FIXME this should be removed
788     int templength;
789     float lamefloat;
790     static const char *pfx = ":Data:Maps:";
791     char *buf;
792
793     float headprop, legprop, armprop, bodyprop;
794
795     LOGFUNC;
796
797     LOG(std::string("Loading level...") + name);
798
799     if (!gameon)
800         visibleloading = 1;
801     if (stealthloading)
802         visibleloading = 0;
803     if (!stillloading)
804         loadtime = 0;
805     gamestarted = 1;
806
807     numenvsounds = 0;
808
809     if (tutoriallevel != -1)
810         tutoriallevel = 0;
811     else
812         tutoriallevel = 1;
813
814     if (tutoriallevel == 1)
815         tutorialstage = 0;
816     if (tutorialstage == 0) {
817         tutorialstagetime = 0;
818         tutorialmaxtime = 1;
819     }
820     loadingstuff = 1;
821     pause_sound(whooshsound);
822     pause_sound(stream_firesound);
823
824     // Change the map filename into something that is os specific
825     buf = (char*) alloca(strlen(pfx) + strlen(name) + 1);
826     sprintf(buf, "%s%s", pfx, name);
827     const char *FixedFN = ConvertFileName(buf);
828
829     int mapvers;
830     FILE *tfile;
831     tfile = fopen( FixedFN, "rb" );
832     if (tfile) {
833         pause_sound(stream_firesound);
834         scoreadded = 0;
835         windialogue = false;
836         hostiletime = 0;
837         won = 0;
838
839         animation[bounceidleanim].Load((char *)"Idle", middleheight, neutral);
840
841         numdialogues = 0;
842
843         for (int i = 0; i < 20; i++)
844             dialoguegonethrough[i] = 0;
845
846         indialogue = -1;
847         cameramode = 0;
848
849         damagedealt = 0;
850         damagetaken = 0;
851
852         if (accountactive)
853             difficulty = accountactive->getDifficulty();
854
855         numhotspots = 0;
856         currenthotspot = -1;
857         bonustime = 1;
858
859         skyboxtexture = 1;
860         skyboxr = 1;
861         skyboxg = 1;
862         skyboxb = 1;
863
864         freeze = 0;
865         winfreeze = 0;
866
867         for (int i = 0; i < 100; i++)
868             bonusnum[i] = 0;
869
870         numfalls = 0;
871         numflipfail = 0;
872         numseen = 0;
873         numstaffattack = 0;
874         numswordattack = 0;
875         numknifeattack = 0;
876         numunarmedattack = 0;
877         numescaped = 0;
878         numflipped = 0;
879         numwallflipped = 0;
880         numthrowkill = 0;
881         numafterkill = 0;
882         numreversals = 0;
883         numattacks = 0;
884         maxalarmed = 0;
885         numresponded = 0;
886
887         bonustotal = startbonustotal;
888         bonus = 0;
889         gameon = 1;
890         changedelay = 0;
891         if (console) {
892             emit_sound_np(consolesuccesssound);
893             freeze = 0;
894             console = false;
895         }
896
897         if (!stealthloading) {
898             terrain.numdecals = 0;
899             Sprite::deleteSprites();
900             for (int i = 0; i < objects.numobjects; i++)
901                 objects.model[i].numdecals = 0;
902
903             int j = objects.numobjects;
904             for (int i = 0; i < j; i++) {
905                 objects.DeleteObject(0);
906                 if (visibleloading)
907                     LoadingScreen();
908             }
909
910             for (int i = 0; i < subdivision; i++)
911                 for (int j = 0; j < subdivision; j++)
912                     terrain.patchobjectnum[i][j] = 0;
913             if (visibleloading)
914                 LoadingScreen();
915         }
916
917         weapons.clear();
918
919         funpackf(tfile, "Bi", &mapvers);
920         if (mapvers >= 15)
921             funpackf(tfile, "Bi", &indemo);
922         else
923             indemo = 0;
924         if (mapvers >= 5)
925             funpackf(tfile, "Bi", &maptype);
926         else
927             maptype = mapkilleveryone;
928         if (mapvers >= 6)
929             funpackf(tfile, "Bi", &hostile);
930         else
931             hostile = 1;
932         if (mapvers >= 4)
933             funpackf(tfile, "Bf Bf", &viewdistance, &fadestart);
934         else {
935             viewdistance = 100;
936             fadestart = .6;
937         }
938         if (mapvers >= 2)
939             funpackf(tfile, "Bb Bf Bf Bf", &skyboxtexture, &skyboxr, &skyboxg, &skyboxb);
940         else {
941             skyboxtexture = 1;
942             skyboxr = 1;
943             skyboxg = 1;
944             skyboxb = 1;
945         }
946         if (mapvers >= 10)
947             funpackf(tfile, "Bf Bf Bf", &skyboxlightr, &skyboxlightg, &skyboxlightb);
948         else {
949             skyboxlightr = skyboxr;
950             skyboxlightg = skyboxg;
951             skyboxlightb = skyboxb;
952         }
953         if (!stealthloading)
954             funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &Person::players[0]->coords.x, &Person::players[0]->coords.y, &Person::players[0]->coords.z, &Person::players[0]->yaw, &Person::players[0]->targetyaw, &Person::players[0]->num_weapons);
955         if (stealthloading)
956             funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &lamefloat, &lamefloat, &lamefloat, &lamefloat, &lamefloat, &Person::players[0]->num_weapons);
957         Person::players[0]->originalcoords = Person::players[0]->coords;
958         if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
959             for (int j = 0; j < Person::players[0]->num_weapons; j++) {
960                 Person::players[0]->weaponids[j] = weapons.size();
961                 int type;
962                 funpackf(tfile, "Bi", &type);
963                 weapons.push_back(Weapon(type, 0));
964             }
965
966         if (visibleloading)
967             LoadingScreen();
968
969         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->armorhead, &Person::players[0]->armorhigh, &Person::players[0]->armorlow);
970         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->protectionhead, &Person::players[0]->protectionhigh, &Person::players[0]->protectionlow);
971         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->metalhead, &Person::players[0]->metalhigh, &Person::players[0]->metallow);
972         funpackf(tfile, "Bf Bf", &Person::players[0]->power, &Person::players[0]->speedmult);
973
974         funpackf(tfile, "Bi", &Person::players[0]->numclothes);
975
976         if (mapvers >= 9)
977             funpackf(tfile, "Bi Bi", &Person::players[0]->whichskin, &Person::players[0]->creature);
978         else {
979             Person::players[0]->whichskin = 0;
980             Person::players[0]->creature = rabbittype;
981         }
982
983         Person::players[0]->lastattack = -1;
984         Person::players[0]->lastattack2 = -1;
985         Person::players[0]->lastattack3 = -1;
986
987         //dialogues
988         if (mapvers >= 8) {
989             funpackf(tfile, "Bi", &numdialogues);
990             for (int k = 0; k < numdialogues; k++) {
991                 funpackf(tfile, "Bi", &numdialogueboxes[k]);
992                 funpackf(tfile, "Bi", &dialoguetype[k]);
993                 for (int l = 0; l < 10; l++) {
994                     funpackf(tfile, "Bf Bf Bf", &participantlocation[k][l].x, &participantlocation[k][l].y, &participantlocation[k][l].z);
995                     funpackf(tfile, "Bf", &participantyaw[k][l]);
996                 }
997                 for (int l = 0; l < numdialogueboxes[k]; l++) {
998                     funpackf(tfile, "Bi", &dialogueboxlocation[k][l]);
999                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][0]);
1000                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][1]);
1001                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][2]);
1002                     funpackf(tfile, "Bi", &dialogueboxsound[k][l]);
1003
1004                     funpackf(tfile, "Bi", &templength);
1005                     if (templength > 128 || templength <= 0)
1006                         templength = 128;
1007                     int m;
1008                     for (m = 0; m < templength; m++) {
1009                         funpackf(tfile, "Bb", &dialoguetext[k][l][m]);
1010                         if (dialoguetext[k][l][m] == '\0')
1011                             break;
1012                     }
1013                     dialoguetext[k][l][m] = 0;
1014
1015                     funpackf(tfile, "Bi", &templength);
1016                     if (templength > 64 || templength <= 0)
1017                         templength = 64;
1018                     for (m = 0; m < templength; m++) {
1019                         funpackf(tfile, "Bb", &dialoguename[k][l][m]);
1020                         if (dialoguename[k][l][m] == '\0')
1021                             break;
1022                     }
1023                     dialoguename[k][l][m] = 0;
1024                     funpackf(tfile, "Bf Bf Bf", &dialoguecamera[k][l].x, &dialoguecamera[k][l].y, &dialoguecamera[k][l].z);
1025                     funpackf(tfile, "Bi", &participantfocus[k][l]);
1026                     funpackf(tfile, "Bi", &participantaction[k][l]);
1027
1028                     for (m = 0; m < 10; m++)
1029                         funpackf(tfile, "Bf Bf Bf", &participantfacing[k][l][m].x, &participantfacing[k][l][m].y, &participantfacing[k][l][m].z);
1030
1031                     funpackf(tfile, "Bf Bf", &dialoguecamerayaw[k][l], &dialoguecamerapitch[k][l]);
1032                 }
1033             }
1034         } else
1035             numdialogues = 0;
1036
1037         for (int k = 0; k < Person::players[0]->numclothes; k++) {
1038             funpackf(tfile, "Bi", &templength);
1039             for (int l = 0; l < templength; l++)
1040                 funpackf(tfile, "Bb", &Person::players[0]->clothes[k][l]);
1041             Person::players[0]->clothes[k][templength] = '\0';
1042             funpackf(tfile, "Bf Bf Bf", &Person::players[0]->clothestintr[k], &Person::players[0]->clothestintg[k], &Person::players[0]->clothestintb[k]);
1043         }
1044
1045         funpackf(tfile, "Bi", &environment);
1046
1047         funpackf(tfile, "Bi", &objects.numobjects);
1048         for (int i = 0; i < objects.numobjects; i++) {
1049             funpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", &objects.type[i], &objects.yaw[i], &objects.pitch[i], &objects.position[i].x, &objects.position[i].y, &objects.position[i].z, &objects.scale[i]);
1050             if (objects.type[i] == treeleavestype)
1051                 objects.scale[i] = objects.scale[i - 1];
1052         }
1053
1054         if (mapvers >= 7) {
1055             funpackf(tfile, "Bi", &numhotspots);
1056             for (int i = 0; i < numhotspots; i++) {
1057                 funpackf(tfile, "Bi Bf Bf Bf Bf", &hotspottype[i], &hotspotsize[i], &hotspot[i].x, &hotspot[i].y, &hotspot[i].z);
1058                 funpackf(tfile, "Bi", &templength);
1059                 if (templength)
1060                     for (int l = 0; l < templength; l++)
1061                         funpackf(tfile, "Bb", &hotspottext[i][l]);
1062                 hotspottext[i][templength] = '\0';
1063                 if (hotspottype[i] == -111)
1064                     indemo = 1;
1065             }
1066         } else
1067             numhotspots = 0;
1068
1069         if (visibleloading)
1070             LoadingScreen();
1071
1072         if (!stealthloading) {
1073             objects.center = 0;
1074             for (int i = 0; i < objects.numobjects; i++)
1075                 objects.center += objects.position[i];
1076             objects.center /= objects.numobjects;
1077
1078
1079             if (visibleloading)
1080                 LoadingScreen();
1081
1082             float maxdistance = 0;
1083             float tempdist;
1084             for (int i = 0; i < objects.numobjects; i++) {
1085                 tempdist = distsq(&objects.center, &objects.position[i]);
1086                 if (tempdist > maxdistance) {
1087                     maxdistance = tempdist;
1088                 }
1089             }
1090             objects.radius = fast_sqrt(maxdistance);
1091         }
1092
1093         if (visibleloading)
1094             LoadingScreen();
1095
1096         int numplayers;
1097         funpackf(tfile, "Bi", &numplayers);
1098         int howmanyremoved = 0;
1099         bool removeanother = 0;
1100         if (numplayers > maxplayers) {
1101             cout << "Warning: this level contains more players than allowed" << endl;
1102         }
1103         if (numplayers > 1) {
1104             for (int i = 1; i < numplayers; i++) {
1105                 Person::players.push_back(shared_ptr<Person>(new Person()));
1106                 if (visibleloading)
1107                     LoadingScreen();
1108                 removeanother = 0;
1109
1110                 funpackf(tfile, "Bi Bi Bf Bf Bf Bi", &Person::players[i - howmanyremoved]->whichskin, &Person::players[i - howmanyremoved]->creature, &Person::players[i - howmanyremoved]->coords.x, &Person::players[i - howmanyremoved]->coords.y, &Person::players[i - howmanyremoved]->coords.z, &Person::players[i - howmanyremoved]->num_weapons);
1111                 if (mapvers >= 5)
1112                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->howactive);
1113                 else
1114                     Person::players[i - howmanyremoved]->howactive = typeactive;
1115                 if (mapvers >= 3)
1116                     funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->scale);
1117                 else
1118                     Person::players[i - howmanyremoved]->scale = -1;
1119                 if (mapvers >= 11)
1120                     funpackf(tfile, "Bb", &Person::players[i - howmanyremoved]->immobile);
1121                 else
1122                     Person::players[i - howmanyremoved]->immobile = 0;
1123                 if (mapvers >= 12)
1124                     funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->yaw);
1125                 else
1126                     Person::players[i - howmanyremoved]->yaw = 0;
1127                 Person::players[i - howmanyremoved]->targetyaw = Person::players[i - howmanyremoved]->yaw;
1128                 if (Person::players[i - howmanyremoved]->num_weapons < 0 || Person::players[i - howmanyremoved]->num_weapons > 5) {
1129                     removeanother = 1;
1130                     howmanyremoved++;
1131                 }
1132                 if (!removeanother) {
1133                     if (Person::players[i - howmanyremoved]->num_weapons > 0 && Person::players[i - howmanyremoved]->num_weapons < 5) {
1134                         for (int j = 0; j < Person::players[i - howmanyremoved]->num_weapons; j++) {
1135                             Person::players[i - howmanyremoved]->weaponids[j] = weapons.size();
1136                             int type;
1137                             funpackf(tfile, "Bi", &type);
1138                             weapons.push_back(Weapon(type, i));
1139                         }
1140                     }
1141                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->numwaypoints);
1142                     for (int j = 0; j < Person::players[i - howmanyremoved]->numwaypoints; j++) {
1143                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].x);
1144                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].y);
1145                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].z);
1146                         if (mapvers >= 5)
1147                             funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->waypointtype[j]);
1148                         else
1149                             Person::players[i - howmanyremoved]->waypointtype[j] = wpkeepwalking;
1150                     }
1151
1152                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->waypoint);
1153                     if (Person::players[i - howmanyremoved]->waypoint > Person::players[i - howmanyremoved]->numwaypoints - 1)
1154                         Person::players[i - howmanyremoved]->waypoint = 0;
1155
1156                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->armorhead, &Person::players[i - howmanyremoved]->armorhigh, &Person::players[i - howmanyremoved]->armorlow);
1157                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->protectionhead, &Person::players[i - howmanyremoved]->protectionhigh, &Person::players[i - howmanyremoved]->protectionlow);
1158                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->metalhead, &Person::players[i - howmanyremoved]->metalhigh, &Person::players[i - howmanyremoved]->metallow);
1159                     funpackf(tfile, "Bf Bf", &Person::players[i - howmanyremoved]->power, &Person::players[i - howmanyremoved]->speedmult);
1160
1161                     if (mapvers >= 4)
1162                         funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
1163                     else {
1164                         headprop = 1;
1165                         bodyprop = 1;
1166                         armprop = 1;
1167                         legprop = 1;
1168                     }
1169                     if (Person::players[i - howmanyremoved]->creature == wolftype) {
1170                         Person::players[i - howmanyremoved]->proportionhead = 1.1 * headprop;
1171                         Person::players[i - howmanyremoved]->proportionbody = 1.1 * bodyprop;
1172                         Person::players[i - howmanyremoved]->proportionarms = 1.1 * armprop;
1173                         Person::players[i - howmanyremoved]->proportionlegs = 1.1 * legprop;
1174                     }
1175
1176                     if (Person::players[i - howmanyremoved]->creature == rabbittype) {
1177                         Person::players[i - howmanyremoved]->proportionhead = 1.2 * headprop;
1178                         Person::players[i - howmanyremoved]->proportionbody = 1.05 * bodyprop;
1179                         Person::players[i - howmanyremoved]->proportionarms = 1.00 * armprop;
1180                         Person::players[i - howmanyremoved]->proportionlegs = 1.1 * legprop;
1181                         Person::players[i - howmanyremoved]->proportionlegs.y = 1.05 * legprop;
1182                     }
1183
1184                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->numclothes);
1185                     if (Person::players[i - howmanyremoved]->numclothes) {
1186                         for (int k = 0; k < Person::players[i - howmanyremoved]->numclothes; k++) {
1187                             int templength;
1188                             funpackf(tfile, "Bi", &templength);
1189                             for (int l = 0; l < templength; l++)
1190                                 funpackf(tfile, "Bb", &Person::players[i - howmanyremoved]->clothes[k][l]);
1191                             Person::players[i - howmanyremoved]->clothes[k][templength] = '\0';
1192                             funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->clothestintr[k], &Person::players[i - howmanyremoved]->clothestintg[k], &Person::players[i - howmanyremoved]->clothestintb[k]);
1193                         }
1194                     }
1195                 }
1196             }
1197         }
1198         if (visibleloading)
1199             LoadingScreen();
1200
1201         numplayers -= howmanyremoved;
1202         Person::players.resize(numplayers);
1203
1204         funpackf(tfile, "Bi", &numpathpoints);
1205         if (numpathpoints > 30 || numpathpoints < 0)
1206             numpathpoints = 0;
1207         for (int j = 0; j < numpathpoints; j++) {
1208             funpackf(tfile, "Bf Bf Bf Bi", &pathpoint[j].x, &pathpoint[j].y, &pathpoint[j].z, &numpathpointconnect[j]);
1209             for (int k = 0; k < numpathpointconnect[j]; k++) {
1210                 funpackf(tfile, "Bi", &pathpointconnect[j][k]);
1211             }
1212         }
1213         if (visibleloading)
1214             LoadingScreen();
1215
1216         funpackf(tfile, "Bf Bf Bf Bf", &mapcenter.x, &mapcenter.y, &mapcenter.z, &mapradius);
1217
1218         SetUpLighting();
1219         if (environment != oldenvironment)
1220             Setenvironment(environment);
1221         oldenvironment = environment;
1222
1223         if (!stealthloading) {
1224             int j = objects.numobjects;
1225             objects.numobjects = 0;
1226             for (int i = 0; i < j; i++) {
1227                 objects.MakeObject(objects.type[i], objects.position[i], objects.yaw[i], objects.pitch[i], objects.scale[i]);
1228                 if (visibleloading)
1229                     LoadingScreen();
1230             }
1231
1232             terrain.DoShadows();
1233             if (visibleloading)
1234                 LoadingScreen();
1235             objects.DoShadows();
1236             if (visibleloading)
1237                 LoadingScreen();
1238         }
1239
1240         fclose(tfile);
1241
1242         for (unsigned i = 0; i < Person::players.size(); i++) {
1243             if (visibleloading)
1244                 LoadingScreen();
1245             Person::players[i]->burnt = 0;
1246             Person::players[i]->bled = 0;
1247             Person::players[i]->onfire = 0;
1248             if (i == 0 || Person::players[i]->scale < 0)
1249                 Person::players[i]->scale = .2;
1250             Person::players[i]->skeleton.free = 0;
1251             Person::players[i]->skeleton.id = i;
1252             if (i == 0 && mapvers < 9)
1253                 Person::players[i]->creature = rabbittype;
1254             if (Person::players[i]->creature != wolftype) {
1255                 Person::players[i]->skeleton.Load(
1256                     (char *)":Data:Skeleton:Basic Figure",
1257                     (char *)":Data:Skeleton:Basic Figurelow",
1258                     (char *)":Data:Skeleton:Rabbitbelt",
1259                     (char *)":Data:Models:Body.solid",
1260                     (char *)":Data:Models:Body2.solid",
1261                     (char *)":Data:Models:Body3.solid",
1262                     (char *)":Data:Models:Body4.solid",
1263                     (char *)":Data:Models:Body5.solid",
1264                     (char *)":Data:Models:Body6.solid",
1265                     (char *)":Data:Models:Body7.solid",
1266                     (char *)":Data:Models:Bodylow.solid",
1267                     (char *)":Data:Models:Belt.solid", 0);
1268             } else {
1269                 if (Person::players[i]->creature != wolftype) {
1270                     Person::players[i]->skeleton.Load(
1271                         (char *)":Data:Skeleton:Basic Figure",
1272                         (char *)":Data:Skeleton:Basic Figurelow",
1273                         (char *)":Data:Skeleton:Rabbitbelt",
1274                         (char *)":Data:Models:Body.solid",
1275                         (char *)":Data:Models:Body2.solid",
1276                         (char *)":Data:Models:Body3.solid",
1277                         (char *)":Data:Models:Body4.solid",
1278                         (char *)":Data:Models:Body5.solid",
1279                         (char *)":Data:Models:Body6.solid",
1280                         (char *)":Data:Models:Body7.solid",
1281                         (char *)":Data:Models:Bodylow.solid",
1282                         (char *)":Data:Models:Belt.solid", 1);
1283                     Person::players[i]->skeleton.drawmodelclothes.textureptr.load(":Data:Textures:Belt.png", 1, 1);
1284                 }
1285                 if (Person::players[i]->creature == wolftype) {
1286                     Person::players[i]->skeleton.Load(
1287                         (char *)":Data:Skeleton:Basic Figure Wolf",
1288                         (char *)":Data:Skeleton:Basic Figure Wolf Low",
1289                         (char *)":Data:Skeleton:Rabbitbelt",
1290                         (char *)":Data:Models:Wolf.solid",
1291                         (char *)":Data:Models:Wolf2.solid",
1292                         (char *)":Data:Models:Wolf3.solid",
1293                         (char *)":Data:Models:Wolf4.solid",
1294                         (char *)":Data:Models:Wolf5.solid",
1295                         (char *)":Data:Models:Wolf6.solid",
1296                         (char *)":Data:Models:Wolf7.solid",
1297                         (char *)":Data:Models:Wolflow.solid",
1298                         (char *)":Data:Models:Belt.solid", 0);
1299                 }
1300             }
1301
1302             Person::players[i]->skeleton.drawmodel.textureptr.load(creatureskin[Person::players[i]->creature][Person::players[i]->whichskin], 1, &Person::players[i]->skeleton.skinText[0], &Person::players[i]->skeleton.skinsize);
1303
1304             Person::players[i]->addClothes();
1305
1306             Person::players[i]->animCurrent = bounceidleanim;
1307             Person::players[i]->animTarget = bounceidleanim;
1308             Person::players[i]->frameCurrent = 0;
1309             Person::players[i]->frameTarget = 1;
1310             Person::players[i]->target = 0;
1311             Person::players[i]->speed = 1 + (float)(Random() % 100) / 1000;
1312             if (difficulty == 0)
1313                 Person::players[i]->speed -= .2;
1314             if (difficulty == 1)
1315                 Person::players[i]->speed -= .1;
1316
1317             Person::players[i]->velocity = 0;
1318             Person::players[i]->oldcoords = Person::players[i]->coords;
1319             Person::players[i]->realoldcoords = Person::players[i]->coords;
1320
1321             Person::players[i]->id = i;
1322             Person::players[i]->skeleton.id = i;
1323             Person::players[i]->updatedelay = 0;
1324             Person::players[i]->normalsupdatedelay = 0;
1325
1326             Person::players[i]->aitype = passivetype;
1327             Person::players[i]->madskills = 0;
1328
1329             if (i == 0) {
1330                 Person::players[i]->proportionhead = 1.2;
1331                 Person::players[i]->proportionbody = 1.05;
1332                 Person::players[i]->proportionarms = 1.00;
1333                 Person::players[i]->proportionlegs = 1.1;
1334                 Person::players[i]->proportionlegs.y = 1.05;
1335             }
1336             Person::players[i]->headless = 0;
1337             Person::players[i]->currentoffset = 0;
1338             Person::players[i]->targetoffset = 0;
1339
1340             Person::players[i]->damagetolerance = 200;
1341
1342             if (Person::players[i]->creature == wolftype) {
1343                 if (i == 0 || Person::players[i]->scale < 0)
1344                     Person::players[i]->scale = .23;
1345                 Person::players[i]->damagetolerance = 300;
1346             }
1347
1348             if (visibleloading)
1349                 LoadingScreen();
1350             if (cellophane) {
1351                 Person::players[i]->proportionhead.z = 0;
1352                 Person::players[i]->proportionbody.z = 0;
1353                 Person::players[i]->proportionarms.z = 0;
1354                 Person::players[i]->proportionlegs.z = 0;
1355             }
1356
1357             Person::players[i]->tempanimation.Load((char *)"Tempanim", 0, 0);
1358
1359             Person::players[i]->headmorphness = 0;
1360             Person::players[i]->targetheadmorphness = 1;
1361             Person::players[i]->headmorphstart = 0;
1362             Person::players[i]->headmorphend = 0;
1363
1364             Person::players[i]->pausetime = 0;
1365
1366             Person::players[i]->dead = 0;
1367             Person::players[i]->jumppower = 5;
1368             Person::players[i]->damage = 0;
1369             Person::players[i]->permanentdamage = 0;
1370             Person::players[i]->superpermanentdamage = 0;
1371
1372             Person::players[i]->forwardkeydown = 0;
1373             Person::players[i]->leftkeydown = 0;
1374             Person::players[i]->backkeydown = 0;
1375             Person::players[i]->rightkeydown = 0;
1376             Person::players[i]->jumpkeydown = 0;
1377             Person::players[i]->crouchkeydown = 0;
1378             Person::players[i]->throwkeydown = 0;
1379
1380             Person::players[i]->collided = -10;
1381             Person::players[i]->loaded = 1;
1382             Person::players[i]->bloodloss = 0;
1383             Person::players[i]->weaponactive = -1;
1384             Person::players[i]->weaponstuck = -1;
1385             Person::players[i]->bleeding = 0;
1386             Person::players[i]->deathbleeding = 0;
1387             Person::players[i]->stunned = 0;
1388             Person::players[i]->hasvictim = 0;
1389             Person::players[i]->wentforweapon = 0;
1390         }
1391
1392         Person::players[0]->aitype = playercontrolled;
1393         Person::players[0]->weaponactive = -1;
1394
1395         if (difficulty == 1) {
1396             Person::players[0]->power = 1 / .9;
1397             Person::players[0]->damagetolerance = 250;
1398         } else if (difficulty == 0) {
1399             Person::players[0]->power = 1 / .8;
1400             Person::players[0]->damagetolerance = 300;
1401             Person::players[0]->armorhead *= 1.5;
1402             Person::players[0]->armorhigh *= 1.5;
1403             Person::players[0]->armorlow *= 1.5;
1404         }
1405
1406         cameraloc = Person::players[0]->coords;
1407         cameraloc.y += 5;
1408         yaw = Person::players[0]->yaw;
1409
1410         hawkcoords = Person::players[0]->coords;
1411         hawkcoords.y += 30;
1412
1413         if (visibleloading)
1414             LoadingScreen();
1415
1416         LOG("Starting background music...");
1417
1418         OPENAL_StopSound(OPENAL_ALL);
1419         if (ambientsound) {
1420             if (environment == snowyenvironment) {
1421                 emit_stream_np(stream_wind);
1422             } else if (environment == desertenvironment) {
1423                 emit_stream_np(stream_desertambient);
1424             } else if (environment == grassyenvironment) {
1425                 emit_stream_np(stream_wind, 100.);
1426             }
1427         }
1428         oldmusicvolume[0] = 0;
1429         oldmusicvolume[1] = 0;
1430         oldmusicvolume[2] = 0;
1431         oldmusicvolume[3] = 0;
1432
1433         if (!firstload)
1434             firstload = 1;
1435     } else {
1436         perror("Problem");
1437     }
1438     leveltime = 0;
1439     loadingstuff = 0;
1440     visibleloading = 0;
1441 }
1442
1443 void doTutorial()
1444 {
1445     if (tutorialstagetime > tutorialmaxtime) {
1446         tutorialstage++;
1447         tutorialsuccess = 0;
1448         if (tutorialstage <= 1) {
1449             canattack = 0;
1450             cananger = 0;
1451             reversaltrain = 0;
1452         }
1453         switch (tutorialstage) {
1454         case 1:
1455             tutorialmaxtime = 5;
1456             break;
1457         case 2:
1458             tutorialmaxtime = 2;
1459             break;
1460         case 3:
1461             tutorialmaxtime = 600;
1462             break;
1463         case 4:
1464             tutorialmaxtime = 1000;
1465             break;
1466         case 5:
1467             tutorialmaxtime = 600;
1468             break;
1469         case 6:
1470             tutorialmaxtime = 600;
1471             break;
1472         case 7:
1473             tutorialmaxtime = 600;
1474             break;
1475         case 8:
1476             tutorialmaxtime = 600;
1477             break;
1478         case 9:
1479             tutorialmaxtime = 600;
1480             break;
1481         case 10:
1482             tutorialmaxtime = 2;
1483             break;
1484         case 11:
1485             tutorialmaxtime = 1000;
1486             break;
1487         case 12:
1488             tutorialmaxtime = 1000;
1489             break;
1490         case 13:
1491             tutorialmaxtime = 2;
1492             break;
1493         case 14: {
1494             tutorialmaxtime = 3;
1495
1496             XYZ temp, temp2;
1497
1498             temp.x = 1011;
1499             temp.y = 84;
1500             temp.z = 491;
1501             temp2.x = 1025;
1502             temp2.y = 75;
1503             temp2.z = 447;
1504
1505             Person::players[1]->coords = (temp + temp2) / 2;
1506
1507             emit_sound_at(fireendsound, Person::players[1]->coords);
1508
1509             for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
1510                 if (Random() % 2 == 0) {
1511                     if (!Person::players[1]->skeleton.free)
1512                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
1513                     if (Person::players[1]->skeleton.free)
1514                         temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
1515                     if (!Person::players[1]->skeleton.free)
1516                         temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords;
1517                     if (Person::players[1]->skeleton.free)
1518                         temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
1519                     Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
1520                 }
1521             }
1522         }
1523         break;
1524         case 15:
1525             tutorialmaxtime = 500;
1526             break;
1527         case 16:
1528             tutorialmaxtime = 500;
1529             break;
1530         case 17:
1531             tutorialmaxtime = 500;
1532             break;
1533         case 18:
1534             tutorialmaxtime = 500;
1535             break;
1536         case 19:
1537             tutorialstage = 20;
1538             break;
1539         case 20:
1540             tutorialmaxtime = 500;
1541             break;
1542         case 21:
1543             tutorialmaxtime = 500;
1544             if (bonus == cannon) {
1545                 bonus = Slicebonus;
1546                 againbonus = 1;
1547             } else
1548                 againbonus = 0;
1549             break;
1550         case 22:
1551             tutorialmaxtime = 500;
1552             break;
1553         case 23:
1554             tutorialmaxtime = 500;
1555             break;
1556         case 24:
1557             tutorialmaxtime = 500;
1558             break;
1559         case 25:
1560             tutorialmaxtime = 500;
1561             break;
1562         case 26:
1563             tutorialmaxtime = 2;
1564             break;
1565         case 27:
1566             tutorialmaxtime = 4;
1567             reversaltrain = 1;
1568             cananger = 1;
1569             Person::players[1]->aitype = attacktypecutoff;
1570             break;
1571         case 28:
1572             tutorialmaxtime = 400;
1573             break;
1574         case 29:
1575             tutorialmaxtime = 400;
1576             Person::players[0]->escapednum = 0;
1577             break;
1578         case 30:
1579             tutorialmaxtime = 4;
1580             reversaltrain = 0;
1581             cananger = 0;
1582             Person::players[1]->aitype = passivetype;
1583             break;
1584         case 31:
1585             tutorialmaxtime = 13;
1586             break;
1587         case 32:
1588             tutorialmaxtime = 8;
1589             break;
1590         case 33:
1591             tutorialmaxtime = 400;
1592             cananger = 1;
1593             canattack = 1;
1594             Person::players[1]->aitype = attacktypecutoff;
1595             break;
1596         case 34:
1597             tutorialmaxtime = 400;
1598             break;
1599         case 35:
1600             tutorialmaxtime = 400;
1601             break;
1602         case 36:
1603             tutorialmaxtime = 2;
1604             reversaltrain = 0;
1605             cananger = 0;
1606             Person::players[1]->aitype = passivetype;
1607             break;
1608         case 37:
1609             damagedealt = 0;
1610             damagetaken = 0;
1611             tutorialmaxtime = 50;
1612             cananger = 1;
1613             canattack = 1;
1614             Person::players[1]->aitype = attacktypecutoff;
1615             break;
1616         case 38:
1617             tutorialmaxtime = 4;
1618             canattack = 0;
1619             cananger = 0;
1620             Person::players[1]->aitype = passivetype;
1621             break;
1622         case 39: {
1623             XYZ temp, temp2;
1624
1625             temp.x = 1011;
1626             temp.y = 84;
1627             temp.z = 491;
1628             temp2.x = 1025;
1629             temp2.y = 75;
1630             temp2.z = 447;
1631
1632             Weapon w(knife, -1);
1633             w.position = (temp + temp2) / 2;
1634             w.tippoint = (temp + temp2) / 2;
1635
1636             w.velocity = 0.1;
1637             w.tipvelocity = 0.1;
1638             w.missed = 1;
1639             w.hitsomething = 0;
1640             w.freetime = 0;
1641             w.firstfree = 1;
1642             w.physics = 1;
1643
1644             weapons.push_back(w);
1645         }
1646         break;
1647         case 40:
1648             tutorialmaxtime = 300;
1649             break;
1650         case 41:
1651             tutorialmaxtime = 300;
1652             break;
1653         case 42:
1654             tutorialmaxtime = 8;
1655             break;
1656         case 43:
1657             tutorialmaxtime = 300;
1658             break;
1659         case 44:
1660             weapons[0].owner = 1;
1661             Person::players[0]->weaponactive = -1;
1662             Person::players[0]->num_weapons = 0;
1663             Person::players[1]->weaponactive = 0;
1664             Person::players[1]->num_weapons = 1;
1665             Person::players[1]->weaponids[0] = 0;
1666
1667             cananger = 1;
1668             canattack = 1;
1669             Person::players[1]->aitype = attacktypecutoff;
1670
1671             tutorialmaxtime = 300;
1672             break;
1673         case 45:
1674             weapons[0].owner = 1;
1675             Person::players[0]->weaponactive = -1;
1676             Person::players[0]->num_weapons = 0;
1677             Person::players[1]->weaponactive = 0;
1678             Person::players[1]->num_weapons = 1;
1679             Person::players[1]->weaponids[0] = 0;
1680
1681             tutorialmaxtime = 300;
1682             break;
1683         case 46:
1684             weapons[0].owner = 1;
1685             Person::players[0]->weaponactive = -1;
1686             Person::players[0]->num_weapons = 0;
1687             Person::players[1]->weaponactive = 0;
1688             Person::players[1]->num_weapons = 1;
1689             Person::players[1]->weaponids[0] = 0;
1690
1691             weapons[0].setType(sword);
1692
1693             tutorialmaxtime = 300;
1694             break;
1695         case 47: {
1696             tutorialmaxtime = 10;
1697
1698             XYZ temp, temp2;
1699
1700             temp.x = 1011;
1701             temp.y = 84;
1702             temp.z = 491;
1703             temp2.x = 1025;
1704             temp2.y = 75;
1705             temp2.z = 447;
1706
1707             Weapon w(sword, -1);
1708             w.position = (temp + temp2) / 2;
1709             w.tippoint = (temp + temp2) / 2;
1710
1711             w.velocity = 0.1;
1712             w.tipvelocity = 0.1;
1713             w.missed = 1;
1714             w.hitsomething = 0;
1715             w.freetime = 0;
1716             w.firstfree = 1;
1717             w.physics = 1;
1718
1719             weapons.push_back(w);
1720
1721             weapons[0].owner = 1;
1722             weapons[1].owner = 0;
1723             Person::players[0]->weaponactive = 0;
1724             Person::players[0]->num_weapons = 1;
1725             Person::players[0]->weaponids[0] = 1;
1726             Person::players[1]->weaponactive = 0;
1727             Person::players[1]->num_weapons = 1;
1728             Person::players[1]->weaponids[0] = 0;
1729
1730         }
1731         break;
1732         case 48:
1733             canattack = 0;
1734             cananger = 0;
1735             Person::players[1]->aitype = passivetype;
1736
1737             tutorialmaxtime = 15;
1738
1739             weapons[0].owner = 1;
1740             weapons[1].owner = 0;
1741             Person::players[0]->weaponactive = 0;
1742             Person::players[0]->num_weapons = 1;
1743             Person::players[0]->weaponids[0] = 1;
1744             Person::players[1]->weaponactive = 0;
1745             Person::players[1]->num_weapons = 1;
1746             Person::players[1]->weaponids[0] = 0;
1747
1748             if (Person::players[0]->weaponactive != -1)
1749                 weapons[Person::players[0]->weaponids[Person::players[0]->weaponactive]].setType(staff);
1750             else
1751                 weapons[0].setType(staff);
1752             break;
1753         case 49:
1754             canattack = 0;
1755             cananger = 0;
1756             Person::players[1]->aitype = passivetype;
1757
1758             tutorialmaxtime = 200;
1759
1760             weapons[1].position = 1000;
1761             weapons[1].tippoint = 1000;
1762
1763             weapons[0].setType(knife);
1764
1765             weapons[0].owner = 0;
1766             Person::players[1]->weaponactive = -1;
1767             Person::players[1]->num_weapons = 0;
1768             Person::players[0]->weaponactive = 0;
1769             Person::players[0]->num_weapons = 1;
1770             Person::players[0]->weaponids[0] = 0;
1771
1772             break;
1773         case 50: {
1774             tutorialmaxtime = 8;
1775
1776             XYZ temp, temp2;
1777             emit_sound_at(fireendsound, Person::players[1]->coords);
1778
1779             for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
1780                 if (Random() % 2 == 0) {
1781                     if (!Person::players[1]->skeleton.free)
1782                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
1783                     if (Person::players[1]->skeleton.free)
1784                         temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
1785                     if (!Person::players[1]->skeleton.free)
1786                         temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords;
1787                     if (Person::players[1]->skeleton.free)
1788                         temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
1789                     Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
1790                 }
1791             }
1792
1793             Person::players[1]->num_weapons = 0;
1794             Person::players[1]->weaponstuck = -1;
1795             Person::players[1]->weaponactive = -1;
1796
1797             weapons.clear();
1798         }
1799         break;
1800         case 51:
1801             tutorialmaxtime = 80000;
1802             break;
1803         default:
1804             break;
1805         }
1806         if (tutorialstage <= 51)
1807             tutorialstagetime = 0;
1808     }
1809
1810     //Tutorial success
1811     if (tutorialstagetime < tutorialmaxtime - 3) {
1812         switch (tutorialstage) {
1813         case 3:
1814             if (deltah || deltav)
1815                 tutorialsuccess += multiplier;
1816             break;
1817         case 4:
1818             if (Person::players[0]->forwardkeydown || Person::players[0]->backkeydown || Person::players[0]->leftkeydown || Person::players[0]->rightkeydown)
1819                 tutorialsuccess += multiplier;
1820             break;
1821         case 5:
1822             if (Person::players[0]->jumpkeydown)
1823                 tutorialsuccess = 1;
1824             break;
1825         case 6:
1826             if (Person::players[0]->isCrouch())
1827                 tutorialsuccess = 1;
1828             break;
1829         case 7:
1830             if (Person::players[0]->animTarget == rollanim)
1831                 tutorialsuccess = 1;
1832             break;
1833         case 8:
1834             if (Person::players[0]->animTarget == sneakanim)
1835                 tutorialsuccess += multiplier;
1836             break;
1837         case 9:
1838             if (Person::players[0]->animTarget == rabbitrunninganim || Person::players[0]->animTarget == wolfrunninganim)
1839                 tutorialsuccess += multiplier;
1840             break;
1841         case 11:
1842             if (Person::players[0]->isWallJump())
1843                 tutorialsuccess = 1;
1844             break;
1845         case 12:
1846             if (Person::players[0]->animTarget == flipanim)
1847                 tutorialsuccess = 1;
1848             break;
1849         case 15:
1850             if (Person::players[0]->animTarget == upunchanim || Person::players[0]->animTarget == winduppunchanim)
1851                 tutorialsuccess = 1;
1852             break;
1853         case 16:
1854             if (Person::players[0]->animTarget == winduppunchanim)
1855                 tutorialsuccess = 1;
1856             break;
1857         case 17:
1858             if (Person::players[0]->animTarget == spinkickanim)
1859                 tutorialsuccess = 1;
1860             break;
1861         case 18:
1862             if (Person::players[0]->animTarget == sweepanim)
1863                 tutorialsuccess = 1;
1864             break;
1865         case 19:
1866             if (Person::players[0]->animTarget == dropkickanim)
1867                 tutorialsuccess = 1;
1868             break;
1869         case 20:
1870             if (Person::players[0]->animTarget == rabbitkickanim)
1871                 tutorialsuccess = 1;
1872             break;
1873         case 21:
1874             if (bonus == cannon)
1875                 tutorialsuccess = 1;
1876             break;
1877         case 22:
1878             if (bonus == spinecrusher)
1879                 tutorialsuccess = 1;
1880             break;
1881         case 23:
1882             if (Person::players[0]->animTarget == walljumprightkickanim || Person::players[0]->animTarget == walljumpleftkickanim)
1883                 tutorialsuccess = 1;
1884             break;
1885         case 24:
1886             if (Person::players[0]->animTarget == rabbittacklinganim)
1887                 tutorialsuccess = 1;
1888             break;
1889         case 25:
1890             if (Person::players[0]->animTarget == backhandspringanim)
1891                 tutorialsuccess = 1;
1892             break;
1893         case 28:
1894             if (animation[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
1895                 tutorialsuccess = 1;
1896             break;
1897         case 29:
1898             if (Person::players[0]->escapednum == 2) {
1899                 tutorialsuccess = 1;
1900                 reversaltrain = 0;
1901                 cananger = 0;
1902                 Person::players[1]->aitype = passivetype;
1903             }
1904             break;
1905         case 33:
1906             if (animation[Person::players[0]->animTarget].attack == reversal)
1907                 tutorialsuccess = 1;
1908             break;
1909         case 34:
1910             if (animation[Person::players[0]->animTarget].attack == reversal)
1911                 tutorialsuccess = 1;
1912             break;
1913         case 35:
1914             if (animation[Person::players[0]->animTarget].attack == reversal) {
1915                 tutorialsuccess = 1;
1916                 reversaltrain = 0;
1917                 cananger = 0;
1918                 Person::players[1]->aitype = passivetype;
1919             }
1920             break;
1921         case 40:
1922             if (Person::players[0]->num_weapons > 0)
1923                 tutorialsuccess = 1;
1924             break;
1925         case 41:
1926             if (Person::players[0]->weaponactive == -1 && Person::players[0]->num_weapons > 0)
1927                 tutorialsuccess = 1;
1928             break;
1929         case 43:
1930             if (Person::players[0]->animTarget == knifeslashstartanim)
1931                 tutorialsuccess = 1;
1932             break;
1933         case 44:
1934             if (animation[Person::players[0]->animTarget].attack == reversal)
1935                 tutorialsuccess = 1;
1936             break;
1937         case 45:
1938             if (animation[Person::players[0]->animTarget].attack == reversal)
1939                 tutorialsuccess = 1;
1940             break;
1941         case 46:
1942             if (animation[Person::players[0]->animTarget].attack == reversal)
1943                 tutorialsuccess = 1;
1944             break;
1945         case 49:
1946             if (Person::players[1]->weaponstuck != -1)
1947                 tutorialsuccess = 1;
1948             break;
1949         default:
1950             break;
1951         }
1952         if (tutorialsuccess >= 1)
1953             tutorialstagetime = tutorialmaxtime - 3;
1954
1955
1956         if (tutorialstagetime == tutorialmaxtime - 3) {
1957             emit_sound_np(consolesuccesssound);
1958         }
1959
1960         if (tutorialsuccess >= 1) {
1961             if (tutorialstage == 34 || tutorialstage == 35)
1962                 tutorialstagetime = tutorialmaxtime - 1;
1963         }
1964     }
1965
1966     if (tutorialstage < 14 || tutorialstage >= 50) {
1967         Person::players[1]->coords.y = 300;
1968         Person::players[1]->velocity = 0;
1969     }
1970 }
1971
1972 void doDebugKeys()
1973 {
1974     float headprop, bodyprop, armprop, legprop;
1975     if (debugmode) {
1976         if (Input::isKeyPressed(SDL_SCANCODE_H)) {
1977             Person::players[0]->damagetolerance = 200000;
1978             Person::players[0]->damage = 0;
1979             Person::players[0]->burnt = 0;
1980             Person::players[0]->permanentdamage = 0;
1981             Person::players[0]->superpermanentdamage = 0;
1982         }
1983
1984         if (Input::isKeyPressed(SDL_SCANCODE_J)) {
1985             environment++;
1986             if (environment > 2)
1987                 environment = 0;
1988             Setenvironment(environment);
1989         }
1990
1991         if (Input::isKeyPressed(SDL_SCANCODE_C)) {
1992             cameramode = !cameramode;
1993         }
1994
1995         if (Input::isKeyPressed(SDL_SCANCODE_X) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
1996             if (Person::players[0]->num_weapons > 0) {
1997                 if (weapons[Person::players[0]->weaponids[0]].getType() == sword)
1998                     weapons[Person::players[0]->weaponids[0]].setType(staff);
1999                 else if (weapons[Person::players[0]->weaponids[0]].getType() == staff)
2000                     weapons[Person::players[0]->weaponids[0]].setType(knife);
2001                 else
2002                     weapons[Person::players[0]->weaponids[0]].setType(sword);
2003             }
2004         }
2005
2006         if (Input::isKeyPressed(SDL_SCANCODE_X) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2007             int closest = findClosestPlayer();
2008             if (closest >= 0) {
2009                 if (Person::players[closest]->num_weapons) {
2010                     if (weapons[Person::players[closest]->weaponids[0]].getType() == sword)
2011                         weapons[Person::players[closest]->weaponids[0]].setType(staff);
2012                     else if (weapons[Person::players[closest]->weaponids[0]].getType() == staff)
2013                         weapons[Person::players[closest]->weaponids[0]].setType(knife);
2014                     else
2015                         weapons[Person::players[closest]->weaponids[0]].setType(sword);
2016                 }
2017                 if (!Person::players[closest]->num_weapons) {
2018                     Person::players[closest]->weaponids[0] = weapons.size();
2019
2020                     weapons.push_back(Weapon(knife, closest));
2021
2022                     Person::players[closest]->num_weapons = 1;
2023                 }
2024             }
2025         }
2026
2027         if (Input::isKeyDown(SDL_SCANCODE_U)) {
2028             int closest = findClosestPlayer();
2029             if (closest >= 0) {
2030                 Person::players[closest]->yaw += multiplier * 50;
2031                 Person::players[closest]->targetyaw = Person::players[closest]->yaw;
2032             }
2033         }
2034
2035
2036         if (Input::isKeyPressed(SDL_SCANCODE_O) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2037             int closest = findClosestPlayer();
2038             if (Input::isKeyDown(SDL_SCANCODE_LCTRL))
2039                 closest = 0;
2040
2041             if (closest >= 0) {
2042                 Person::players[closest]->whichskin++;
2043                 if (Person::players[closest]->whichskin > 9)
2044                     Person::players[closest]->whichskin = 0;
2045                 if (Person::players[closest]->whichskin > 2 && Person::players[closest]->creature == wolftype)
2046                     Person::players[closest]->whichskin = 0;
2047
2048                 Person::players[closest]->skeleton.drawmodel.textureptr.load(creatureskin[Person::players[closest]->creature][Person::players[closest]->whichskin], 1,
2049                         &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
2050             }
2051
2052             Person::players[closest]->addClothes();
2053         }
2054
2055         if (Input::isKeyPressed(SDL_SCANCODE_O) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2056             int closest = findClosestPlayer();
2057             if (closest >= 0) {
2058                 if (Person::players[closest]->creature == wolftype) {
2059                     headprop = Person::players[closest]->proportionhead.x / 1.1;
2060                     bodyprop = Person::players[closest]->proportionbody.x / 1.1;
2061                     armprop = Person::players[closest]->proportionarms.x / 1.1;
2062                     legprop = Person::players[closest]->proportionlegs.x / 1.1;
2063                 }
2064
2065                 if (Person::players[closest]->creature == rabbittype) {
2066                     headprop = Person::players[closest]->proportionhead.x / 1.2;
2067                     bodyprop = Person::players[closest]->proportionbody.x / 1.05;
2068                     armprop = Person::players[closest]->proportionarms.x / 1.00;
2069                     legprop = Person::players[closest]->proportionlegs.x / 1.1;
2070                 }
2071
2072
2073                 if (Person::players[closest]->creature == rabbittype) {
2074                     Person::players[closest]->skeleton.id = closest;
2075                     Person::players[closest]->skeleton.Load((char *)":Data:Skeleton:Basic Figure Wolf", (char *)":Data:Skeleton:Basic Figure Wolf Low", (char *)":Data:Skeleton:Rabbitbelt", (char *)":Data:Models:Wolf.solid", (char *)":Data:Models:Wolf2.solid", (char *)":Data:Models:Wolf3.solid", (char *)":Data:Models:Wolf4.solid", (char *)":Data:Models:Wolf5.solid", (char *)":Data:Models:Wolf6.solid", (char *)":Data:Models:Wolf7.solid", (char *)":Data:Models:Wolflow.solid", (char *)":Data:Models:Belt.solid", 0);
2076                     Person::players[closest]->skeleton.drawmodel.textureptr.load(":Data:Textures:Wolf.jpg", 1, &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
2077                     Person::players[closest]->whichskin = 0;
2078                     Person::players[closest]->creature = wolftype;
2079
2080                     Person::players[closest]->proportionhead = 1.1;
2081                     Person::players[closest]->proportionbody = 1.1;
2082                     Person::players[closest]->proportionarms = 1.1;
2083                     Person::players[closest]->proportionlegs = 1.1;
2084                     Person::players[closest]->proportionlegs.y = 1.1;
2085                     Person::players[closest]->scale = .23 * 5 * Person::players[0]->scale;
2086
2087                     Person::players[closest]->damagetolerance = 300;
2088                 } else {
2089                     Person::players[closest]->skeleton.id = closest;
2090                     Person::players[closest]->skeleton.Load((char *)":Data:Skeleton:Basic Figure", (char *)":Data:Skeleton:Basic Figurelow", (char *)":Data:Skeleton:Rabbitbelt", (char *)":Data:Models:Body.solid", (char *)":Data:Models:Body2.solid", (char *)":Data:Models:Body3.solid", (char *)":Data:Models:Body4.solid", (char *)":Data:Models:Body5.solid", (char *)":Data:Models:Body6.solid", (char *)":Data:Models:Body7.solid", (char *)":Data:Models:Bodylow.solid", (char *)":Data:Models:Belt.solid", 1);
2091                     Person::players[closest]->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur3.jpg", 1, &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
2092                     Person::players[closest]->whichskin = 0;
2093                     Person::players[closest]->creature = rabbittype;
2094
2095                     Person::players[closest]->proportionhead = 1.2;
2096                     Person::players[closest]->proportionbody = 1.05;
2097                     Person::players[closest]->proportionarms = 1.00;
2098                     Person::players[closest]->proportionlegs = 1.1;
2099                     Person::players[closest]->proportionlegs.y = 1.05;
2100                     Person::players[closest]->scale = .2 * 5 * Person::players[0]->scale;
2101
2102                     Person::players[closest]->damagetolerance = 200;
2103                 }
2104
2105                 if (Person::players[closest]->creature == wolftype) {
2106                     Person::players[closest]->proportionhead = 1.1 * headprop;
2107                     Person::players[closest]->proportionbody = 1.1 * bodyprop;
2108                     Person::players[closest]->proportionarms = 1.1 * armprop;
2109                     Person::players[closest]->proportionlegs = 1.1 * legprop;
2110                 }
2111
2112                 if (Person::players[closest]->creature == rabbittype) {
2113                     Person::players[closest]->proportionhead = 1.2 * headprop;
2114                     Person::players[closest]->proportionbody = 1.05 * bodyprop;
2115                     Person::players[closest]->proportionarms = 1.00 * armprop;
2116                     Person::players[closest]->proportionlegs = 1.1 * legprop;
2117                     Person::players[closest]->proportionlegs.y = 1.05 * legprop;
2118                 }
2119
2120             }
2121         }
2122
2123         if (Input::isKeyPressed(SDL_SCANCODE_B) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2124             slomo = 1 - slomo;
2125             slomodelay = 1000;
2126         }
2127
2128
2129         if (((Input::isKeyPressed(SDL_SCANCODE_I) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)))) {
2130             int closest = -1;
2131             float closestdist = std::numeric_limits<float>::max();
2132
2133             for (unsigned i = 1; i < Person::players.size(); i++) {
2134                 float distance = distsq(&Person::players[i]->coords, &Person::players[0]->coords);
2135                 if (!Person::players[i]->headless)
2136                     if (distance < closestdist) {
2137                         closestdist = distance;
2138                         closest = i;
2139                     }
2140             }
2141
2142             XYZ flatfacing2, flatvelocity2;
2143             XYZ blah;
2144             if (closest != -1 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
2145                 blah = Person::players[closest]->coords;
2146                 XYZ headspurtdirection;
2147                 //int i = Person::players[closest]->skeleton.jointlabels[head];
2148                 Joint& headjoint = Person::players[closest]->joint(head);
2149                 for (int k = 0; k < Person::players[closest]->skeleton.num_joints; k++) {
2150                     if (!Person::players[closest]->skeleton.free)
2151                         flatvelocity2 = Person::players[closest]->velocity;
2152                     if (Person::players[closest]->skeleton.free)
2153                         flatvelocity2 = headjoint.velocity;
2154                     if (!Person::players[closest]->skeleton.free)
2155                         flatfacing2 = DoRotation(DoRotation(DoRotation(headjoint.position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
2156                     if (Person::players[closest]->skeleton.free)
2157                         flatfacing2 = headjoint.position * Person::players[closest]->scale + Person::players[closest]->coords;
2158                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
2159                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
2160                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
2161                     headspurtdirection = headjoint.position - Person::players[closest]->jointPos(neck);
2162                     Normalise(&headspurtdirection);
2163                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, .6, 1);
2164                     flatvelocity2 += headspurtdirection * 8;
2165                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 / 2, 1, 1, 1, .16, 1);
2166                 }
2167                 Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
2168
2169                 emit_sound_at(splattersound, blah);
2170                 emit_sound_at(breaksound2, blah, 100.);
2171
2172                 if (Person::players[closest]->skeleton.free == 2)
2173                     Person::players[closest]->skeleton.free = 0;
2174                 Person::players[closest]->RagDoll(0);
2175                 Person::players[closest]->dead = 2;
2176                 Person::players[closest]->headless = 1;
2177                 Person::players[closest]->DoBloodBig(3, 165);
2178
2179                 camerashake += .3;
2180             }
2181         }
2182
2183         if (((Input::isKeyPressed(SDL_SCANCODE_I) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)))) {
2184             int closest = findClosestPlayer();
2185             XYZ flatfacing2, flatvelocity2;
2186             XYZ blah;
2187             if (closest >= 0 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
2188                 blah = Person::players[closest]->coords;
2189                 emit_sound_at(splattersound, blah);
2190                 emit_sound_at(breaksound2, blah);
2191
2192                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
2193                     if (!Person::players[closest]->skeleton.free)
2194                         flatvelocity2 = Person::players[closest]->velocity;
2195                     if (Person::players[closest]->skeleton.free)
2196                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
2197                     if (!Person::players[closest]->skeleton.free)
2198                         flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
2199                     if (Person::players[closest]->skeleton.free)
2200                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
2201                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
2202                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
2203                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
2204                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
2205                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .3, 1);
2206                     Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
2207                 }
2208
2209                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
2210                     if (!Person::players[closest]->skeleton.free)
2211                         flatvelocity2 = Person::players[closest]->velocity;
2212                     if (Person::players[closest]->skeleton.free)
2213                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
2214                     if (!Person::players[closest]->skeleton.free)
2215                         flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
2216                     if (Person::players[closest]->skeleton.free)
2217                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
2218                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
2219                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
2220                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
2221                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
2222                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
2223                 }
2224
2225                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
2226                     if (!Person::players[closest]->skeleton.free)
2227                         flatvelocity2 = Person::players[closest]->velocity;
2228                     if (Person::players[closest]->skeleton.free)
2229                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
2230                     if (!Person::players[closest]->skeleton.free)
2231                         flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
2232                     if (Person::players[closest]->skeleton.free)
2233                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
2234                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
2235                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
2236                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
2237                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, 3, 1);
2238                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
2239                 }
2240
2241                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
2242                     if (!Person::players[closest]->skeleton.free)
2243                         flatvelocity2 = Person::players[closest]->velocity;
2244                     if (Person::players[closest]->skeleton.free)
2245                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
2246                     if (!Person::players[closest]->skeleton.free)
2247                         flatfacing2 = DoRotation(DoRotation(DoRotation(Person::players[closest]->skeleton.joints[i].position, 0, 0, Person::players[closest]->tilt), Person::players[closest]->tilt2, 0, 0), 0, Person::players[closest]->yaw, 0) * Person::players[closest]->scale + Person::players[closest]->coords;
2248                     if (Person::players[closest]->skeleton.free)
2249                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
2250                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
2251                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
2252                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
2253                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, 3, 1);
2254                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
2255                 }
2256
2257                 XYZ temppos;
2258                 for (unsigned j = 0; j < Person::players.size(); j++) {
2259                     if (int(j) != closest) {
2260                         if (distsq(&Person::players[j]->coords, &Person::players[closest]->coords) < 25) {
2261                             Person::players[j]->DoDamage((25 - distsq(&Person::players[j]->coords, &Person::players[closest]->coords)) * 60);
2262                             if (Person::players[j]->skeleton.free == 2)
2263                                 Person::players[j]->skeleton.free = 1;
2264                             Person::players[j]->skeleton.longdead = 0;
2265                             Person::players[j]->RagDoll(0);
2266                             for (int i = 0; i < Person::players[j]->skeleton.num_joints; i++) {
2267                                 temppos = Person::players[j]->skeleton.joints[i].position + Person::players[j]->coords;
2268                                 if (distsq(&temppos, &Person::players[closest]->coords) < 25) {
2269                                     flatvelocity2 = temppos - Person::players[closest]->coords;
2270                                     Normalise(&flatvelocity2);
2271                                     Person::players[j]->skeleton.joints[i].velocity += flatvelocity2 * ((20 - distsq(&temppos, &Person::players[closest]->coords)) * 20);
2272                                 }
2273                             }
2274                         }
2275                     }
2276                 }
2277
2278                 Person::players[closest]->DoDamage(10000);
2279                 Person::players[closest]->RagDoll(0);
2280                 Person::players[closest]->dead = 2;
2281                 Person::players[closest]->coords = 20;
2282                 Person::players[closest]->skeleton.free = 2;
2283
2284                 camerashake += .6;
2285
2286             }
2287         }
2288
2289         if (Input::isKeyPressed(SDL_SCANCODE_F)) {
2290             Person::players[0]->onfire = 1 - Person::players[0]->onfire;
2291             if (Person::players[0]->onfire) {
2292                 Person::players[0]->CatchFire();
2293             }
2294             if (!Person::players[0]->onfire) {
2295                 emit_sound_at(fireendsound, Person::players[0]->coords);
2296                 pause_sound(stream_firesound);
2297             }
2298         }
2299
2300         if (Input::isKeyPressed(SDL_SCANCODE_N) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2301             Person::players[0]->RagDoll(0);
2302
2303             emit_sound_at(whooshsound, Person::players[0]->coords, 128.);
2304         }
2305
2306         if (Input::isKeyPressed(SDL_SCANCODE_N) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2307             for (int i = 0; i < objects.numobjects; i++) {
2308                 if (objects.type[i] == treeleavestype) {
2309                     objects.scale[i] *= .9;
2310                 }
2311             }
2312         }
2313
2314         if (Input::isKeyPressed(SDL_SCANCODE_M) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2315             editorenabled = !editorenabled;
2316             if (editorenabled) {
2317                 Person::players[0]->damagetolerance = 100000;
2318             } else {
2319                 Person::players[0]->damagetolerance = 200;
2320             }
2321             Person::players[0]->damage = 0; // these lines were in both if and else, but I think they would better fit in the if
2322             Person::players[0]->permanentdamage = 0;
2323             Person::players[0]->superpermanentdamage = 0;
2324             Person::players[0]->bloodloss = 0;
2325             Person::players[0]->deathbleeding = 0;
2326         }
2327
2328         //skip level
2329         if (whichlevel != -2 && Input::isKeyPressed(SDL_SCANCODE_K) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !editorenabled) {
2330             targetlevel++;
2331             if (targetlevel > numchallengelevels - 1)
2332                 targetlevel = 0;
2333             loading = 1;
2334             leveltime = 5;
2335         }
2336
2337         if (editorenabled) {
2338             if (Input::isKeyPressed(SDL_SCANCODE_DELETE) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2339                 int closest = findClosestPlayer();
2340                 if (closest >= 0) {
2341                     Person::players.erase(Person::players.begin()+closest);
2342                 }
2343             }
2344
2345             if (Input::isKeyPressed(SDL_SCANCODE_DELETE) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2346                 int closest = findClosestObject();
2347                 if (closest >= 0)
2348                     objects.position[closest].y -= 500;
2349             }
2350
2351             if (Input::isKeyPressed(SDL_SCANCODE_M) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2352                 if (objects.numobjects < max_objects - 1) {
2353                     XYZ boxcoords;
2354                     boxcoords.x = Person::players[0]->coords.x;
2355                     boxcoords.z = Person::players[0]->coords.z;
2356                     boxcoords.y = Person::players[0]->coords.y - 3;
2357                     if (editortype == bushtype)
2358                         boxcoords.y = Person::players[0]->coords.y - .5;
2359                     if (editortype == firetype)
2360                         boxcoords.y = Person::players[0]->coords.y - .5;
2361                     //objects.MakeObject(abs(Random()%3),boxcoords,Random()%360);
2362                     float temprotat, temprotat2;
2363                     temprotat = editoryaw;
2364                     temprotat2 = editorpitch;
2365                     if (temprotat < 0 || editortype == bushtype)
2366                         temprotat = Random() % 360;
2367                     if (temprotat2 < 0)
2368                         temprotat2 = Random() % 360;
2369
2370                     objects.MakeObject(editortype, boxcoords, (int)temprotat - ((int)temprotat) % 30, (int)temprotat2, editorsize);
2371                     if (editortype == treetrunktype)
2372                         objects.MakeObject(treeleavestype, boxcoords, Random() % 360 * (temprotat2 < 2) + (int)editoryaw - ((int)editoryaw) % 30, editorpitch, editorsize);
2373                 }
2374             }
2375
2376             if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2377                 Person::players.push_back(shared_ptr<Person>(new Person()));
2378
2379                 Person::players.back()->scale = .2 * 5 * Person::players[0]->scale;
2380                 Person::players.back()->creature = rabbittype;
2381                 Person::players.back()->howactive = editoractive;
2382                 Person::players.back()->skeleton.id = Person::players.size()-1;
2383                 Person::players.back()->skeleton.Load((char *)":Data:Skeleton:Basic Figure", (char *)":Data:Skeleton:Basic Figurelow", (char *)":Data:Skeleton:Rabbitbelt", (char *)":Data:Models:Body.solid", (char *)":Data:Models:Body2.solid", (char *)":Data:Models:Body3.solid", (char *)":Data:Models:Body4.solid", (char *)":Data:Models:Body5.solid", (char *)":Data:Models:Body6.solid", (char *)":Data:Models:Body7.solid", (char *)":Data:Models:Bodylow.solid", (char *)":Data:Models:Belt.solid", 1);
2384
2385                 int k = abs(Random() % 2) + 1;
2386                 if (k == 0) {
2387                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur3.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
2388                     Person::players.back()->whichskin = 0;
2389                 } else if (k == 1) {
2390                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
2391                     Person::players.back()->whichskin = 1;
2392                 } else {
2393                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur2.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
2394                     Person::players.back()->whichskin = 2;
2395                 }
2396
2397                 Person::players.back()->skeleton.drawmodelclothes.textureptr.load(":Data:Textures:Belt.png", 1, 1);
2398                 Person::players.back()->power = 1;
2399                 Person::players.back()->speedmult = 1;
2400                 Person::players.back()->animCurrent = bounceidleanim;
2401                 Person::players.back()->animTarget = bounceidleanim;
2402                 Person::players.back()->frameCurrent = 0;
2403                 Person::players.back()->frameTarget = 1;
2404                 Person::players.back()->target = 0;
2405                 Person::players.back()->bled = 0;
2406                 Person::players.back()->speed = 1 + (float)(Random() % 100) / 1000;
2407
2408                 Person::players.back()->targetyaw = Person::players[0]->targetyaw;
2409                 Person::players.back()->yaw = Person::players[0]->yaw;
2410
2411                 Person::players.back()->velocity = 0;
2412                 Person::players.back()->coords = Person::players[0]->coords;
2413                 Person::players.back()->oldcoords = Person::players.back()->coords;
2414                 Person::players.back()->realoldcoords = Person::players.back()->coords;
2415
2416                 Person::players.back()->id = Person::players.size()-1;
2417                 Person::players.back()->updatedelay = 0;
2418                 Person::players.back()->normalsupdatedelay = 0;
2419
2420                 Person::players.back()->aitype = passivetype;
2421
2422                 if (Person::players[0]->creature == wolftype) {
2423                     headprop = Person::players[0]->proportionhead.x / 1.1;
2424                     bodyprop = Person::players[0]->proportionbody.x / 1.1;
2425                     armprop = Person::players[0]->proportionarms.x / 1.1;
2426                     legprop = Person::players[0]->proportionlegs.x / 1.1;
2427                 }
2428
2429                 if (Person::players[0]->creature == rabbittype) {
2430                     headprop = Person::players[0]->proportionhead.x / 1.2;
2431                     bodyprop = Person::players[0]->proportionbody.x / 1.05;
2432                     armprop = Person::players[0]->proportionarms.x / 1.00;
2433                     legprop = Person::players[0]->proportionlegs.x / 1.1;
2434                 }
2435
2436                 if (Person::players.back()->creature == wolftype) {
2437                     Person::players.back()->proportionhead = 1.1 * headprop;
2438                     Person::players.back()->proportionbody = 1.1 * bodyprop;
2439                     Person::players.back()->proportionarms = 1.1 * armprop;
2440                     Person::players.back()->proportionlegs = 1.1 * legprop;
2441                 }
2442
2443                 if (Person::players.back()->creature == rabbittype) {
2444                     Person::players.back()->proportionhead = 1.2 * headprop;
2445                     Person::players.back()->proportionbody = 1.05 * bodyprop;
2446                     Person::players.back()->proportionarms = 1.00 * armprop;
2447                     Person::players.back()->proportionlegs = 1.1 * legprop;
2448                     Person::players.back()->proportionlegs.y = 1.05 * legprop;
2449                 }
2450
2451                 Person::players.back()->headless = 0;
2452                 Person::players.back()->onfire = 0;
2453
2454                 if (cellophane) {
2455                     Person::players.back()->proportionhead.z = 0;
2456                     Person::players.back()->proportionbody.z = 0;
2457                     Person::players.back()->proportionarms.z = 0;
2458                     Person::players.back()->proportionlegs.z = 0;
2459                 }
2460
2461                 Person::players.back()->tempanimation.Load((char *)"Tempanim", 0, 0);
2462
2463                 Person::players.back()->damagetolerance = 200;
2464
2465                 Person::players.back()->protectionhead = Person::players[0]->protectionhead;
2466                 Person::players.back()->protectionhigh = Person::players[0]->protectionhigh;
2467                 Person::players.back()->protectionlow = Person::players[0]->protectionlow;
2468                 Person::players.back()->armorhead = Person::players[0]->armorhead;
2469                 Person::players.back()->armorhigh = Person::players[0]->armorhigh;
2470                 Person::players.back()->armorlow = Person::players[0]->armorlow;
2471                 Person::players.back()->metalhead = Person::players[0]->metalhead;
2472                 Person::players.back()->metalhigh = Person::players[0]->metalhigh;
2473                 Person::players.back()->metallow = Person::players[0]->metallow;
2474
2475                 Person::players.back()->immobile = Person::players[0]->immobile;
2476
2477                 Person::players.back()->numclothes = Person::players[0]->numclothes;
2478                 for (int i = 0; i < Person::players.back()->numclothes; i++) {
2479                     strcpy(Person::players.back()->clothes[i], Person::players[0]->clothes[i]);
2480                     Person::players.back()->clothestintr[i] = Person::players[0]->clothestintr[i];
2481                     Person::players.back()->clothestintg[i] = Person::players[0]->clothestintg[i];
2482                     Person::players.back()->clothestintb[i] = Person::players[0]->clothestintb[i];
2483                 }
2484                 Person::players.back()->addClothes();
2485
2486                 Person::players.back()->power = Person::players[0]->power;
2487                 Person::players.back()->speedmult = Person::players[0]->speedmult;
2488
2489                 Person::players.back()->damage = 0;
2490                 Person::players.back()->permanentdamage = 0;
2491                 Person::players.back()->superpermanentdamage = 0;
2492                 Person::players.back()->deathbleeding = 0;
2493                 Person::players.back()->bleeding = 0;
2494                 Person::players.back()->numwaypoints = 0;
2495                 Person::players.back()->waypoint = 0;
2496                 Person::players.back()->jumppath = 0;
2497                 Person::players.back()->weaponstuck = -1;
2498                 Person::players.back()->weaponactive = -1;
2499                 Person::players.back()->num_weapons = 0;
2500                 Person::players.back()->bloodloss = 0;
2501                 Person::players.back()->dead = 0;
2502
2503                 Person::players.back()->loaded = 1;
2504             }
2505
2506             if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2507                 if (Person::players.back()->numwaypoints < 90) {
2508                     Person::players.back()->waypoints[Person::players.back()->numwaypoints] = Person::players[0]->coords;
2509                     Person::players.back()->waypointtype[Person::players.back()->numwaypoints] = editorpathtype;
2510                     Person::players.back()->numwaypoints++;
2511                 }
2512             }
2513
2514             if (Input::isKeyPressed(SDL_SCANCODE_P) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2515                 if (numpathpoints < 30) {
2516                     bool connected, alreadyconnected;
2517                     connected = 0;
2518                     if (numpathpoints > 1)
2519                         for (int i = 0; i < numpathpoints; i++) {
2520                             if (distsq(&pathpoint[i], &Person::players[0]->coords) < .5 && i != pathpointselected && !connected) {
2521                                 alreadyconnected = 0;
2522                                 for (int j = 0; j < numpathpointconnect[pathpointselected]; j++) {
2523                                     if (pathpointconnect[pathpointselected][j] == i)
2524                                         alreadyconnected = 1;
2525                                 }
2526                                 if (!alreadyconnected) {
2527                                     numpathpointconnect[pathpointselected]++;
2528                                     connected = 1;
2529                                     pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected] - 1] = i;
2530                                 }
2531                             }
2532                         }
2533                     if (!connected) {
2534                         numpathpoints++;
2535                         pathpoint[numpathpoints - 1] = Person::players[0]->coords;
2536                         numpathpointconnect[numpathpoints - 1] = 0;
2537                         if (numpathpoints > 1 && pathpointselected != -1) {
2538                             numpathpointconnect[pathpointselected]++;
2539                             pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected] - 1] = numpathpoints - 1;
2540                         }
2541                         pathpointselected = numpathpoints - 1;
2542                     }
2543                 }
2544             }
2545
2546             if (Input::isKeyPressed(SDL_SCANCODE_PERIOD)) {
2547                 pathpointselected++;
2548                 if (pathpointselected >= numpathpoints)
2549                     pathpointselected = -1;
2550             }
2551             if (Input::isKeyPressed(SDL_SCANCODE_COMMA) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2552                 pathpointselected--;
2553                 if (pathpointselected <= -2)
2554                     pathpointselected = numpathpoints - 1;
2555             }
2556             if (Input::isKeyPressed(SDL_SCANCODE_COMMA) && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2557                 if (pathpointselected != -1) {
2558                     numpathpoints--;
2559                     pathpoint[pathpointselected] = pathpoint[numpathpoints];
2560                     numpathpointconnect[pathpointselected] = numpathpointconnect[numpathpoints];
2561                     for (int i = 0; i < numpathpointconnect[pathpointselected]; i++) {
2562                         pathpointconnect[pathpointselected][i] = pathpointconnect[numpathpoints][i];
2563                     }
2564                     for (int i = 0; i < numpathpoints; i++) {
2565                         for (int j = 0; j < numpathpointconnect[i]; j++) {
2566                             if (pathpointconnect[i][j] == pathpointselected) {
2567                                 pathpointconnect[i][j] = pathpointconnect[i][numpathpointconnect[i] - 1];
2568                                 numpathpointconnect[i]--;
2569                             }
2570                             if (pathpointconnect[i][j] == numpathpoints) {
2571                                 pathpointconnect[i][j] = pathpointselected;
2572                             }
2573                         }
2574                     }
2575                     pathpointselected = numpathpoints - 1;
2576                 }
2577             }
2578
2579             if (Input::isKeyPressed(SDL_SCANCODE_LEFT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2580                 editortype--;
2581                 if (editortype == treeleavestype || editortype == 10)
2582                     editortype--;
2583                 if (editortype < 0)
2584                     editortype = firetype;
2585             }
2586
2587             if (Input::isKeyPressed(SDL_SCANCODE_RIGHT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2588                 editortype++;
2589                 if (editortype == treeleavestype || editortype == 10)
2590                     editortype++;
2591                 if (editortype > firetype)
2592                     editortype = 0;
2593             }
2594
2595             if (Input::isKeyDown(SDL_SCANCODE_LEFT) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2596                 editoryaw -= multiplier * 100;
2597                 if (editoryaw < -.01)
2598                     editoryaw = -.01;
2599             }
2600
2601             if (Input::isKeyDown(SDL_SCANCODE_RIGHT) && !Input::isKeyDown(SDL_SCANCODE_LSHIFT) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2602                 editoryaw += multiplier * 100;
2603             }
2604
2605             if (Input::isKeyDown(SDL_SCANCODE_UP) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2606                 editorsize += multiplier;
2607             }
2608
2609             if (Input::isKeyDown(SDL_SCANCODE_DOWN) && !Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2610                 editorsize -= multiplier;
2611                 if (editorsize < .1)
2612                     editorsize = .1;
2613             }
2614
2615
2616             if (Input::isKeyPressed(SDL_SCANCODE_LEFT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2617                 mapradius -= multiplier * 10;
2618             }
2619
2620             if (Input::isKeyPressed(SDL_SCANCODE_RIGHT) && Input::isKeyDown(SDL_SCANCODE_LSHIFT) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2621                 mapradius += multiplier * 10;
2622             }
2623             if (Input::isKeyDown(SDL_SCANCODE_UP) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2624                 editorpitch += multiplier * 100;
2625             }
2626
2627             if (Input::isKeyDown(SDL_SCANCODE_DOWN) && Input::isKeyDown(SDL_SCANCODE_LCTRL)) {
2628                 editorpitch -= multiplier * 100;
2629                 if (editorpitch < -.01)
2630                     editorpitch = -.01;
2631             }
2632             if (Input::isKeyPressed(SDL_SCANCODE_DELETE) && objects.numobjects && Input::isKeyDown(SDL_SCANCODE_LSHIFT)) {
2633                 int closest = findClosestObject();
2634                 if (closest >= 0)
2635                     objects.DeleteObject(closest);
2636             }
2637         }
2638     }
2639 }
2640
2641 void doJumpReversals()
2642 {
2643     for (unsigned k = 0; k < Person::players.size(); k++)
2644         for (unsigned i = k; i < Person::players.size(); i++) {
2645             if (i == k)
2646                 continue;
2647             if (     Person::players[k]->skeleton.free == 0 &&
2648                      Person::players[i]->skeleton.oldfree == 0 &&
2649                      (Person::players[i]->animTarget == jumpupanim ||
2650                       Person::players[k]->animTarget == jumpupanim) &&
2651                      (Person::players[i]->aitype == playercontrolled ||
2652                       Person::players[k]->aitype == playercontrolled) &&
2653                      ((Person::players[i]->aitype == attacktypecutoff && Person::players[i]->stunned <= 0) ||
2654                       (Person::players[k]->aitype == attacktypecutoff && Person::players[k]->stunned <= 0))) {
2655                 if (     distsq(&Person::players[i]->coords, &Person::players[k]->coords) < 10 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5) &&
2656                          distsqflat(&Person::players[i]->coords, &Person::players[k]->coords) < 2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
2657                     //TODO: refactor two huge similar ifs
2658                     if (Person::players[i]->animTarget == jumpupanim &&
2659                             Person::players[k]->animTarget != getupfrombackanim &&
2660                             Person::players[k]->animTarget != getupfromfrontanim &&
2661                             animation[Person::players[k]->animTarget].height == middleheight &&
2662                             normaldotproduct(Person::players[i]->velocity, Person::players[k]->coords - Person::players[i]->coords) < 0 &&
2663                             ((Person::players[k]->aitype == playercontrolled && Person::players[k]->attackkeydown) ||
2664                              Person::players[k]->aitype != playercontrolled)) {
2665                         Person::players[i]->victim = Person::players[k];
2666                         Person::players[i]->velocity = 0;
2667                         Person::players[i]->animCurrent = jumpreversedanim;
2668                         Person::players[i]->animTarget = jumpreversedanim;
2669                         Person::players[i]->frameCurrent = 0;
2670                         Person::players[i]->frameTarget = 1;
2671                         Person::players[i]->targettilt2 = 0;
2672                         Person::players[k]->victim = Person::players[i];
2673                         Person::players[k]->velocity = 0;
2674                         Person::players[k]->animCurrent = jumpreversalanim;
2675                         Person::players[k]->animTarget = jumpreversalanim;
2676                         Person::players[k]->frameCurrent = 0;
2677                         Person::players[k]->frameTarget = 1;
2678                         Person::players[k]->targettilt2 = 0;
2679                         if (Person::players[i]->coords.y < Person::players[k]->coords.y + 1) {
2680                             Person::players[i]->animCurrent = rabbitkickreversedanim;
2681                             Person::players[i]->animTarget = rabbitkickreversedanim;
2682                             Person::players[i]->frameCurrent = 1;
2683                             Person::players[i]->frameTarget = 2;
2684                             Person::players[k]->animCurrent = rabbitkickreversalanim;
2685                             Person::players[k]->animTarget = rabbitkickreversalanim;
2686                             Person::players[k]->frameCurrent = 1;
2687                             Person::players[k]->frameTarget = 2;
2688                         }
2689                         Person::players[i]->target = 0;
2690                         Person::players[k]->oldcoords = Person::players[k]->coords;
2691                         Person::players[i]->coords = Person::players[k]->coords;
2692                         Person::players[k]->targetyaw = Person::players[i]->targetyaw;
2693                         Person::players[k]->yaw = Person::players[i]->targetyaw;
2694                         if (Person::players[k]->aitype == attacktypecutoff)
2695                             Person::players[k]->stunned = .5;
2696                     }
2697                     if (Person::players[k]->animTarget == jumpupanim &&
2698                             Person::players[i]->animTarget != getupfrombackanim &&
2699                             Person::players[i]->animTarget != getupfromfrontanim &&
2700                             animation[Person::players[i]->animTarget].height == middleheight &&
2701                             normaldotproduct(Person::players[k]->velocity, Person::players[i]->coords - Person::players[k]->coords) < 0 &&
2702                             ((Person::players[i]->aitype == playercontrolled && Person::players[i]->attackkeydown) ||
2703                              Person::players[i]->aitype != playercontrolled)) {
2704                         Person::players[k]->victim = Person::players[i];
2705                         Person::players[k]->velocity = 0;
2706                         Person::players[k]->animCurrent = jumpreversedanim;
2707                         Person::players[k]->animTarget = jumpreversedanim;
2708                         Person::players[k]->frameCurrent = 0;
2709                         Person::players[k]->frameTarget = 1;
2710                         Person::players[k]->targettilt2 = 0;
2711                         Person::players[i]->victim = Person::players[k];
2712                         Person::players[i]->velocity = 0;
2713                         Person::players[i]->animCurrent = jumpreversalanim;
2714                         Person::players[i]->animTarget = jumpreversalanim;
2715                         Person::players[i]->frameCurrent = 0;
2716                         Person::players[i]->frameTarget = 1;
2717                         Person::players[i]->targettilt2 = 0;
2718                         if (Person::players[k]->coords.y < Person::players[i]->coords.y + 1) {
2719                             Person::players[k]->animTarget = rabbitkickreversedanim;
2720                             Person::players[k]->animCurrent = rabbitkickreversedanim;
2721                             Person::players[i]->animCurrent = rabbitkickreversalanim;
2722                             Person::players[i]->animTarget = rabbitkickreversalanim;
2723                             Person::players[k]->frameCurrent = 1;
2724                             Person::players[k]->frameTarget = 2;
2725                             Person::players[i]->frameCurrent = 1;
2726                             Person::players[i]->frameTarget = 2;
2727                         }
2728                         Person::players[k]->target = 0;
2729                         Person::players[i]->oldcoords = Person::players[i]->coords;
2730                         Person::players[k]->coords = Person::players[i]->coords;
2731                         Person::players[i]->targetyaw = Person::players[k]->targetyaw;
2732                         Person::players[i]->yaw = Person::players[k]->targetyaw;
2733                         if (Person::players[i]->aitype == attacktypecutoff)
2734                             Person::players[i]->stunned = .5;
2735                     }
2736                 }
2737             }
2738         }
2739 }
2740
2741 void doAerialAcrobatics()
2742 {
2743     static XYZ facing, flatfacing;
2744     for (unsigned k = 0; k < Person::players.size(); k++) {
2745         Person::players[k]->turnspeed = 500;
2746
2747         if ((Person::players[k]->isRun() &&
2748                 ((Person::players[k]->targetyaw != rabbitrunninganim &&
2749                   Person::players[k]->targetyaw != wolfrunninganim) ||
2750                  Person::players[k]->frameTarget == 4)) ||
2751                 Person::players[k]->animTarget == removeknifeanim ||
2752                 Person::players[k]->animTarget == crouchremoveknifeanim ||
2753                 Person::players[k]->animTarget == flipanim ||
2754                 Person::players[k]->animTarget == fightsidestep ||
2755                 Person::players[k]->animTarget == walkanim) {
2756             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed);
2757         }
2758
2759
2760         if (Person::players[k]->isStop() ||
2761                 Person::players[k]->isLanding() ||
2762                 Person::players[k]->animTarget == staggerbackhighanim ||
2763                 (Person::players[k]->animTarget == sneakanim && Person::players[k]->animCurrent == sneakanim) ||
2764                 Person::players[k]->animTarget == staggerbackhardanim ||
2765                 Person::players[k]->animTarget == backhandspringanim ||
2766                 Person::players[k]->animTarget == dodgebackanim ||
2767                 Person::players[k]->animTarget == rollanim ||
2768                 (animation[Person::players[k]->animTarget].attack &&
2769                  Person::players[k]->animTarget != rabbitkickanim &&
2770                  (Person::players[k]->animTarget != crouchstabanim || Person::players[k]->hasvictim) &&
2771                  (Person::players[k]->animTarget != swordgroundstabanim || Person::players[k]->hasvictim))) {
2772             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed * 2);
2773         }
2774
2775         if (Person::players[k]->animTarget == sneakanim && Person::players[k]->animCurrent != sneakanim) {
2776             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed * 4);
2777         }
2778
2779         Person::players[k]->DoStuff();
2780         if (Person::players[k]->immobile && k != 0)
2781             Person::players[k]->coords = Person::players[k]->realoldcoords;
2782
2783         //if player's position has changed (?)
2784         if (distsq(&Person::players[k]->coords, &Person::players[k]->realoldcoords) > 0 &&
2785                 !Person::players[k]->skeleton.free &&
2786                 Person::players[k]->animTarget != climbanim &&
2787                 Person::players[k]->animTarget != hanganim) {
2788             XYZ lowpoint, lowpointtarget, lowpoint2, lowpointtarget2, lowpoint3, lowpointtarget3, lowpoint4, lowpointtarget4, lowpoint5, lowpointtarget5, lowpoint6, lowpointtarget6, lowpoint7, lowpointtarget7, colpoint, colpoint2;
2789             int whichhit;
2790             bool tempcollide = 0;
2791
2792             if (Person::players[k]->collide < -.3)
2793                 Person::players[k]->collide = -.3;
2794             if (Person::players[k]->collide > 1)
2795                 Person::players[k]->collide = 1;
2796             Person::players[k]->collide -= multiplier * 30;
2797
2798             //clip to terrain
2799             Person::players[k]->coords.y = max(Person::players[k]->coords.y, terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z));
2800
2801             for (int l = 0; l < terrain.patchobjectnum[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz]; l++) {
2802                 int i = terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz][l];
2803                 if (objects.type[i] != rocktype ||
2804                         objects.scale[i] > .5 && Person::players[k]->aitype == playercontrolled ||
2805                         objects.position[i].y > Person::players[k]->coords.y) {
2806                     lowpoint = Person::players[k]->coords;
2807                     if (Person::players[k]->animTarget != jumpupanim &&
2808                             Person::players[k]->animTarget != jumpdownanim &&
2809                             !Person::players[k]->isFlip())
2810                         lowpoint.y += 1.25;
2811                     else
2812                         lowpoint.y += 1.3;
2813                     if (     Person::players[k]->coords.y < terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z) &&
2814                              Person::players[k]->coords.y > terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z) - .1)
2815                         Person::players[k]->coords.y = terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z);
2816                     if (Person::players[k]->SphereCheck(&lowpoint, 1.3, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
2817                         flatfacing = lowpoint - Person::players[k]->coords;
2818                         Person::players[k]->coords = lowpoint;
2819                         Person::players[k]->coords.y -= 1.3;
2820                         Person::players[k]->collide = 1;
2821                         tempcollide = 1;
2822                         //wall jumps
2823                         //TODO: refactor four similar blocks
2824                         if (Person::players[k]->aitype == playercontrolled &&
2825                                 (Person::players[k]->animTarget == jumpupanim ||
2826                                  Person::players[k]->animTarget == jumpdownanim ||
2827                                  Person::players[k]->isFlip()) &&
2828                                 !Person::players[k]->jumptogglekeydown &&
2829                                 Person::players[k]->jumpkeydown) {
2830                             lowpointtarget = lowpoint + DoRotation(Person::players[k]->facing, 0, -90, 0) * 1.5;
2831                             XYZ tempcoords1 = lowpoint;
2832                             whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
2833                             if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
2834                                 Person::players[k]->setAnimation(walljumpleftanim);
2835                                 emit_sound_at(movewhooshsound, Person::players[k]->coords);
2836                                 if (k == 0)
2837                                     pause_sound(whooshsound);
2838
2839                                 lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
2840                                 Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
2841                                 if (lowpointtarget.z < 0)
2842                                     Person::players[k]->yaw = 180 - Person::players[k]->yaw;
2843                                 Person::players[k]->targetyaw = Person::players[k]->yaw;
2844                                 Person::players[k]->lowyaw = Person::players[k]->yaw;
2845                                 if (k == 0)
2846                                     numwallflipped++;
2847                             } else {
2848                                 lowpoint = tempcoords1;
2849                                 lowpointtarget = lowpoint + DoRotation(Person::players[k]->facing, 0, 90, 0) * 1.5;
2850                                 whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
2851                                 if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
2852                                     Person::players[k]->setAnimation(walljumprightanim);
2853                                     emit_sound_at(movewhooshsound, Person::players[k]->coords);
2854                                     if (k == 0)
2855                                         pause_sound(whooshsound);
2856
2857                                     lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
2858                                     Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
2859                                     if (lowpointtarget.z < 0)
2860                                         Person::players[k]->yaw = 180 - Person::players[k]->yaw;
2861                                     Person::players[k]->targetyaw = Person::players[k]->yaw;
2862                                     Person::players[k]->lowyaw = Person::players[k]->yaw;
2863                                     if (k == 0)
2864                                         numwallflipped++;
2865                                 } else {
2866                                     lowpoint = tempcoords1;
2867                                     lowpointtarget = lowpoint + Person::players[k]->facing * 2;
2868                                     whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
2869                                     if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
2870                                         Person::players[k]->setAnimation(walljumpbackanim);
2871                                         emit_sound_at(movewhooshsound, Person::players[k]->coords);
2872                                         if (k == 0)
2873                                             pause_sound(whooshsound);
2874
2875                                         lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
2876                                         Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
2877                                         if (lowpointtarget.z < 0)
2878                                             Person::players[k]->yaw = 180 - Person::players[k]->yaw;
2879                                         Person::players[k]->targetyaw = Person::players[k]->yaw;
2880                                         Person::players[k]->lowyaw = Person::players[k]->yaw;
2881                                         if (k == 0)
2882                                             numwallflipped++;
2883                                     } else {
2884                                         lowpoint = tempcoords1;
2885                                         lowpointtarget = lowpoint - Person::players[k]->facing * 2;
2886                                         whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
2887                                         if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
2888                                             Person::players[k]->setAnimation(walljumpfrontanim);
2889                                             emit_sound_at(movewhooshsound, Person::players[k]->coords);
2890                                             if (k == 0)
2891                                                 pause_sound(whooshsound);
2892
2893                                             lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
2894                                             Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
2895                                             if (lowpointtarget.z < 0)
2896                                                 Person::players[k]->yaw = 180 - Person::players[k]->yaw;
2897                                             Person::players[k]->yaw += 180;
2898                                             Person::players[k]->targetyaw = Person::players[k]->yaw;
2899                                             Person::players[k]->lowyaw = Person::players[k]->yaw;
2900                                             if (k == 0)
2901                                                 numwallflipped++;
2902                                         }
2903                                     }
2904                                 }
2905                             }
2906                         }
2907                     }
2908                 } else if (objects.type[i] == rocktype) {
2909                     lowpoint2 = Person::players[k]->coords;
2910                     lowpoint = Person::players[k]->coords;
2911                     lowpoint.y += 2;
2912                     if (objects.model[i].LineCheck(&lowpoint, &lowpoint2, &colpoint, &objects.position[i], &objects.yaw[i]) != -1) {
2913                         Person::players[k]->coords = colpoint;
2914                         Person::players[k]->collide = 1;
2915                         tempcollide = 1;
2916
2917                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) {
2918                             //flipped into a rock
2919                             if (Person::players[k]->isFlip() && animation[Person::players[k]->animTarget].label[Person::players[k]->frameTarget] == 7)
2920                                 Person::players[k]->RagDoll(0);
2921
2922                             if (Person::players[k]->animTarget == jumpupanim) {
2923                                 Person::players[k]->jumppower = -4;
2924                                 Person::players[k]->animTarget = Person::players[k]->getIdle();
2925                             }
2926                             Person::players[k]->target = 0;
2927                             Person::players[k]->frameTarget = 0;
2928                             Person::players[k]->onterrain = 1;
2929
2930                             if (Person::players[k]->id == 0) {
2931                                 pause_sound(whooshsound);
2932                                 OPENAL_SetVolume(channels[whooshsound], 0);
2933                             }
2934
2935                             //landing
2936                             if ((Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) && !Person::players[k]->wasLanding()) {
2937                                 if (Person::players[k]->isFlip())
2938                                     Person::players[k]->jumppower = -4;
2939                                 Person::players[k]->animTarget = Person::players[k]->getLanding();
2940                                 emit_sound_at(landsound, Person::players[k]->coords, 128.);
2941                                 if (k == 0) {
2942                                     envsound[numenvsounds] = Person::players[k]->coords;
2943                                     envsoundvol[numenvsounds] = 16;
2944                                     envsoundlife[numenvsounds] = .4;
2945                                     numenvsounds++;
2946                                 }
2947
2948                             }
2949                         }
2950                     }
2951                 }
2952             }
2953
2954             if (tempcollide)
2955                 for (int l = 0; l < terrain.patchobjectnum[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz]; l++) {
2956                     int i = terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz][l];
2957                     lowpoint = Person::players[k]->coords;
2958                     lowpoint.y += 1.35;
2959                     if (objects.type[i] != rocktype)
2960                         if (Person::players[k]->SphereCheck(&lowpoint, 1.33, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
2961                             if (Person::players[k]->animTarget != jumpupanim &&
2962                                     Person::players[k]->animTarget != jumpdownanim &&
2963                                     Person::players[k]->onterrain)
2964                                 Person::players[k]->avoidcollided = 1;
2965                             Person::players[k]->coords = lowpoint;
2966                             Person::players[k]->coords.y -= 1.35;
2967                             Person::players[k]->collide = 1;
2968
2969                             if ((Person::players[k]->grabdelay <= 0 || Person::players[k]->aitype != playercontrolled) &&
2970                                     (Person::players[k]->animCurrent != climbanim &&
2971                                      Person::players[k]->animCurrent != hanganim &&
2972                                      !Person::players[k]->isWallJump() ||
2973                                      Person::players[k]->animTarget == jumpupanim ||
2974                                      Person::players[k]->animTarget == jumpdownanim)) {
2975                                 lowpoint = Person::players[k]->coords;
2976                                 objects.model[i].SphereCheckPossible(&lowpoint, 1.5, &objects.position[i], &objects.yaw[i]);
2977                                 lowpoint = Person::players[k]->coords;
2978                                 lowpoint.y += .05;
2979                                 facing = 0;
2980                                 facing.z = -1;
2981                                 facing = DoRotation(facing, 0, Person::players[k]->targetyaw + 180, 0);
2982                                 lowpointtarget = lowpoint + facing * 1.4;
2983                                 whichhit = objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
2984                                 if (whichhit != -1) {
2985                                     lowpoint = Person::players[k]->coords;
2986                                     lowpoint.y += .1;
2987                                     lowpointtarget = lowpoint + facing * 1.4;
2988                                     lowpoint2 = lowpoint;
2989                                     lowpointtarget2 = lowpointtarget;
2990                                     lowpoint3 = lowpoint;
2991                                     lowpointtarget3 = lowpointtarget;
2992                                     lowpoint4 = lowpoint;
2993                                     lowpointtarget4 = lowpointtarget;
2994                                     lowpoint5 = lowpoint;
2995                                     lowpointtarget5 = lowpointtarget;
2996                                     lowpoint6 = lowpoint;
2997                                     lowpointtarget6 = lowpointtarget;
2998                                     lowpoint7 = lowpoint;
2999                                     lowpointtarget7 = lowpoint;
3000                                     lowpoint2.x += .1;
3001                                     lowpointtarget2.x += .1;
3002                                     lowpoint3.z += .1;
3003                                     lowpointtarget3.z += .1;
3004                                     lowpoint4.x -= .1;
3005                                     lowpointtarget4.x -= .1;
3006                                     lowpoint5.z -= .1;
3007                                     lowpointtarget5.z -= .1;
3008                                     lowpoint6.y += 45 / 13;
3009                                     lowpointtarget6.y += 45 / 13;
3010                                     lowpointtarget6 += facing * .6;
3011                                     lowpointtarget7.y += 90 / 13;
3012                                     whichhit = objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3013                                     if (objects.friction[i] > .5)
3014                                         if (whichhit != -1) {
3015                                             if (whichhit != -1 && Person::players[k]->animTarget != jumpupanim && Person::players[k]->animTarget != jumpdownanim)
3016                                                 Person::players[k]->collided = 1;
3017                                             if (checkcollide(lowpoint7, lowpointtarget7) == -1)
3018                                                 if (checkcollide(lowpoint6, lowpointtarget6) == -1)
3019                                                     if (     objects.model[i].LineCheckPossible(&lowpoint2, &lowpointtarget2,
3020                                                              &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3021                                                              objects.model[i].LineCheckPossible(&lowpoint3, &lowpointtarget3,
3022                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3023                                                              objects.model[i].LineCheckPossible(&lowpoint4, &lowpointtarget4,
3024                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3025                                                              objects.model[i].LineCheckPossible(&lowpoint5, &lowpointtarget5,
3026                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
3027                                                         for (int j = 0; j < 45; j++) {
3028                                                             lowpoint = Person::players[k]->coords;
3029                                                             lowpoint.y += (float)j / 13;
3030                                                             lowpointtarget = lowpoint + facing * 1.4;
3031                                                             if (objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget,
3032                                                                                                    &colpoint2, &objects.position[i], &objects.yaw[i]) == -1) {
3033                                                                 if (j <= 6 || j <= 25 && Person::players[k]->animTarget == jumpdownanim)
3034                                                                     break;
3035                                                                 if (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim) {
3036                                                                     lowpoint = Person::players[k]->coords;
3037                                                                     lowpoint.y += (float)j / 13;
3038                                                                     lowpointtarget = lowpoint + facing * 1.3;
3039                                                                     flatfacing = Person::players[k]->coords;
3040                                                                     Person::players[k]->coords = colpoint - DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[k], 0) * .01;
3041                                                                     Person::players[k]->coords.y = lowpointtarget.y - .07;
3042                                                                     Person::players[k]->currentoffset = (flatfacing - Person::players[k]->coords) / Person::players[k]->scale;
3043
3044                                                                     if (j > 10 || !Person::players[k]->isRun()) {
3045                                                                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->animTarget == jumpupanim) {
3046                                                                             if (k == 0)
3047                                                                                 pause_sound(whooshsound);
3048                                                                         }
3049                                                                         emit_sound_at(jumpsound, Person::players[k]->coords, 128.);
3050
3051                                                                         lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3052                                                                         Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3053                                                                         if (lowpointtarget.z < 0)
3054                                                                             Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3055                                                                         Person::players[k]->targetyaw = Person::players[k]->yaw;
3056                                                                         Person::players[k]->lowyaw = Person::players[k]->yaw;
3057
3058                                                                         //Person::players[k]->velocity=lowpointtarget*.03;
3059                                                                         Person::players[k]->velocity = 0;
3060
3061                                                                         //climb ledge (?)
3062                                                                         if (Person::players[k]->animTarget == jumpupanim) {
3063                                                                             Person::players[k]->animTarget = climbanim;
3064                                                                             Person::players[k]->jumppower = 0;
3065                                                                             Person::players[k]->jumpclimb = 1;
3066                                                                         }
3067                                                                         Person::players[k]->transspeed = 6;
3068                                                                         Person::players[k]->target = 0;
3069                                                                         Person::players[k]->frameTarget = 1;
3070                                                                         //hang ledge (?)
3071                                                                         if (j > 25) {
3072                                                                             Person::players[k]->setAnimation(hanganim);
3073                                                                             Person::players[k]->jumppower = 0;
3074                                                                         }
3075                                                                     }
3076                                                                     break;
3077                                                                 }
3078                                                             }
3079                                                         }
3080                                         }
3081                                 }
3082                             }
3083                         }
3084                 }
3085             if (Person::players[k]->collide <= 0) {
3086                 //in the air
3087                 if (!Person::players[k]->onterrain &&
3088                         Person::players[k]->animTarget != jumpupanim &&
3089                         Person::players[k]->animTarget != jumpdownanim &&
3090                         Person::players[k]->animTarget != climbanim &&
3091                         Person::players[k]->animTarget != hanganim &&
3092                         !Person::players[k]->isWallJump() &&
3093                         !Person::players[k]->isFlip()) {
3094                     if (Person::players[k]->animCurrent != climbanim &&
3095                             Person::players[k]->animCurrent != tempanim &&
3096                             Person::players[k]->animTarget != backhandspringanim &&
3097                             (Person::players[k]->animTarget != rollanim ||
3098                              Person::players[k]->frameTarget < 2 ||
3099                              Person::players[k]->frameTarget > 6)) {
3100                         //stagger off ledge (?)
3101                         if (Person::players[k]->animTarget == staggerbackhighanim || Person::players[k]->animTarget == staggerbackhardanim)
3102                             Person::players[k]->RagDoll(0);
3103                         Person::players[k]->setAnimation(jumpdownanim);
3104
3105                         if (!k)
3106                             emit_sound_at(whooshsound, Person::players[k]->coords, 128.);
3107                     }
3108                     //gravity
3109                     Person::players[k]->velocity.y += gravity;
3110                 }
3111             }
3112         }
3113         Person::players[k]->realoldcoords = Person::players[k]->coords;
3114     }
3115 }
3116
3117 void doAttacks()
3118 {
3119     static int randattack;
3120     static bool playerrealattackkeydown = 0;
3121
3122     if (!Input::isKeyDown(attackkey))
3123         oldattackkey = 0;
3124     if (oldattackkey)
3125         Person::players[0]->attackkeydown = 0;
3126     if (oldattackkey)
3127         playerrealattackkeydown = 0;
3128     if (!oldattackkey)
3129         playerrealattackkeydown = Input::isKeyDown(attackkey);
3130     if ((Person::players[0]->parriedrecently <= 0 ||
3131             Person::players[0]->weaponactive == -1) &&
3132             (!oldattackkey ||
3133              (realthreat &&
3134               Person::players[0]->lastattack != swordslashanim &&
3135               Person::players[0]->lastattack != knifeslashstartanim &&
3136               Person::players[0]->lastattack != staffhitanim &&
3137               Person::players[0]->lastattack != staffspinhitanim)))
3138         Person::players[0]->attackkeydown = Input::isKeyDown(attackkey);
3139     if (Input::isKeyDown(attackkey) &&
3140             !oldattackkey &&
3141             !Person::players[0]->backkeydown) {
3142         for (unsigned k = 0; k < Person::players.size(); k++) {
3143             if ((Person::players[k]->animTarget == swordslashanim ||
3144                     Person::players[k]->animTarget == staffhitanim ||
3145                     Person::players[k]->animTarget == staffspinhitanim) &&
3146                     Person::players[0]->animCurrent != dodgebackanim &&
3147                     !Person::players[k]->skeleton.free)
3148                 Person::players[k]->Reverse();
3149         }
3150     }
3151
3152     if (!hostile || indialogue != -1)
3153         Person::players[0]->attackkeydown = 0;
3154
3155     for (unsigned k = 0; k < Person::players.size(); k++) {
3156         if (indialogue != -1)
3157             Person::players[k]->attackkeydown = 0;
3158         if (Person::players[k]->animTarget != rabbitrunninganim && Person::players[k]->animTarget != wolfrunninganim) {
3159             if (Person::players[k]->aitype != playercontrolled)
3160                 Person::players[k]->victim = Person::players[0];
3161             //attack key pressed
3162             if (Person::players[k]->attackkeydown) {
3163                 //dodge backward
3164                 if (Person::players[k]->backkeydown &&
3165                         Person::players[k]->animTarget != backhandspringanim &&
3166                         (Person::players[k]->isIdle() ||
3167                          Person::players[k]->isStop() ||
3168                          Person::players[k]->isRun() ||
3169                          Person::players[k]->animTarget == walkanim)) {
3170                     if (Person::players[k]->jumppower <= 1) {
3171                         Person::players[k]->jumppower -= 2;
3172                     } else {
3173                         for (unsigned i = 0; i < Person::players.size(); i++) {
3174                             if (i == k)
3175                                 continue;
3176                             if (Person::players[i]->animTarget == swordslashanim ||
3177                                     Person::players[i]->animTarget == knifeslashstartanim ||
3178                                     Person::players[i]->animTarget == staffhitanim ||
3179                                     Person::players[i]->animTarget == staffspinhitanim)
3180                                 if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < 6.5 && !Person::players[i]->skeleton.free) {
3181                                     Person::players[k]->setAnimation(dodgebackanim);
3182                                     Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
3183                                     Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
3184                                 }
3185                         }
3186                         if (Person::players[k]->animTarget != dodgebackanim) {
3187                             if (k == 0)
3188                                 numflipped++;
3189                             Person::players[k]->setAnimation(backhandspringanim);
3190                             Person::players[k]->targetyaw = -yaw + 180;
3191                             if (Person::players[k]->leftkeydown)
3192                                 Person::players[k]->targetyaw -= 45;
3193                             if (Person::players[k]->rightkeydown)
3194                                 Person::players[k]->targetyaw += 45;
3195                             Person::players[k]->yaw = Person::players[k]->targetyaw;
3196                             Person::players[k]->jumppower -= 2;
3197                         }
3198                     }
3199                 }
3200                 //attack
3201                 if (!animation[Person::players[k]->animTarget].attack &&
3202                         !Person::players[k]->backkeydown &&
3203                         (Person::players[k]->isIdle() ||
3204                          Person::players[k]->isRun() ||
3205                          Person::players[k]->animTarget == walkanim ||
3206                          Person::players[k]->animTarget == sneakanim ||
3207                          Person::players[k]->isCrouch())) {
3208                     const int attackweapon = Person::players[k]->weaponactive == -1 ? 0 : weapons[Person::players[k]->weaponids[Person::players[k]->weaponactive]].getType();
3209                     //normal attacks (?)
3210                     Person::players[k]->hasvictim = 0;
3211                     if (Person::players.size() > 1)
3212                         for (unsigned i = 0; i < Person::players.size(); i++) {
3213                             if (i == k || !(k == 0 || i == 0))
3214                                 continue;
3215                             if (!Person::players[k]->hasvictim)
3216                                 if (animation[Person::players[k]->animTarget].attack != reversal) {
3217                                     //choose an attack
3218                                     const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
3219                                     if (distance < 4.5 &&
3220                                             !Person::players[i]->skeleton.free &&
3221                                             Person::players[i]->howactive < typedead1 &&
3222                                             Person::players[i]->animTarget != jumpreversedanim &&
3223                                             Person::players[i]->animTarget != rabbitkickreversedanim &&
3224                                             Person::players[i]->animTarget != rabbitkickanim &&
3225                                             Person::players[k]->animTarget != rabbitkickanim &&
3226                                             Person::players[i]->animTarget != getupfrombackanim &&
3227                                             (Person::players[i]->animTarget != staggerbackhighanim &&
3228                                              (Person::players[i]->animTarget != staggerbackhardanim ||
3229                                               animation[staggerbackhardanim].label[Person::players[i]->frameTarget] == 6)) &&
3230                                             Person::players[i]->animTarget != jumpdownanim &&
3231                                             Person::players[i]->animTarget != jumpupanim &&
3232                                             Person::players[i]->animTarget != getupfromfrontanim) {
3233                                         Person::players[k]->victim = Person::players[i];
3234                                         Person::players[k]->hasvictim = 1;
3235                                         if (Person::players[k]->aitype == playercontrolled) { //human player
3236                                             //sweep
3237                                             if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3238                                                     Person::players[k]->crouchkeydown &&
3239                                                     animation[Person::players[i]->animTarget].height != lowheight)
3240                                                 Person::players[k]->animTarget = sweepanim;
3241                                             //winduppunch
3242                                             else if (distance < 1.5 * sq(Person::players[k]->scale * 5) &&
3243                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3244                                                      !Person::players[k]->forwardkeydown &&
3245                                                      !Person::players[k]->leftkeydown &&
3246                                                      !Person::players[k]->rightkeydown &&
3247                                                      !Person::players[k]->crouchkeydown &&
3248                                                      !attackweapon &&
3249                                                      !reversaltrain)
3250                                                 Person::players[k]->animTarget = winduppunchanim;
3251                                             //upunch
3252                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3253                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3254                                                      !Person::players[k]->forwardkeydown &&
3255                                                      !Person::players[k]->leftkeydown &&
3256                                                      !Person::players[k]->rightkeydown &&
3257                                                      !Person::players[k]->crouchkeydown &&
3258                                                      !attackweapon)
3259                                                 Person::players[k]->animTarget = upunchanim;
3260                                             //knifefollow
3261                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3262                                                      Person::players[i]->staggerdelay > 0 &&
3263                                                      attackweapon == knife &&
3264                                                      Person::players[i]->bloodloss > Person::players[i]->damagetolerance / 2)
3265                                                 Person::players[k]->animTarget = knifefollowanim;
3266                                             //knifeslashstart
3267                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3268                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3269                                                      !Person::players[k]->forwardkeydown &&
3270                                                      !Person::players[k]->leftkeydown &&
3271                                                      !Person::players[k]->rightkeydown &&
3272                                                      !Person::players[k]->crouchkeydown &&
3273                                                      attackweapon == knife &&
3274                                                      Person::players[k]->weaponmissdelay <= 0)
3275                                                 Person::players[k]->animTarget = knifeslashstartanim;
3276                                             //swordslash
3277                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
3278                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3279                                                      !Person::players[k]->crouchkeydown &&
3280                                                      attackweapon == sword &&
3281                                                      Person::players[k]->weaponmissdelay <= 0)
3282                                                 Person::players[k]->animTarget = swordslashanim;
3283                                             //staffhit
3284                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
3285                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3286                                                      !Person::players[k]->crouchkeydown &&
3287                                                      attackweapon == staff &&
3288                                                      Person::players[k]->weaponmissdelay <= 0 &&
3289                                                      !Person::players[k]->leftkeydown &&
3290                                                      !Person::players[k]->rightkeydown &&
3291                                                      !Person::players[k]->forwardkeydown)
3292                                                 Person::players[k]->animTarget = staffhitanim;
3293                                             //staffspinhit
3294                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
3295                                                      animation[Person::players[i]->animTarget].height != lowheight &&
3296                                                      !Person::players[k]->crouchkeydown &&
3297                                                      attackweapon == staff &&
3298                                                      Person::players[k]->weaponmissdelay <= 0)
3299                                                 Person::players[k]->animTarget = staffspinhitanim;
3300                                             //spinkick
3301                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3302                                                      animation[Person::players[i]->animTarget].height != lowheight)
3303                                                 Person::players[k]->animTarget = spinkickanim;
3304                                             //lowkick
3305                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3306                                                      animation[Person::players[i]->animTarget].height == lowheight &&
3307                                                      animation[Person::players[k]->animTarget].attack != normalattack)
3308                                                 Person::players[k]->animTarget = lowkickanim;
3309                                         } else { //AI player
3310                                             if (distance < 4.5 * sq(Person::players[k]->scale * 5)) {
3311                                                 randattack = abs(Random() % 5);
3312                                                 if (!attackweapon && distance < 2.5 * sq(Person::players[k]->scale * 5)) {
3313                                                     //sweep
3314                                                     if (randattack == 0 && animation[Person::players[i]->animTarget].height != lowheight)
3315                                                         Person::players[k]->animTarget = sweepanim;
3316                                                     //upunch
3317                                                     else if (randattack == 1 && animation[Person::players[i]->animTarget].height != lowheight &&
3318                                                              !attackweapon)
3319                                                         Person::players[k]->animTarget = upunchanim;
3320                                                     //spinkick
3321                                                     else if (randattack == 2 && animation[Person::players[i]->animTarget].height != lowheight)
3322                                                         Person::players[k]->animTarget = spinkickanim;
3323                                                     //lowkick
3324                                                     else if (animation[Person::players[i]->animTarget].height == lowheight)
3325                                                         Person::players[k]->animTarget = lowkickanim;
3326                                                 }
3327                                                 if (attackweapon) {
3328                                                     //sweep
3329                                                     if ((tutoriallevel != 1 || !attackweapon) &&
3330                                                             distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3331                                                             randattack == 0 &&
3332                                                             animation[Person::players[i]->animTarget].height != lowheight)
3333                                                         Person::players[k]->animTarget = sweepanim;
3334                                                     //knifeslashstart
3335                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3336                                                              attackweapon == knife &&
3337                                                              Person::players[k]->weaponmissdelay <= 0)
3338                                                         Person::players[k]->animTarget = knifeslashstartanim;
3339                                                     //swordslash
3340                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
3341                                                                Person::players[0]->hasvictim &&
3342                                                                Person::players[0]->animTarget == swordslashanim) &&
3343                                                              attackweapon == sword &&
3344                                                              Person::players[k]->weaponmissdelay <= 0)
3345                                                         Person::players[k]->animTarget = swordslashanim;
3346                                                     //staffhit
3347                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
3348                                                                Person::players[0]->hasvictim &&
3349                                                                Person::players[0]->animTarget == swordslashanim) &&
3350                                                              attackweapon == staff &&
3351                                                              Person::players[k]->weaponmissdelay <= 0 &&
3352                                                              randattack < 3)
3353                                                         Person::players[k]->animTarget = staffhitanim;
3354                                                     //staffspinhit
3355                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
3356                                                                Person::players[0]->hasvictim &&
3357                                                                Person::players[0]->animTarget == swordslashanim) &&
3358                                                              attackweapon == staff &&
3359                                                              Person::players[k]->weaponmissdelay <= 0 &&
3360                                                              randattack >= 3)
3361                                                         Person::players[k]->animTarget = staffspinhitanim;
3362                                                     //spinkick
3363                                                     else if ((tutoriallevel != 1 || !attackweapon) &&
3364                                                              distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3365                                                              randattack == 1 &&
3366                                                              animation[Person::players[i]->animTarget].height != lowheight)
3367                                                         Person::players[k]->animTarget = spinkickanim;
3368                                                     //lowkick
3369                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
3370                                                              animation[Person::players[i]->animTarget].height == lowheight &&
3371                                                              animation[Person::players[k]->animTarget].attack != normalattack)
3372                                                         Person::players[k]->animTarget = lowkickanim;
3373                                                 }
3374                                             }
3375                                         }
3376                                         //upunch becomes wolfslap
3377                                         if (Person::players[k]->animTarget == upunchanim && Person::players[k]->creature == wolftype)
3378                                             Person::players[k]->animTarget = wolfslapanim;
3379                                     }
3380                                     //sneak attacks
3381                                     if ((k == 0) && (tutoriallevel != 1 || tutorialstage == 22) &&
3382                                             Person::players[i]->howactive < typedead1 &&
3383                                             distance < 1.5 * sq(Person::players[k]->scale * 5) &&
3384                                             !Person::players[i]->skeleton.free &&
3385                                             Person::players[i]->animTarget != getupfrombackanim &&
3386                                             Person::players[i]->animTarget != getupfromfrontanim &&
3387                                             (Person::players[i]->stunned > 0 && Person::players[k]->madskills ||
3388                                              Person::players[i]->surprised > 0 ||
3389                                              Person::players[i]->aitype == passivetype ||
3390                                              attackweapon && Person::players[i]->stunned > 0) &&
3391                                             normaldotproduct(Person::players[i]->facing, Person::players[i]->coords - Person::players[k]->coords) > 0) {
3392                                         //sneakattack
3393                                         if (!attackweapon) {
3394                                             Person::players[k]->animCurrent = sneakattackanim;
3395                                             Person::players[k]->animTarget = sneakattackanim;
3396                                             Person::players[i]->animCurrent = sneakattackedanim;
3397                                             Person::players[i]->animTarget = sneakattackedanim;
3398                                             Person::players[k]->oldcoords = Person::players[k]->coords;
3399                                             Person::players[k]->coords = Person::players[i]->coords;
3400                                         }
3401                                         //knifesneakattack
3402                                         if (attackweapon == knife) {
3403                                             Person::players[k]->animCurrent = knifesneakattackanim;
3404                                             Person::players[k]->animTarget = knifesneakattackanim;
3405                                             Person::players[i]->animCurrent = knifesneakattackedanim;
3406                                             Person::players[i]->animTarget = knifesneakattackedanim;
3407                                             Person::players[i]->oldcoords = Person::players[i]->coords;
3408                                             Person::players[i]->coords = Person::players[k]->coords;
3409                                         }
3410                                         //swordsneakattack
3411                                         if (attackweapon == sword) {
3412                                             Person::players[k]->animCurrent = swordsneakattackanim;
3413                                             Person::players[k]->animTarget = swordsneakattackanim;
3414                                             Person::players[i]->animCurrent = swordsneakattackedanim;
3415                                             Person::players[i]->animTarget = swordsneakattackedanim;
3416                                             Person::players[i]->oldcoords = Person::players[i]->coords;
3417                                             Person::players[i]->coords = Person::players[k]->coords;
3418                                         }
3419                                         if (attackweapon != staff) {
3420                                             Person::players[k]->victim = Person::players[i];
3421                                             Person::players[k]->hasvictim = 1;
3422                                             Person::players[i]->targettilt2 = 0;
3423                                             Person::players[i]->frameTarget = 1;
3424                                             Person::players[i]->frameCurrent = 0;
3425                                             Person::players[i]->target = 0;
3426                                             Person::players[i]->velocity = 0;
3427                                             Person::players[k]->targettilt2 = Person::players[i]->targettilt2;
3428                                             Person::players[k]->frameCurrent = Person::players[i]->frameCurrent;
3429                                             Person::players[k]->frameTarget = Person::players[i]->frameTarget;
3430                                             Person::players[k]->target = Person::players[i]->target;
3431                                             Person::players[k]->velocity = 0;
3432                                             Person::players[k]->targetyaw = Person::players[i]->yaw;
3433                                             Person::players[k]->yaw = Person::players[i]->yaw;
3434                                             Person::players[i]->targetyaw = Person::players[i]->yaw;
3435                                         }
3436                                     }
3437                                     if (animation[Person::players[k]->animTarget].attack == normalattack &&
3438                                             Person::players[k]->victim == Person::players[i] &&
3439                                             (!Person::players[i]->skeleton.free)) {
3440                                         oldattackkey = 1;
3441                                         Person::players[k]->frameTarget = 0;
3442                                         Person::players[k]->target = 0;
3443
3444                                         Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
3445                                         Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
3446                                         Person::players[k]->lastattack3 = Person::players[k]->lastattack2;
3447                                         Person::players[k]->lastattack2 = Person::players[k]->lastattack;
3448                                         Person::players[k]->lastattack = Person::players[k]->animTarget;
3449                                     }
3450                                     if (Person::players[k]->animTarget == knifefollowanim &&
3451                                             Person::players[k]->victim == Person::players[i]) {
3452                                         oldattackkey = 1;
3453                                         Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
3454                                         Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
3455                                         Person::players[k]->victim = Person::players[i];
3456                                         Person::players[k]->hasvictim = 1;
3457                                         Person::players[i]->animTarget = knifefollowedanim;
3458                                         Person::players[i]->animCurrent = knifefollowedanim;
3459                                         Person::players[i]->targettilt2 = 0;
3460                                         Person::players[i]->targettilt2 = Person::players[k]->targettilt2;
3461                                         Person::players[i]->frameTarget = 1;
3462                                         Person::players[i]->frameCurrent = 0;
3463                                         Person::players[i]->target = 0;
3464                                         Person::players[i]->velocity = 0;
3465                                         Person::players[k]->animCurrent = knifefollowanim;
3466                                         Person::players[k]->animTarget = knifefollowanim;
3467                                         Person::players[k]->targettilt2 = Person::players[i]->targettilt2;
3468                                         Person::players[k]->frameCurrent = Person::players[i]->frameCurrent;
3469                                         Person::players[k]->frameTarget = Person::players[i]->frameTarget;
3470                                         Person::players[k]->target = Person::players[i]->target;
3471                                         Person::players[k]->velocity = 0;
3472                                         Person::players[k]->oldcoords = Person::players[k]->coords;
3473                                         Person::players[i]->coords = Person::players[k]->coords;
3474                                         Person::players[i]->targetyaw = Person::players[k]->targetyaw;
3475                                         Person::players[i]->yaw = Person::players[k]->targetyaw;
3476                                         Person::players[k]->yaw = Person::players[k]->targetyaw;
3477                                         Person::players[i]->yaw = Person::players[k]->targetyaw;
3478                                     }
3479                                 }
3480                         }
3481                     const bool hasstaff = attackweapon == staff;
3482                     if (k == 0 && Person::players.size() > 1)
3483                         for (unsigned i = 0; i < Person::players.size(); i++) {
3484                             if (i == k)
3485                                 continue;
3486                             if ((playerrealattackkeydown || Person::players[i]->dead || !hasstaff) &&
3487                                     animation[Person::players[k]->animTarget].attack == neutral) {
3488                                 const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
3489                                 if (!Person::players[i]->dead || !realthreat || (!attackweapon && Person::players[k]->crouchkeydown))
3490                                     if (Person::players[i]->skeleton.free)
3491                                         if (distance < 3.5 * sq(Person::players[k]->scale * 5) &&
3492                                                 (Person::players[i]->dead ||
3493                                                  Person::players[i]->skeleton.longdead > 1000 ||
3494                                                  Person::players[k]->isRun() ||
3495                                                  hasstaff ||
3496                                                  (attackweapon &&
3497                                                   (Person::players[i]->skeleton.longdead > 2000 ||
3498                                                    Person::players[i]->damage > Person::players[i]->damagetolerance / 8 ||
3499                                                    Person::players[i]->bloodloss > Person::players[i]->damagetolerance / 2) &&
3500                                                   distance < 1.5 * sq(Person::players[k]->scale * 5)))) {
3501                                             Person::players[k]->victim = Person::players[i];
3502                                             Person::players[k]->hasvictim = 1;
3503                                             if (attackweapon && tutoriallevel != 1) {
3504                                                 //crouchstab
3505                                                 if (Person::players[k]->crouchkeydown && attackweapon == knife && distance < 1.5 * sq(Person::players[k]->scale * 5))
3506                                                     Person::players[k]->animTarget = crouchstabanim;
3507                                                 //swordgroundstab
3508                                                 if (Person::players[k]->crouchkeydown && distance < 1.5 * sq(Person::players[k]->scale * 5) && attackweapon == sword)
3509                                                     Person::players[k]->animTarget = swordgroundstabanim;
3510                                                 //staffgroundsmash
3511                                                 if (distance < 3.5 * sq(Person::players[k]->scale * 5) && attackweapon == staff)
3512                                                     Person::players[k]->animTarget = staffgroundsmashanim;
3513                                             }
3514                                             if (distance < 2.5 &&
3515                                                     Person::players[k]->crouchkeydown &&
3516                                                     Person::players[k]->animTarget != crouchstabanim &&
3517                                                     !attackweapon &&
3518                                                     Person::players[i]->dead &&
3519                                                     Person::players[i]->skeleton.free &&
3520                                                     Person::players[i]->skeleton.longdead > 1000) {
3521                                                 Person::players[k]->animTarget = killanim;
3522                                                 //TODO: refactor this out, what does it do?
3523                                                 for (int j = 0; j < terrain.numdecals; j++) {
3524                                                     if ((terrain.decaltype[j] == blooddecal || terrain.decaltype[j] == blooddecalslow) &&
3525                                                             terrain.decalalivetime[j] < 2)
3526                                                         terrain.DeleteDecal(j);
3527                                                 }
3528                                                 for (int l = 0; l < objects.numobjects; l++) {
3529                                                     if (objects.model[l].type == decalstype)
3530                                                         for (int j = 0; j < objects.model[l].numdecals; j++) {
3531                                                             if ((objects.model[l].decaltype[j] == blooddecal ||
3532                                                                     objects.model[l].decaltype[j] == blooddecalslow) &&
3533                                                                     objects.model[l].decalalivetime[j] < 2)
3534                                                                 objects.model[l].DeleteDecal(j);
3535                                                         }
3536                                                 }
3537                                             }
3538                                             if (!Person::players[i]->dead || musictype != 2)
3539                                                 if (distance < 3.5 &&
3540                                                         (Person::players[k]->isRun() || Person::players[k]->isIdle() && Person::players[k]->attackkeydown) &&
3541                                                         Person::players[k]->staggerdelay <= 0 &&
3542                                                         (Person::players[i]->dead ||
3543                                                          Person::players[i]->skeleton.longdead < 300 &&
3544                                                          Person::players[k]->lastattack != spinkickanim &&
3545                                                          Person::players[i]->skeleton.free) &&
3546                                                         (!Person::players[i]->dead || musictype != stream_fighttheme)) {
3547                                                     Person::players[k]->animTarget = dropkickanim;
3548                                                     for (int j = 0; j < terrain.numdecals; j++) {
3549                                                         if ((terrain.decaltype[j] == blooddecal || terrain.decaltype[j] == blooddecalslow) &&
3550                                                                 terrain.decalalivetime[j] < 2) {
3551                                                             terrain.DeleteDecal(j);
3552                                                         }
3553                                                     }
3554                                                     for (int l = 0; l < objects.numobjects; l++) {
3555                                                         if (objects.model[l].type == decalstype)
3556                                                             for (int j = 0; j < objects.model[l].numdecals; j++) {
3557                                                                 if ((objects.model[l].decaltype[j] == blooddecal ||
3558                                                                         objects.model[l].decaltype[j] == blooddecalslow) &&
3559                                                                         objects.model[l].decalalivetime[j] < 2) {
3560                                                                     objects.model[l].DeleteDecal(j);
3561                                                                 }
3562                                                             }
3563                                                     }
3564                                                 }
3565                                         }
3566                                 if (animation[Person::players[k]->animTarget].attack == normalattack &&
3567                                         Person::players[k]->victim == Person::players[i] &&
3568                                         (!Person::players[i]->skeleton.free ||
3569                                          Person::players[k]->animTarget == killanim ||
3570                                          Person::players[k]->animTarget == crouchstabanim ||
3571                                          Person::players[k]->animTarget == swordgroundstabanim ||
3572                                          Person::players[k]->animTarget == staffgroundsmashanim ||
3573                                          Person::players[k]->animTarget == dropkickanim)) {
3574                                     oldattackkey = 1;
3575                                     Person::players[k]->frameTarget = 0;
3576                                     Person::players[k]->target = 0;
3577
3578                                     XYZ targetpoint = Person::players[i]->coords;
3579                                     if (Person::players[k]->animTarget == crouchstabanim ||
3580                                             Person::players[k]->animTarget == swordgroundstabanim ||
3581                                             Person::players[k]->animTarget == staffgroundsmashanim) {
3582                                         targetpoint += (Person::players[i]->jointPos(abdomen) +
3583                                                         Person::players[i]->jointPos(neck)) / 2 *
3584                                                        Person::players[i]->scale;
3585                                     }
3586                                     Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, targetpoint);
3587                                     Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, targetpoint);
3588
3589                                     if (Person::players[k]->animTarget == crouchstabanim || Person::players[k]->animTarget == swordgroundstabanim) {
3590                                         Person::players[k]->targetyaw += (float)(abs(Random() % 100) - 50) / 4;
3591                                     }
3592
3593                                     if (Person::players[k]->animTarget == staffgroundsmashanim)
3594                                         Person::players[k]->targettilt2 += 10;
3595
3596                                     Person::players[k]->lastattack3 = Person::players[k]->lastattack2;
3597                                     Person::players[k]->lastattack2 = Person::players[k]->lastattack;
3598                                     Person::players[k]->lastattack = Person::players[k]->animTarget;
3599
3600                                     if (Person::players[k]->animTarget == swordgroundstabanim) {
3601                                         Person::players[k]->targetyaw += 30;
3602                                     }
3603                                 }
3604                             }
3605                         }
3606                     if (!Person::players[k]->hasvictim) {
3607                         //find victim
3608                         for (unsigned i = 0; i < Person::players.size(); i++) {
3609                             if (i == k || !(i == 0 || k == 0))
3610                                 continue;
3611                             if (!Person::players[i]->skeleton.free) {
3612                                 if (Person::players[k]->hasvictim) {
3613                                     if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) <
3614                                             distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords))
3615                                         Person::players[k]->victim = Person::players[i];
3616                                 } else {
3617                                     Person::players[k]->victim = Person::players[i];
3618                                     Person::players[k]->hasvictim = 1;
3619                                 }
3620                             }
3621                         }
3622                     }
3623                     if (Person::players[k]->aitype == playercontrolled)
3624                         //rabbit kick
3625                         if (Person::players[k]->attackkeydown &&
3626                                 Person::players[k]->isRun() &&
3627                                 Person::players[k]->wasRun() &&
3628                                 ((Person::players[k]->hasvictim &&
3629                                   distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords) < 12 * sq(Person::players[k]->scale * 5) &&
3630                                   distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords) > 7 * sq(Person::players[k]->scale * 5) &&
3631                                   !Person::players[k]->victim->skeleton.free &&
3632                                   Person::players[k]->victim->animTarget != getupfrombackanim &&
3633                                   Person::players[k]->victim->animTarget != getupfromfrontanim &&
3634                                   animation[Person::players[k]->victim->animTarget].height != lowheight &&
3635                                   Person::players[k]->aitype != playercontrolled && //wat???
3636                                   normaldotproduct(Person::players[k]->facing, Person::players[k]->victim->coords - Person::players[k]->coords) > 0 &&
3637                                   Person::players[k]->rabbitkickenabled) ||
3638                                  Person::players[k]->jumpkeydown)) {
3639                             oldattackkey = 1;
3640                             Person::players[k]->setAnimation(rabbitkickanim);
3641                         }
3642                     //update counts
3643                     if (animation[Person::players[k]->animTarget].attack && k == 0) {
3644                         numattacks++;
3645                         switch (attackweapon) {
3646                         case 0:
3647                             numunarmedattack++;
3648                             break;
3649                         case knife:
3650                             numknifeattack++;
3651                             break;
3652                         case sword:
3653                             numswordattack++;
3654                             break;
3655                         case staff:
3656                             numstaffattack++;
3657                             break;
3658                         }
3659                     }
3660                 }
3661             }
3662         }
3663     }
3664 }
3665
3666 void doPlayerCollisions()
3667 {
3668     static XYZ rotatetarget;
3669     static float collisionradius;
3670     if (Person::players.size() > 1)
3671         for (unsigned k = 0; k < Person::players.size(); k++)
3672             for (unsigned i = k + 1; i < Person::players.size(); i++) {
3673                 //neither player is part of a reversal
3674                 if ((animation[Person::players[i]->animTarget].attack != reversed &&
3675                         animation[Person::players[i]->animTarget].attack != reversal &&
3676                         animation[Person::players[k]->animTarget].attack != reversed &&
3677                         animation[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
3678                     if ((animation[Person::players[i]->animCurrent].attack != reversed &&
3679                             animation[Person::players[i]->animCurrent].attack != reversal &&
3680                             animation[Person::players[k]->animCurrent].attack != reversed &&
3681                             animation[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
3682                         //neither is sleeping
3683                         if (Person::players[i]->howactive <= typesleeping && Person::players[k]->howactive <= typesleeping)
3684                             if (Person::players[i]->howactive != typesittingwall && Person::players[k]->howactive != typesittingwall)
3685                                 //in same patch, neither is climbing
3686                                 if (Person::players[i]->whichpatchx == Person::players[k]->whichpatchx &&
3687                                         Person::players[i]->whichpatchz == Person::players[k]->whichpatchz &&
3688                                         Person::players[k]->skeleton.oldfree == Person::players[k]->skeleton.free &&
3689                                         Person::players[i]->skeleton.oldfree == Person::players[i]->skeleton.free &&
3690                                         Person::players[i]->animTarget != climbanim &&
3691                                         Person::players[i]->animTarget != hanganim &&
3692                                         Person::players[k]->animTarget != climbanim &&
3693                                         Person::players[k]->animTarget != hanganim)
3694                                     //players are close (bounding box test)
3695                                     if (Person::players[i]->coords.y > Person::players[k]->coords.y - 3)
3696                                         if (Person::players[i]->coords.y < Person::players[k]->coords.y + 3)
3697                                             if (Person::players[i]->coords.x > Person::players[k]->coords.x - 3)
3698                                                 if (Person::players[i]->coords.x < Person::players[k]->coords.x + 3)
3699                                                     if (Person::players[i]->coords.z > Person::players[k]->coords.z - 3)
3700                                                         if (Person::players[i]->coords.z < Person::players[k]->coords.z + 3) {
3701                                                             //spread fire from player to player
3702                                                             if (distsq(&Person::players[i]->coords, &Person::players[k]->coords)
3703                                                                     < 3 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
3704                                                                 if (Person::players[i]->onfire || Person::players[k]->onfire) {
3705                                                                     if (!Person::players[i]->onfire)
3706                                                                         Person::players[i]->CatchFire();
3707                                                                     if (!Person::players[k]->onfire)
3708                                                                         Person::players[k]->CatchFire();
3709                                                                 }
3710                                                             }
3711
3712                                                             XYZ tempcoords1 = Person::players[i]->coords;
3713                                                             XYZ tempcoords2 = Person::players[k]->coords;
3714                                                             if (!Person::players[i]->skeleton.oldfree)
3715                                                                 tempcoords1.y += Person::players[i]->jointPos(abdomen).y * Person::players[i]->scale;
3716                                                             if (!Person::players[k]->skeleton.oldfree)
3717                                                                 tempcoords2.y += Person::players[k]->jointPos(abdomen).y * Person::players[k]->scale;
3718                                                             collisionradius = 1.2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
3719                                                             if (Person::players[0]->hasvictim)
3720                                                                 if (Person::players[0]->animTarget == rabbitkickanim && (k == 0 || i == 0) && !Person::players[0]->victim->skeleton.free)
3721                                                                     collisionradius = 3;
3722                                                             if ((!Person::players[i]->skeleton.oldfree || !Person::players[k]->skeleton.oldfree) &&
3723                                                                     (distsq(&tempcoords1, &tempcoords2) < collisionradius ||
3724                                                                      distsq(&Person::players[i]->coords, &Person::players[k]->coords) < collisionradius)) {
3725                                                                 //jump down on a dead body
3726                                                                 if (k == 0 || i == 0) {
3727                                                                     int l = i ? i : k;
3728                                                                     if (Person::players[0]->animTarget == jumpdownanim &&
3729                                                                             !Person::players[0]->skeleton.oldfree &&
3730                                                                             !Person::players[0]->skeleton.free &&
3731                                                                             Person::players[l]->skeleton.oldfree &&
3732                                                                             Person::players[l]->skeleton.free &&
3733                                                                             Person::players[l]->dead &&
3734                                                                             Person::players[0]->lastcollide <= 0 &&
3735                                                                             fabs(Person::players[l]->coords.y - Person::players[0]->coords.y) < .2 &&
3736                                                                             distsq(&Person::players[0]->coords, &Person::players[l]->coords) < .7 * sq((Person::players[l]->scale + Person::players[0]->scale) * 2.5)) {
3737                                                                         Person::players[0]->coords.y = Person::players[l]->coords.y;
3738                                                                         Person::players[l]->velocity = Person::players[0]->velocity;
3739                                                                         Person::players[l]->skeleton.free = 0;
3740                                                                         Person::players[l]->yaw = 0;
3741                                                                         Person::players[l]->RagDoll(0);
3742                                                                         Person::players[l]->DoDamage(20);
3743                                                                         camerashake += .3;
3744                                                                         Person::players[l]->skeleton.longdead = 0;
3745                                                                         Person::players[0]->lastcollide = 1;
3746                                                                     }
3747                                                                 }
3748
3749                                                                 if (     (Person::players[i]->skeleton.oldfree == 1 && findLengthfast(&Person::players[i]->velocity) > 1) ||
3750                                                                          (Person::players[k]->skeleton.oldfree == 1 && findLengthfast(&Person::players[k]->velocity) > 1) ||
3751                                                                          (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0)) {
3752                                                                     rotatetarget = Person::players[k]->velocity - Person::players[i]->velocity;
3753                                                                     if ((Person::players[i]->animTarget != getupfrombackanim && Person::players[i]->animTarget != getupfromfrontanim ||
3754                                                                             Person::players[i]->skeleton.free) &&
3755                                                                             (Person::players[k]->animTarget != getupfrombackanim && Person::players[k]->animTarget != getupfromfrontanim ||
3756                                                                              Person::players[k]->skeleton.free))
3757                                                                         if ((((k != 0 && findLengthfast(&rotatetarget) > 150 ||
3758                                                                                 k == 0 && findLengthfast(&rotatetarget) > 50 && Person::players[0]->rabbitkickragdoll) &&
3759                                                                                 normaldotproduct(rotatetarget, Person::players[k]->coords - Person::players[i]->coords) > 0) &&
3760                                                                                 (k == 0 ||
3761                                                                                  k != 0 && Person::players[i]->skeleton.oldfree == 1 && animation[Person::players[k]->animCurrent].attack == neutral ||
3762                                                                                  /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && animation[Person::players[i]->animCurrent].attack == neutral)) ||
3763                                                                                 (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) &&
3764                                                                                 (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) &&
3765                                                                                 k == 0 && !Person::players[i]->skeleton.oldfree && !Person::players[k]->skeleton.oldfree) {
3766                                                                             //If hit by body
3767                                                                             if (     (i != 0 || Person::players[i]->skeleton.free) &&
3768                                                                                      (k != 0 || Person::players[k]->skeleton.free) ||
3769                                                                                      (animation[Person::players[i]->animTarget].height == highheight &&
3770                                                                                       animation[Person::players[k]->animTarget].height == highheight)) {
3771                                                                                 if (tutoriallevel != 1) {
3772                                                                                     emit_sound_at(heavyimpactsound, Person::players[i]->coords);
3773                                                                                 }
3774
3775                                                                                 Person::players[i]->RagDoll(0);
3776                                                                                 if (Person::players[i]->damage > Person::players[i]->damagetolerance - findLengthfast(&rotatetarget) / 4 && !Person::players[i]->dead) {
3777                                                                                     award_bonus(0, aimbonus);
3778                                                                                 }
3779                                                                                 Person::players[i]->DoDamage(findLengthfast(&rotatetarget) / 4);
3780                                                                                 Person::players[k]->RagDoll(0);
3781                                                                                 if (Person::players[k]->damage > Person::players[k]->damagetolerance - findLengthfast(&rotatetarget) / 4 && !Person::players[k]->dead) {
3782                                                                                     award_bonus(0, aimbonus); // Huh, again?
3783                                                                                 }
3784                                                                                 Person::players[k]->DoDamage(findLengthfast(&rotatetarget) / 4);
3785
3786                                                                                 for (int j = 0; j < Person::players[i]->skeleton.num_joints; j++) {
3787                                                                                     Person::players[i]->skeleton.joints[j].velocity = Person::players[i]->skeleton.joints[j].velocity / 5 + Person::players[k]->velocity;
3788                                                                                 }
3789                                                                                 for (int j = 0; j < Person::players[k]->skeleton.num_joints; j++) {
3790                                                                                     Person::players[k]->skeleton.joints[j].velocity = Person::players[k]->skeleton.joints[j].velocity / 5 + Person::players[i]->velocity;
3791                                                                                 }
3792
3793                                                                             }
3794                                                                         }
3795                                                                     if (     (animation[Person::players[i]->animTarget].attack == neutral ||
3796                                                                               animation[Person::players[i]->animTarget].attack == normalattack) &&
3797                                                                              (animation[Person::players[k]->animTarget].attack == neutral ||
3798                                                                               animation[Person::players[k]->animTarget].attack == normalattack)) {
3799                                                                         //If bumped
3800                                                                         if (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0) {
3801                                                                             if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < .5 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
3802                                                                                 rotatetarget = Person::players[k]->coords - Person::players[i]->coords;
3803                                                                                 Normalise(&rotatetarget);
3804                                                                                 Person::players[k]->coords = (Person::players[k]->coords + Person::players[i]->coords) / 2;
3805                                                                                 Person::players[i]->coords = Person::players[k]->coords - rotatetarget * fast_sqrt(.6) / 2
3806                                                                                                    * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
3807                                                                                 Person::players[k]->coords += rotatetarget * fast_sqrt(.6) / 2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
3808                                                                                 if (Person::players[k]->howactive == typeactive || hostile)
3809                                                                                     if (Person::players[k]->isIdle()) {
3810                                                                                         if (Person::players[k]->howactive < typesleeping)
3811                                                                                             Person::players[k]->setAnimation(Person::players[k]->getStop());
3812                                                                                         else if (Person::players[k]->howactive == typesleeping)
3813                                                                                             Person::players[k]->setAnimation(getupfromfrontanim);
3814                                                                                         if (!editorenabled)
3815                                                                                             Person::players[k]->howactive = typeactive;
3816                                                                                     }
3817                                                                                 if (Person::players[i]->howactive == typeactive || hostile)
3818                                                                                     if (Person::players[i]->isIdle()) {
3819                                                                                         if (Person::players[i]->howactive < typesleeping)
3820                                                                                             Person::players[i]->setAnimation(Person::players[k]->getStop());
3821                                                                                         else
3822                                                                                             Person::players[i]->setAnimation(getupfromfrontanim);
3823                                                                                         if (!editorenabled)
3824                                                                                             Person::players[i]->howactive = typeactive;
3825                                                                                     }
3826                                                                             }
3827                                                                             //jump down on player
3828                                                                             if (hostile) {
3829                                                                                 if (k == 0 && i != 0 && Person::players[k]->animTarget == jumpdownanim &&
3830                                                                                         !Person::players[i]->isCrouch() &&
3831                                                                                         Person::players[i]->animTarget != rollanim &&
3832                                                                                         !Person::players[k]->skeleton.oldfree && !
3833                                                                                         Person::players[k]->skeleton.free &&
3834                                                                                         Person::players[k]->lastcollide <= 0 &&
3835                                                                                         Person::players[k]->velocity.y < -10) {
3836                                                                                     Person::players[i]->velocity = Person::players[k]->velocity;
3837                                                                                     Person::players[k]->velocity = Person::players[k]->velocity * -.5;
3838                                                                                     Person::players[k]->velocity.y = Person::players[i]->velocity.y;
3839                                                                                     Person::players[i]->DoDamage(20);
3840                                                                                     Person::players[i]->RagDoll(0);
3841                                                                                     Person::players[k]->lastcollide = 1;
3842                                                                                     award_bonus(k, AboveBonus);
3843                                                                                 }
3844                                                                                 if (i == 0 && k != 0 && Person::players[i]->animTarget == jumpdownanim &&
3845                                                                                         !Person::players[k]->isCrouch() &&
3846                                                                                         Person::players[k]->animTarget != rollanim &&
3847                                                                                         !Person::players[i]->skeleton.oldfree &&
3848                                                                                         !Person::players[i]->skeleton.free &&
3849                                                                                         Person::players[i]->lastcollide <= 0 &&
3850                                                                                         Person::players[i]->velocity.y < -10) {
3851                                                                                     Person::players[k]->velocity = Person::players[i]->velocity;
3852                                                                                     Person::players[i]->velocity = Person::players[i]->velocity * -.3;
3853                                                                                     Person::players[i]->velocity.y = Person::players[k]->velocity.y;
3854                                                                                     Person::players[k]->DoDamage(20);
3855                                                                                     Person::players[k]->RagDoll(0);
3856                                                                                     Person::players[i]->lastcollide = 1;
3857                                                                                     award_bonus(i, AboveBonus);
3858                                                                                 }
3859                                                                             }
3860                                                                         }
3861                                                                     }
3862                                                                 }
3863                                                                 Person::players[i]->CheckKick();
3864                                                                 Person::players[k]->CheckKick();
3865                                                             }
3866                                                         }
3867             }
3868 }
3869
3870 void doAI(unsigned i)
3871 {
3872     static bool connected;
3873     if (Person::players[i]->aitype != playercontrolled && indialogue == -1) {
3874         Person::players[i]->jumpclimb = 0;
3875         //disable movement in editor
3876         if (editorenabled)
3877             Person::players[i]->stunned = 1;
3878
3879         Person::players[i]->pause = 0;
3880         if (distsqflat(&Person::players[0]->coords, &Person::players[i]->coords) < 30 &&
3881                 Person::players[0]->coords.y > Person::players[i]->coords.y + 2 &&
3882                 !Person::players[0]->onterrain)
3883             Person::players[i]->pause = 1;
3884
3885         //pathfinding
3886         if (Person::players[i]->aitype == pathfindtype) {
3887             if (Person::players[i]->finalpathfindpoint == -1) {
3888                 float closestdistance;
3889                 float tempdist;
3890                 int closest;
3891                 XYZ colpoint;
3892                 closest = -1;
3893                 closestdistance = -1;
3894                 for (int j = 0; j < numpathpoints; j++)
3895                     if (closest == -1 || distsq(&Person::players[i]->finalfinaltarget, &pathpoint[j]) < closestdistance) {
3896                         closestdistance = distsq(&Person::players[i]->finalfinaltarget, &pathpoint[j]);
3897                         closest = j;
3898                         Person::players[i]->finaltarget = pathpoint[j];
3899                     }
3900                 Person::players[i]->finalpathfindpoint = closest;
3901                 for (int j = 0; j < numpathpoints; j++)
3902                     for (int k = 0; k < numpathpointconnect[j]; k++) {
3903                         DistancePointLine(&Person::players[i]->finalfinaltarget, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist, &colpoint );
3904                         if (sq(tempdist) < closestdistance)
3905                             if (findDistance(&colpoint, &pathpoint[j]) + findDistance(&colpoint, &pathpoint[pathpointconnect[j][k]]) <
3906                                     findDistance(&pathpoint[j], &pathpoint[pathpointconnect[j][k]]) + .1) {
3907                                 closestdistance = sq(tempdist);
3908                                 closest = j;
3909                                 Person::players[i]->finaltarget = colpoint;
3910                             }
3911                     }
3912                 Person::players[i]->finalpathfindpoint = closest;
3913
3914             }
3915             if (Person::players[i]->targetpathfindpoint == -1) {
3916                 float closestdistance;
3917                 float tempdist;
3918                 int closest;
3919                 XYZ colpoint;
3920                 closest = -1;
3921                 closestdistance = -1;
3922                 if (Person::players[i]->lastpathfindpoint == -1) {
3923                     for (int j = 0; j < numpathpoints; j++) {
3924                         if (j != Person::players[i]->lastpathfindpoint)
3925                             if (closest == -1 || (distsq(&Person::players[i]->coords, &pathpoint[j]) < closestdistance)) {
3926                                 closestdistance = distsq(&Person::players[i]->coords, &pathpoint[j]);
3927                                 closest = j;
3928                             }
3929                     }
3930                     Person::players[i]->targetpathfindpoint = closest;
3931                     for (int j = 0; j < numpathpoints; j++)
3932                         if (j != Person::players[i]->lastpathfindpoint)
3933                             for (int k = 0; k < numpathpointconnect[j]; k++) {
3934                                 DistancePointLine(&Person::players[i]->coords, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist, &colpoint );
3935                                 if (sq(tempdist) < closestdistance) {
3936                                     if (findDistance(&colpoint, &pathpoint[j]) + findDistance(&colpoint, &pathpoint[pathpointconnect[j][k]]) <
3937                                             findDistance(&pathpoint[j], &pathpoint[pathpointconnect[j][k]]) + .1) {
3938                                         closestdistance = sq(tempdist);
3939                                         closest = j;
3940                                     }
3941                                 }
3942                             }
3943                     Person::players[i]->targetpathfindpoint = closest;
3944                 } else {
3945                     for (int j = 0; j < numpathpoints; j++)
3946                         if (j != Person::players[i]->lastpathfindpoint &&
3947                                 j != Person::players[i]->lastpathfindpoint2 &&
3948                                 j != Person::players[i]->lastpathfindpoint3 &&
3949                                 j != Person::players[i]->lastpathfindpoint4) {
3950                             connected = 0;
3951                             if (numpathpointconnect[j])
3952                                 for (int k = 0; k < numpathpointconnect[j]; k++)
3953                                     if (pathpointconnect[j][k] == Person::players[i]->lastpathfindpoint)
3954                                         connected = 1;
3955                             if (!connected)
3956                                 if (numpathpointconnect[Person::players[i]->lastpathfindpoint])
3957                                     for (int k = 0; k < numpathpointconnect[Person::players[i]->lastpathfindpoint]; k++)
3958                                         if (pathpointconnect[Person::players[i]->lastpathfindpoint][k] == j)
3959                                             connected = 1;
3960                             if (connected) {
3961                                 tempdist = findPathDist(j, Person::players[i]->finalpathfindpoint);
3962                                 if (closest == -1 || tempdist < closestdistance) {
3963                                     closestdistance = tempdist;
3964                                     closest = j;
3965                                 }
3966                             }
3967                         }
3968                     Person::players[i]->targetpathfindpoint = closest;
3969                 }
3970             }
3971             Person::players[i]->losupdatedelay -= multiplier;
3972
3973             Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, pathpoint[Person::players[i]->targetpathfindpoint]);
3974             Person::players[i]->lookyaw = Person::players[i]->targetyaw;
3975
3976             //reached target point
3977             if (distsqflat(&Person::players[i]->coords, &pathpoint[Person::players[i]->targetpathfindpoint]) < .6) {
3978                 Person::players[i]->lastpathfindpoint4 = Person::players[i]->lastpathfindpoint3;
3979                 Person::players[i]->lastpathfindpoint3 = Person::players[i]->lastpathfindpoint2;
3980                 Person::players[i]->lastpathfindpoint2 = Person::players[i]->lastpathfindpoint;
3981                 Person::players[i]->lastpathfindpoint = Person::players[i]->targetpathfindpoint;
3982                 if (Person::players[i]->lastpathfindpoint2 == -1)
3983                     Person::players[i]->lastpathfindpoint2 = Person::players[i]->lastpathfindpoint;
3984                 if (Person::players[i]->lastpathfindpoint3 == -1)
3985                     Person::players[i]->lastpathfindpoint3 = Person::players[i]->lastpathfindpoint2;
3986                 if (Person::players[i]->lastpathfindpoint4 == -1)
3987                     Person::players[i]->lastpathfindpoint4 = Person::players[i]->lastpathfindpoint3;
3988                 Person::players[i]->targetpathfindpoint = -1;
3989             }
3990             if (     distsqflat(&Person::players[i]->coords, &Person::players[i]->finalfinaltarget) <
3991                      distsqflat(&Person::players[i]->coords, &Person::players[i]->finaltarget) ||
3992                      distsqflat(&Person::players[i]->coords, &Person::players[i]->finaltarget) < .6 * sq(Person::players[i]->scale * 5) ||
3993                      Person::players[i]->lastpathfindpoint == Person::players[i]->finalpathfindpoint) {
3994                 Person::players[i]->aitype = passivetype;
3995             }
3996
3997             Person::players[i]->forwardkeydown = 1;
3998             Person::players[i]->leftkeydown = 0;
3999             Person::players[i]->backkeydown = 0;
4000             Person::players[i]->rightkeydown = 0;
4001             Person::players[i]->crouchkeydown = 0;
4002             Person::players[i]->attackkeydown = 0;
4003             Person::players[i]->throwkeydown = 0;
4004
4005             if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8)
4006                 Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4007
4008             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4009                 Person::players[i]->jumpkeydown = 0;
4010             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
4011                 Person::players[i]->jumpkeydown = 1;
4012
4013             if ((tutoriallevel != 1 || cananger) &&
4014                     hostile &&
4015                     !Person::players[0]->dead &&
4016                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
4017                     Person::players[i]->occluded < 25) {
4018                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
4019                         animation[Person::players[0]->animTarget].height != lowheight &&
4020                         !editorenabled &&
4021                         (Person::players[0]->coords.y < Person::players[i]->coords.y + 5 || Person::players[0]->onterrain))
4022                     Person::players[i]->aitype = attacktypecutoff;
4023                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
4024                         animation[Person::players[0]->animTarget].height == highheight &&
4025                         !editorenabled)
4026                     Person::players[i]->aitype = attacktypecutoff;
4027
4028                 if (Person::players[i]->losupdatedelay < 0 && !editorenabled && Person::players[i]->occluded < 2) {
4029                     Person::players[i]->losupdatedelay = .2;
4030                     for (unsigned j = 0; j < Person::players.size(); j++)
4031                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype)
4032                             if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
4033                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
4034                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
4035                                         if (Person::players[j]->coords.y < Person::players[i]->coords.y + 5 || Person::players[j]->onterrain)
4036                                             if (!Person::players[j]->isWallJump() && -1 == checkcollide(
4037                                                         DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)
4038                                                         *Person::players[i]->scale + Person::players[i]->coords,
4039                                                         DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0)
4040                                                         *Person::players[j]->scale + Person::players[j]->coords) ||
4041                                                     (Person::players[j]->animTarget == hanganim &&
4042                                                      normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
4043                                                 Person::players[i]->aitype = searchtype;
4044                                                 Person::players[i]->lastchecktime = 12;
4045                                                 Person::players[i]->lastseen = Person::players[j]->coords;
4046                                                 Person::players[i]->lastseentime = 12;
4047                                             }
4048                 }
4049             }
4050             if (Person::players[i]->aitype == attacktypecutoff && musictype != 2)
4051                 if (Person::players[i]->creature != wolftype) {
4052                     Person::players[i]->stunned = .6;
4053                     Person::players[i]->surprised = .6;
4054                 }
4055         }
4056
4057         if (Person::players[i]->aitype != passivetype && leveltime > .5)
4058             Person::players[i]->howactive = typeactive;
4059
4060         if (Person::players[i]->aitype == passivetype) {
4061             Person::players[i]->aiupdatedelay -= multiplier;
4062             Person::players[i]->losupdatedelay -= multiplier;
4063             Person::players[i]->lastseentime += multiplier;
4064             Person::players[i]->pausetime -= multiplier;
4065             if (Person::players[i]->lastseentime > 1)
4066                 Person::players[i]->lastseentime = 1;
4067
4068             if (Person::players[i]->aiupdatedelay < 0) {
4069                 if (Person::players[i]->numwaypoints > 1 && Person::players[i]->howactive == typeactive && Person::players[i]->pausetime <= 0) {
4070                     Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[i]->waypoints[Person::players[i]->waypoint]);
4071                     Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4072                     Person::players[i]->aiupdatedelay = .05;
4073
4074                     if (distsqflat(&Person::players[i]->coords, &Person::players[i]->waypoints[Person::players[i]->waypoint]) < 1) {
4075                         if (Person::players[i]->waypointtype[Person::players[i]->waypoint] == wppause)
4076                             Person::players[i]->pausetime = 4;
4077                         Person::players[i]->waypoint++;
4078                         if (Person::players[i]->waypoint > Person::players[i]->numwaypoints - 1)
4079                             Person::players[i]->waypoint = 0;
4080
4081                     }
4082                 }
4083
4084                 if (Person::players[i]->numwaypoints > 1 && Person::players[i]->howactive == typeactive && Person::players[i]->pausetime <= 0)
4085                     Person::players[i]->forwardkeydown = 1;
4086                 else
4087                     Person::players[i]->forwardkeydown = 0;
4088                 Person::players[i]->leftkeydown = 0;
4089                 Person::players[i]->backkeydown = 0;
4090                 Person::players[i]->rightkeydown = 0;
4091                 Person::players[i]->crouchkeydown = 0;
4092                 Person::players[i]->attackkeydown = 0;
4093                 Person::players[i]->throwkeydown = 0;
4094
4095                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
4096                     if (!Person::players[i]->avoidsomething)
4097                         Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4098                     else {
4099                         XYZ leftpos, rightpos;
4100                         float leftdist, rightdist;
4101                         leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
4102                         rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
4103                         leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
4104                         rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
4105                         if (leftdist < rightdist)
4106                             Person::players[i]->targetyaw += 90;
4107                         else
4108                             Person::players[i]->targetyaw -= 90;
4109                     }
4110                 }
4111             }
4112             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4113                 Person::players[i]->jumpkeydown = 0;
4114             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
4115                 Person::players[i]->jumpkeydown = 1;
4116
4117
4118             //hearing sounds
4119             if (!editorenabled) {
4120                 if (Person::players[i]->howactive <= typesleeping)
4121                     if (numenvsounds > 0 && (tutoriallevel != 1 || cananger) && hostile)
4122                         for (int j = 0; j < numenvsounds; j++) {
4123                             float vol = Person::players[i]->howactive == typesleeping ? envsoundvol[j] - 14 : envsoundvol[j];
4124                             if (vol > 0 && distsq(&Person::players[i]->coords, &envsound[j]) <
4125                                     2 * (vol + vol * (Person::players[i]->creature == rabbittype) * 3))
4126                                 Person::players[i]->aitype = attacktypecutoff;
4127                         }
4128
4129                 if (Person::players[i]->aitype != passivetype) {
4130                     if (Person::players[i]->howactive == typesleeping)
4131                         Person::players[i]->setAnimation(getupfromfrontanim);
4132                     Person::players[i]->howactive = typeactive;
4133                 }
4134             }
4135
4136             if (Person::players[i]->howactive < typesleeping &&
4137                     ((tutoriallevel != 1 || cananger) && hostile) &&
4138                     !Person::players[0]->dead &&
4139                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
4140                     Person::players[i]->occluded < 25) {
4141                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
4142                         animation[Person::players[0]->animTarget].height != lowheight && !editorenabled)
4143                     Person::players[i]->aitype = attacktypecutoff;
4144                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
4145                         animation[Person::players[0]->animTarget].height == highheight && !editorenabled)
4146                     Person::players[i]->aitype = attacktypecutoff;
4147
4148                 //wolf smell
4149                 if (Person::players[i]->creature == wolftype) {
4150                     XYZ windsmell;
4151                     for (unsigned j = 0; j < Person::players.size(); j++) {
4152                         if (j == 0 || (Person::players[j]->dead && Person::players[j]->bloodloss > 0)) {
4153                             float smelldistance = 50;
4154                             if (j == 0 && Person::players[j]->num_weapons > 0) {
4155                                 if (weapons[Person::players[j]->weaponids[0]].bloody)
4156                                     smelldistance = 100;
4157                                 if (Person::players[j]->num_weapons == 2)
4158                                     if (weapons[Person::players[j]->weaponids[1]].bloody)
4159                                         smelldistance = 100;
4160                             }
4161                             if (j != 0)
4162                                 smelldistance = 100;
4163                             windsmell = windvector;
4164                             Normalise(&windsmell);
4165                             windsmell = windsmell * 2 + Person::players[j]->coords;
4166                             if (distsq(&Person::players[i]->coords, &windsmell) < smelldistance && !editorenabled)
4167                                 Person::players[i]->aitype = attacktypecutoff;
4168                         }
4169                     }
4170                 }
4171
4172                 if (Person::players[i]->howactive < typesleeping && Person::players[i]->losupdatedelay < 0 && !editorenabled && Person::players[i]->occluded < 2) {
4173                     Person::players[i]->losupdatedelay = .2;
4174                     for (unsigned j = 0; j < Person::players.size(); j++) {
4175                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
4176                             if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
4177                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
4178                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
4179                                         if ((-1 == checkcollide(
4180                                                     DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)*
4181                                                     Person::players[i]->scale + Person::players[i]->coords,
4182                                                     DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0)*
4183                                                     Person::players[j]->scale + Person::players[j]->coords) &&
4184                                                 !Person::players[j]->isWallJump()) ||
4185                                                 (Person::players[j]->animTarget == hanganim &&
4186                                                  normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
4187                                             Person::players[i]->lastseentime -= .2;
4188                                             if (j == 0 && animation[Person::players[j]->animTarget].height == lowheight)
4189                                                 Person::players[i]->lastseentime -= .4;
4190                                             else
4191                                                 Person::players[i]->lastseentime -= .6;
4192                                         }
4193                             if (Person::players[i]->lastseentime <= 0) {
4194                                 Person::players[i]->aitype = searchtype;
4195                                 Person::players[i]->lastchecktime = 12;
4196                                 Person::players[i]->lastseen = Person::players[j]->coords;
4197                                 Person::players[i]->lastseentime = 12;
4198                             }
4199                         }
4200                     }
4201                 }
4202             }
4203             //alerted surprise
4204             if (Person::players[i]->aitype == attacktypecutoff && musictype != 2) {
4205                 if (Person::players[i]->creature != wolftype) {
4206                     Person::players[i]->stunned = .6;
4207                     Person::players[i]->surprised = .6;
4208                 }
4209                 if (Person::players[i]->creature == wolftype) {
4210                     Person::players[i]->stunned = .47;
4211                     Person::players[i]->surprised = .47;
4212                 }
4213                 numseen++;
4214             }
4215         }
4216
4217         //search for player
4218         int j;
4219         if (Person::players[i]->aitype == searchtype) {
4220             Person::players[i]->aiupdatedelay -= multiplier;
4221             Person::players[i]->losupdatedelay -= multiplier;
4222             if (!Person::players[i]->pause)
4223                 Person::players[i]->lastseentime -= multiplier;
4224             Person::players[i]->lastchecktime -= multiplier;
4225
4226             if (Person::players[i]->isRun() && !Person::players[i]->onground) {
4227                 if (Person::players[i]->coords.y > terrain.getHeight(Person::players[i]->coords.x, Person::players[i]->coords.z) + 10) {
4228                     XYZ test2 = Person::players[i]->coords + Person::players[i]->facing;
4229                     test2.y += 5;
4230                     XYZ test = Person::players[i]->coords + Person::players[i]->facing;
4231                     test.y -= 10;
4232                     j = checkcollide(test2, test, Person::players[i]->laststanding);
4233                     if (j == -1)
4234                         j = checkcollide(test2, test);
4235                     if (j == -1) {
4236                         Person::players[i]->velocity = 0;
4237                         Person::players[i]->setAnimation(Person::players[i]->getStop());
4238                         Person::players[i]->targetyaw += 180;
4239                         Person::players[i]->stunned = .5;
4240                         //Person::players[i]->aitype=passivetype;
4241                         Person::players[i]->aitype = pathfindtype;
4242                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
4243                         Person::players[i]->finalpathfindpoint = -1;
4244                         Person::players[i]->targetpathfindpoint = -1;
4245                         Person::players[i]->lastpathfindpoint = -1;
4246                         Person::players[i]->lastpathfindpoint2 = -1;
4247                         Person::players[i]->lastpathfindpoint3 = -1;
4248                         Person::players[i]->lastpathfindpoint4 = -1;
4249                     } else
4250                         Person::players[i]->laststanding = j;
4251                 }
4252             }
4253             //check out last seen location
4254             if (Person::players[i]->aiupdatedelay < 0) {
4255                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[i]->lastseen);
4256                 Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4257                 Person::players[i]->aiupdatedelay = .05;
4258                 Person::players[i]->forwardkeydown = 1;
4259
4260                 if (distsqflat(&Person::players[i]->coords, &Person::players[i]->lastseen) < 1 * sq(Person::players[i]->scale * 5) || Person::players[i]->lastchecktime < 0) {
4261                     Person::players[i]->forwardkeydown = 0;
4262                     Person::players[i]->aiupdatedelay = 1;
4263                     Person::players[i]->lastseen.x += (float(Random() % 100) - 50) / 25;
4264                     Person::players[i]->lastseen.z += (float(Random() % 100) - 50) / 25;
4265                     Person::players[i]->lastchecktime = 3;
4266                 }
4267
4268                 Person::players[i]->leftkeydown = 0;
4269                 Person::players[i]->backkeydown = 0;
4270                 Person::players[i]->rightkeydown = 0;
4271                 Person::players[i]->crouchkeydown = 0;
4272                 Person::players[i]->attackkeydown = 0;
4273                 Person::players[i]->throwkeydown = 0;
4274
4275                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
4276                     if (!Person::players[i]->avoidsomething)
4277                         Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4278                     else {
4279                         XYZ leftpos, rightpos;
4280                         float leftdist, rightdist;
4281                         leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
4282                         rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
4283                         leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
4284                         rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
4285                         if (leftdist < rightdist)
4286                             Person::players[i]->targetyaw += 90;
4287                         else
4288                             Person::players[i]->targetyaw -= 90;
4289                     }
4290                 }
4291             }
4292             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4293                 Person::players[i]->jumpkeydown = 0;
4294             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
4295                 Person::players[i]->jumpkeydown = 1;
4296
4297             if (numenvsounds > 0 && ((tutoriallevel != 1 || cananger) && hostile))
4298                 for (int k = 0; k < numenvsounds; k++) {
4299                     if (distsq(&Person::players[i]->coords, &envsound[k]) < 2 * (envsoundvol[k] + envsoundvol[k] * (Person::players[i]->creature == rabbittype) * 3)) {
4300                         Person::players[i]->aitype = attacktypecutoff;
4301                     }
4302                 }
4303
4304             if (!Person::players[0]->dead &&
4305                     Person::players[i]->losupdatedelay < 0 &&
4306                     !editorenabled &&
4307                     Person::players[i]->occluded < 2 &&
4308                     ((tutoriallevel != 1 || cananger) && hostile)) {
4309                 Person::players[i]->losupdatedelay = .2;
4310                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && animation[Person::players[i]->animTarget].height != lowheight) {
4311                     Person::players[i]->aitype = attacktypecutoff;
4312                     Person::players[i]->lastseentime = 1;
4313                 }
4314                 if (abs(Random() % 2) || animation[Person::players[i]->animTarget].height != lowheight)
4315                     //TODO: factor out canSeePlayer()
4316                     if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400)
4317                         if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
4318                             if ((checkcollide(
4319                                         DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)*
4320                                         Person::players[i]->scale + Person::players[i]->coords,
4321                                         DoRotation(Person::players[0]->jointPos(head), 0, Person::players[0]->yaw, 0)*
4322                                         Person::players[0]->scale + Person::players[0]->coords) == -1) ||
4323                                     (Person::players[0]->animTarget == hanganim && normaldotproduct(
4324                                          Person::players[0]->facing, Person::players[i]->coords - Person::players[0]->coords) < 0)) {
4325                                 /* //TODO: changed j to 0 on a whim, make sure this is correct
4326                                 (Person::players[j]->animTarget==hanganim&&normaldotproduct(
4327                                     Person::players[j]->facing,Person::players[i]->coords-Person::players[j]->coords)<0)
4328                                 */
4329                                 Person::players[i]->aitype = attacktypecutoff;
4330                                 Person::players[i]->lastseentime = 1;
4331                             }
4332             }
4333             //player escaped
4334             if (Person::players[i]->lastseentime < 0) {
4335                 //Person::players[i]->aitype=passivetype;
4336                 numescaped++;
4337                 Person::players[i]->aitype = pathfindtype;
4338                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
4339                 Person::players[i]->finalpathfindpoint = -1;
4340                 Person::players[i]->targetpathfindpoint = -1;
4341                 Person::players[i]->lastpathfindpoint = -1;
4342                 Person::players[i]->lastpathfindpoint2 = -1;
4343                 Person::players[i]->lastpathfindpoint3 = -1;
4344                 Person::players[i]->lastpathfindpoint4 = -1;
4345             }
4346         }
4347
4348         if (Person::players[i]->aitype != gethelptype)
4349             Person::players[i]->runninghowlong = 0;
4350
4351         //get help from buddies
4352         if (Person::players[i]->aitype == gethelptype) {
4353             Person::players[i]->runninghowlong += multiplier;
4354             Person::players[i]->aiupdatedelay -= multiplier;
4355
4356             if (Person::players[i]->aiupdatedelay < 0 || Person::players[i]->ally == 0) {
4357                 Person::players[i]->aiupdatedelay = .2;
4358
4359                 //find closest ally
4360                 //TODO: factor out closest search somehow
4361                 if (!Person::players[i]->ally) {
4362                     int closest = -1;
4363                     float closestdist = -1;
4364                     for (unsigned k = 0; k < Person::players.size(); k++) {
4365                         if (k != i && k != 0 && !Person::players[k]->dead &&
4366                                 Person::players[k]->howactive < typedead1 &&
4367                                 !Person::players[k]->skeleton.free &&
4368                                 Person::players[k]->aitype == passivetype) {
4369                             float distance = distsq(&Person::players[i]->coords, &Person::players[k]->coords);
4370                             if (closestdist == -1 || distance < closestdist) {
4371                                 closestdist = distance;
4372                                 closest = k;
4373                             }
4374                             closest = k;
4375                         }
4376                     }
4377                     if (closest != -1)
4378                         Person::players[i]->ally = closest;
4379                     else
4380                         Person::players[i]->ally = 0;
4381                     Person::players[i]->lastseen = Person::players[0]->coords;
4382                     Person::players[i]->lastseentime = 12;
4383                 }
4384
4385
4386                 Person::players[i]->lastchecktime = 12;
4387
4388                 XYZ facing = Person::players[i]->coords;
4389                 XYZ flatfacing = Person::players[Person::players[i]->ally]->coords;
4390                 facing.y += Person::players[i]->jointPos(head).y * Person::players[i]->scale;
4391                 flatfacing.y += Person::players[Person::players[i]->ally]->jointPos(head).y * Person::players[Person::players[i]->ally]->scale;
4392                 if (-1 != checkcollide(facing, flatfacing))
4393                     Person::players[i]->lastseentime -= .1;
4394
4395                 //no available ally, run back to player
4396                 if (Person::players[i]->ally <= 0 ||
4397                         Person::players[Person::players[i]->ally]->skeleton.free ||
4398                         Person::players[Person::players[i]->ally]->aitype != passivetype ||
4399                         Person::players[i]->lastseentime <= 0) {
4400                     Person::players[i]->aitype = searchtype;
4401                     Person::players[i]->lastseentime = 12;
4402                 }
4403
4404                 //seek out ally
4405                 if (Person::players[i]->ally > 0) {
4406                     Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[Person::players[i]->ally]->coords);
4407                     Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4408                     Person::players[i]->aiupdatedelay = .05;
4409                     Person::players[i]->forwardkeydown = 1;
4410
4411                     if (distsqflat(&Person::players[i]->coords, &Person::players[Person::players[i]->ally]->coords) < 3) {
4412                         Person::players[i]->aitype = searchtype;
4413                         Person::players[i]->lastseentime = 12;
4414                         Person::players[Person::players[i]->ally]->aitype = searchtype;
4415                         if (Person::players[Person::players[i]->ally]->lastseentime < Person::players[i]->lastseentime) {
4416                             Person::players[Person::players[i]->ally]->lastseen = Person::players[i]->lastseen;
4417                             Person::players[Person::players[i]->ally]->lastseentime = Person::players[i]->lastseentime;
4418                             Person::players[Person::players[i]->ally]->lastchecktime = Person::players[i]->lastchecktime;
4419                         }
4420                     }
4421
4422                     if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
4423                         if (!Person::players[i]->avoidsomething)
4424                             Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4425                         else {
4426                             XYZ leftpos, rightpos;
4427                             float leftdist, rightdist;
4428                             leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
4429                             rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
4430                             leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
4431                             rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
4432                             if (leftdist < rightdist)
4433                                 Person::players[i]->targetyaw += 90;
4434                             else
4435                                 Person::players[i]->targetyaw -= 90;
4436                         }
4437                     }
4438                 }
4439
4440                 Person::players[i]->leftkeydown = 0;
4441                 Person::players[i]->backkeydown = 0;
4442                 Person::players[i]->rightkeydown = 0;
4443                 Person::players[i]->crouchkeydown = 0;
4444                 Person::players[i]->attackkeydown = 0;
4445             }
4446             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4447                 Person::players[i]->jumpkeydown = 0;
4448             if (Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5)
4449                 Person::players[i]->jumpkeydown = 1;
4450         }
4451
4452         //retreiving a weapon on the ground
4453         if (Person::players[i]->aitype == getweapontype) {
4454             Person::players[i]->aiupdatedelay -= multiplier;
4455             Person::players[i]->lastchecktime -= multiplier;
4456
4457             if (Person::players[i]->aiupdatedelay < 0) {
4458                 Person::players[i]->aiupdatedelay = .2;
4459
4460                 //ALLY IS WEPON
4461                 if (Person::players[i]->ally < 0) {
4462                     int closest = -1;
4463                     float closestdist = -1;
4464                     for (unsigned k = 0; k < weapons.size(); k++)
4465                         if (weapons[k].owner == -1) {
4466                             float distance = distsq(&Person::players[i]->coords, &weapons[k].position);
4467                             if (closestdist == -1 || distance < closestdist) {
4468                                 closestdist = distance;
4469                                 closest = k;
4470                             }
4471                             closest = k;
4472                         }
4473                     if (closest != -1)
4474                         Person::players[i]->ally = closest;
4475                     else
4476                         Person::players[i]->ally = -1;
4477                 }
4478
4479                 Person::players[i]->lastseentime = 12;
4480
4481                 if (!Person::players[0]->dead && ((tutoriallevel != 1 || cananger) && hostile))
4482                     if (Person::players[i]->ally < 0 || Person::players[i]->weaponactive != -1 || Person::players[i]->lastchecktime <= 0) {
4483                         Person::players[i]->aitype = attacktypecutoff;
4484                         Person::players[i]->lastseentime = 1;
4485                     }
4486                 if (!Person::players[0]->dead)
4487                     if (Person::players[i]->ally >= 0) {
4488                         if (weapons[Person::players[i]->ally].owner != -1 ||
4489                                 distsq(&Person::players[i]->coords, &weapons[Person::players[i]->ally].position) > 16) {
4490                             Person::players[i]->aitype = attacktypecutoff;
4491                             Person::players[i]->lastseentime = 1;
4492                         }
4493                         //TODO: factor these out as moveToward()
4494                         Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[Person::players[i]->ally].position);
4495                         Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4496                         Person::players[i]->aiupdatedelay = .05;
4497                         Person::players[i]->forwardkeydown = 1;
4498
4499
4500                         if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
4501                             if (!Person::players[i]->avoidsomething)
4502                                 Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4503                             else {
4504                                 XYZ leftpos, rightpos;
4505                                 float leftdist, rightdist;
4506                                 leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
4507                                 rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
4508                                 leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
4509                                 rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
4510                                 if (leftdist < rightdist)
4511                                     Person::players[i]->targetyaw += 90;
4512                                 else
4513                                     Person::players[i]->targetyaw -= 90;
4514                             }
4515                         }
4516                     }
4517
4518                 Person::players[i]->leftkeydown = 0;
4519                 Person::players[i]->backkeydown = 0;
4520                 Person::players[i]->rightkeydown = 0;
4521                 Person::players[i]->attackkeydown = 0;
4522                 Person::players[i]->throwkeydown = 1;
4523                 Person::players[i]->crouchkeydown = 0;
4524                 if (Person::players[i]->animTarget != crouchremoveknifeanim &&
4525                         Person::players[i]->animTarget != removeknifeanim)
4526                     Person::players[i]->throwtogglekeydown = 0;
4527                 Person::players[i]->drawkeydown = 0;
4528             }
4529             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4530                 Person::players[i]->jumpkeydown = 0;
4531             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
4532                 Person::players[i]->jumpkeydown = 1;
4533         }
4534
4535         if (Person::players[i]->aitype == attacktypecutoff) {
4536             Person::players[i]->aiupdatedelay -= multiplier;
4537             //dodge or reverse rabbit kicks, knife throws, flips
4538             if (Person::players[i]->damage < Person::players[i]->damagetolerance * 2 / 3)
4539                 if ((Person::players[0]->animTarget == rabbitkickanim ||
4540                         Person::players[0]->animTarget == knifethrowanim ||
4541                         (Person::players[0]->isFlip() &&
4542                          normaldotproduct(Person::players[0]->facing, Person::players[0]->coords - Person::players[i]->coords) < 0)) &&
4543                         !Person::players[0]->skeleton.free &&
4544                         (Person::players[i]->aiupdatedelay < .1)) {
4545                     Person::players[i]->attackkeydown = 0;
4546                     if (Person::players[i]->isIdle())
4547                         Person::players[i]->crouchkeydown = 1;
4548                     if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->weaponactive != -1) {
4549                         if (weapons[Person::players[0]->weaponids[0]].getType() == knife) {
4550                             if (Person::players[i]->isIdle() || Person::players[i]->isCrouch() || Person::players[i]->isRun() || Person::players[i]->isFlip()) {
4551                                 if (abs(Random() % 2) == 0)
4552                                     Person::players[i]->setAnimation(backhandspringanim);
4553                                 else
4554                                     Person::players[i]->setAnimation(rollanim);
4555                                 Person::players[i]->targetyaw += 90 * (abs(Random() % 2) * 2 - 1);
4556                                 Person::players[i]->wentforweapon = 0;
4557                             }
4558                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim)
4559                                 Person::players[i]->setAnimation(flipanim);
4560                         }
4561                     }
4562                     Person::players[i]->forwardkeydown = 0;
4563                     Person::players[i]->aiupdatedelay = .02;
4564                 }
4565             //get confused by flips
4566             if (Person::players[0]->isFlip() &&
4567                     !Person::players[0]->skeleton.free &&
4568                     Person::players[0]->animTarget != walljumprightkickanim &&
4569                     Person::players[0]->animTarget != walljumpleftkickanim) {
4570                 if (distsq(&Person::players[0]->coords, &Person::players[i]->coords) < 25)
4571                     if ((1 - Person::players[i]->damage / Person::players[i]->damagetolerance) > .5)
4572                         Person::players[i]->stunned = 1;
4573             }
4574             //go for weapon on the ground
4575             if (Person::players[i]->wentforweapon < 3)
4576                 for (unsigned k = 0; k < weapons.size(); k++)
4577                     if (Person::players[i]->creature != wolftype)
4578                         if (Person::players[i]->num_weapons == 0 &&
4579                                 weapons[k].owner == -1 &&
4580                                 weapons[i].velocity.x == 0 &&
4581                                 weapons[i].velocity.z == 0 &&
4582                                 weapons[i].velocity.y == 0) {
4583                             if (distsq(&Person::players[i]->coords, &weapons[k].position) < 16) {
4584                                 Person::players[i]->wentforweapon++;
4585                                 Person::players[i]->lastchecktime = 6;
4586                                 Person::players[i]->aitype = getweapontype;
4587                                 Person::players[i]->ally = -1;
4588                             }
4589                         }
4590             //dodge/reverse walljump kicks
4591             if (Person::players[i]->damage < Person::players[i]->damagetolerance / 2)
4592                 if (animation[Person::players[i]->animTarget].height != highheight)
4593                     if (Person::players[i]->damage < Person::players[i]->damagetolerance * .5 &&
4594                             ((Person::players[0]->animTarget == walljumprightkickanim ||
4595                               Person::players[0]->animTarget == walljumpleftkickanim) &&
4596                              ((Person::players[i]->aiupdatedelay < .15 &&
4597                                difficulty == 2) ||
4598                               (Person::players[i]->aiupdatedelay < .08 &&
4599                                difficulty != 2)))) {
4600                         Person::players[i]->crouchkeydown = 1;
4601                     }
4602             //walked off a ledge (?)
4603             if (Person::players[i]->isRun() && !Person::players[i]->onground)
4604                 if (Person::players[i]->coords.y > terrain.getHeight(Person::players[i]->coords.x, Person::players[i]->coords.z) + 10) {
4605                     XYZ test2 = Person::players[i]->coords + Person::players[i]->facing;
4606                     test2.y += 5;
4607                     XYZ test = Person::players[i]->coords + Person::players[i]->facing;
4608                     test.y -= 10;
4609                     j = checkcollide(test2, test, Person::players[i]->laststanding);
4610                     if (j == -1)
4611                         j = checkcollide(test2, test);
4612                     if (j == -1) {
4613                         Person::players[i]->velocity = 0;
4614                         Person::players[i]->setAnimation(Person::players[i]->getStop());
4615                         Person::players[i]->targetyaw += 180;
4616                         Person::players[i]->stunned = .5;
4617                         Person::players[i]->aitype = pathfindtype;
4618                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
4619                         Person::players[i]->finalpathfindpoint = -1;
4620                         Person::players[i]->targetpathfindpoint = -1;
4621                         Person::players[i]->lastpathfindpoint = -1;
4622                         Person::players[i]->lastpathfindpoint2 = -1;
4623                         Person::players[i]->lastpathfindpoint3 = -1;
4624                         Person::players[i]->lastpathfindpoint4 = -1;
4625                     } else
4626                         Person::players[i]->laststanding = j;
4627                 }
4628             //lose sight of player in the air (?)
4629             if (Person::players[0]->coords.y > Person::players[i]->coords.y + 5 &&
4630                     animation[Person::players[0]->animTarget].height != highheight &&
4631                     !Person::players[0]->onterrain) {
4632                 Person::players[i]->aitype = pathfindtype;
4633                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
4634                 Person::players[i]->finalpathfindpoint = -1;
4635                 Person::players[i]->targetpathfindpoint = -1;
4636                 Person::players[i]->lastpathfindpoint = -1;
4637                 Person::players[i]->lastpathfindpoint2 = -1;
4638                 Person::players[i]->lastpathfindpoint3 = -1;
4639                 Person::players[i]->lastpathfindpoint4 = -1;
4640             }
4641             //it's time to think (?)
4642             if (Person::players[i]->aiupdatedelay < 0 &&
4643                     !animation[Person::players[i]->animTarget].attack &&
4644                     Person::players[i]->animTarget != staggerbackhighanim &&
4645                     Person::players[i]->animTarget != staggerbackhardanim &&
4646                     Person::players[i]->animTarget != backhandspringanim &&
4647                     Person::players[i]->animTarget != dodgebackanim) {
4648                 //draw weapon
4649                 if (Person::players[i]->weaponactive == -1 && Person::players[i]->num_weapons > 0)
4650                     Person::players[i]->drawkeydown = Random() % 2;
4651                 else
4652                     Person::players[i]->drawkeydown = 0;
4653                 Person::players[i]->rabbitkickenabled = Random() % 2;
4654                 //chase player
4655                 XYZ rotatetarget = Person::players[0]->coords + Person::players[0]->velocity;
4656                 XYZ targetpoint = Person::players[0]->coords;
4657                 if (distsq(&Person::players[0]->coords, &Person::players[i]->coords) <
4658                         distsq(&rotatetarget, &Person::players[i]->coords))
4659                     targetpoint += Person::players[0]->velocity *
4660                                    findDistance(&Person::players[0]->coords, &Person::players[i]->coords) / findLength(&Person::players[i]->velocity);
4661                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, targetpoint);
4662                 Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4663                 Person::players[i]->aiupdatedelay = .2 + fabs((float)(Random() % 100) / 1000);
4664
4665                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 5 && (Person::players[0]->weaponactive == -1 || Person::players[i]->weaponactive != -1))
4666                     Person::players[i]->forwardkeydown = 1;
4667                 else if ((distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 16 ||
4668                           distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 9) &&
4669                          Person::players[0]->weaponactive != -1)
4670                     Person::players[i]->forwardkeydown = 1;
4671                 else if (Random() % 6 == 0 || (Person::players[i]->creature == wolftype && Random() % 3 == 0))
4672                     Person::players[i]->forwardkeydown = 1;
4673                 else
4674                     Person::players[i]->forwardkeydown = 0;
4675                 //chill out around the corpse
4676                 if (Person::players[0]->dead) {
4677                     Person::players[i]->forwardkeydown = 0;
4678                     if (Random() % 10 == 0)
4679                         Person::players[i]->forwardkeydown = 1;
4680                     if (Random() % 100 == 0) {
4681                         Person::players[i]->aitype = pathfindtype;
4682                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
4683                         Person::players[i]->finalpathfindpoint = -1;
4684                         Person::players[i]->targetpathfindpoint = -1;
4685                         Person::players[i]->lastpathfindpoint = -1;
4686                         Person::players[i]->lastpathfindpoint2 = -1;
4687                         Person::players[i]->lastpathfindpoint3 = -1;
4688                         Person::players[i]->lastpathfindpoint4 = -1;
4689                     }
4690                 }
4691                 Person::players[i]->leftkeydown = 0;
4692                 Person::players[i]->backkeydown = 0;
4693                 Person::players[i]->rightkeydown = 0;
4694                 Person::players[i]->crouchkeydown = 0;
4695                 Person::players[i]->throwkeydown = 0;
4696
4697                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8)
4698                     Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4699                 //attack!!!
4700                 if (Random() % 2 == 0 || Person::players[i]->weaponactive != -1 || Person::players[i]->creature == wolftype)
4701                     Person::players[i]->attackkeydown = 1;
4702                 else
4703                     Person::players[i]->attackkeydown = 0;
4704                 if (Person::players[i]->isRun() && Random() % 6 && distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 7)
4705                     Person::players[i]->attackkeydown = 0;
4706
4707                 //TODO: wat
4708                 if (Person::players[i]->aitype != playercontrolled &&
4709                         (Person::players[i]->isIdle() ||
4710                          Person::players[i]->isCrouch() ||
4711                          Person::players[i]->isRun())) {
4712                     int target = -2;
4713                     for (unsigned j = 0; j < Person::players.size(); j++)
4714                         if (j != i && !Person::players[j]->skeleton.free &&
4715                                 Person::players[j]->hasvictim &&
4716                                 (tutoriallevel == 1 && reversaltrain ||
4717                                  Random() % 2 == 0 && difficulty == 2 ||
4718                                  Random() % 4 == 0 && difficulty == 1 ||
4719                                  Random() % 8 == 0 && difficulty == 0 ||
4720                                  Person::players[j]->lastattack2 == Person::players[j]->animTarget &&
4721                                  Person::players[j]->lastattack3 == Person::players[j]->animTarget &&
4722                                  (Random() % 2 == 0 || difficulty == 2) ||
4723                                  (Person::players[i]->isIdle() || Person::players[i]->isRun()) &&
4724                                  Person::players[j]->weaponactive != -1 ||
4725                                  Person::players[j]->animTarget == swordslashanim &&
4726                                  Person::players[i]->weaponactive != -1 ||
4727                                  Person::players[j]->animTarget == staffhitanim ||
4728                                  Person::players[j]->animTarget == staffspinhitanim))
4729                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 4 &&
4730                                     Person::players[j]->victim == Person::players[i] &&
4731                                     (Person::players[j]->animTarget == sweepanim ||
4732                                      Person::players[j]->animTarget == spinkickanim ||
4733                                      Person::players[j]->animTarget == staffhitanim ||
4734                                      Person::players[j]->animTarget == staffspinhitanim ||
4735                                      Person::players[j]->animTarget == winduppunchanim ||
4736                                      Person::players[j]->animTarget == upunchanim ||
4737                                      Person::players[j]->animTarget == wolfslapanim ||
4738                                      Person::players[j]->animTarget == knifeslashstartanim ||
4739                                      Person::players[j]->animTarget == swordslashanim &&
4740                                      (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 2 ||
4741                                       Person::players[i]->weaponactive != -1))) {
4742                                 if (target >= 0)
4743                                     target = -1;
4744                                 else
4745                                     target = j;
4746                             }
4747                     if (target >= 0)
4748                         Person::players[target]->Reverse();
4749                 }
4750
4751                 if (Person::players[i]->collided < 1)
4752                     Person::players[i]->jumpkeydown = 0;
4753                 if (Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5 ||
4754                         distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 400 &&
4755                         Person::players[i]->onterrain &&
4756                         Person::players[i]->creature == rabbittype)
4757                     Person::players[i]->jumpkeydown = 1;
4758                 //TODO: why are we controlling the human?
4759                 if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
4760                     Person::players[0]->jumpkeydown = 0;
4761                 if (Person::players[0]->animTarget == jumpdownanim &&
4762                         distsq(&Person::players[0]->coords, &Person::players[i]->coords) < 40)
4763                     Person::players[i]->crouchkeydown = 1;
4764                 if (Person::players[i]->jumpkeydown)
4765                     Person::players[i]->attackkeydown = 0;
4766
4767                 if (tutoriallevel == 1)
4768                     if (!canattack)
4769                         Person::players[i]->attackkeydown = 0;
4770
4771
4772                 XYZ facing = Person::players[i]->coords;
4773                 XYZ flatfacing = Person::players[0]->coords;
4774                 facing.y += Person::players[i]->jointPos(head).y * Person::players[i]->scale;
4775                 flatfacing.y += Person::players[0]->jointPos(head).y * Person::players[0]->scale;
4776                 if (Person::players[i]->occluded >= 2)
4777                     if (-1 != checkcollide(facing, flatfacing)) {
4778                         if (!Person::players[i]->pause)
4779                             Person::players[i]->lastseentime -= .2;
4780                         if (Person::players[i]->lastseentime <= 0 &&
4781                                 (Person::players[i]->creature != wolftype ||
4782                                  Person::players[i]->weaponstuck == -1)) {
4783                             Person::players[i]->aitype = searchtype;
4784                             Person::players[i]->lastchecktime = 12;
4785                             Person::players[i]->lastseen = Person::players[0]->coords;
4786                             Person::players[i]->lastseentime = 12;
4787                         }
4788                     } else
4789                         Person::players[i]->lastseentime = 1;
4790             }
4791         }
4792         if (animation[Person::players[0]->animTarget].height == highheight &&
4793                 (Person::players[i]->aitype == attacktypecutoff ||
4794                  Person::players[i]->aitype == searchtype))
4795             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
4796                 XYZ test = Person::players[0]->coords;
4797                 test.y -= 40;
4798                 if (-1 == checkcollide(Person::players[0]->coords, test))
4799                     Person::players[i]->stunned = 1;
4800             }
4801         //stunned
4802         if (Person::players[i]->aitype == passivetype && !(Person::players[i]->numwaypoints > 1) ||
4803                 Person::players[i]->stunned > 0 ||
4804                 Person::players[i]->pause && Person::players[i]->damage > Person::players[i]->superpermanentdamage) {
4805             if (Person::players[i]->pause)
4806                 Person::players[i]->lastseentime = 1;
4807             Person::players[i]->targetyaw = Person::players[i]->yaw;
4808             Person::players[i]->forwardkeydown = 0;
4809             Person::players[i]->leftkeydown = 0;
4810             Person::players[i]->backkeydown = 0;
4811             Person::players[i]->rightkeydown = 0;
4812             Person::players[i]->jumpkeydown = 0;
4813             Person::players[i]->attackkeydown = 0;
4814             Person::players[i]->crouchkeydown = 0;
4815             Person::players[i]->throwkeydown = 0;
4816         }
4817
4818
4819         XYZ facing;
4820         facing = 0;
4821         facing.z = -1;
4822
4823         XYZ flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
4824         facing = flatfacing;
4825
4826         if (Person::players[i]->aitype == attacktypecutoff) {
4827             Person::players[i]->targetheadyaw = 180 - roughDirectionTo(Person::players[i]->coords, Person::players[0]->coords);
4828             Person::players[i]->targetheadpitch = pitchTo(Person::players[i]->coords, Person::players[0]->coords);
4829         } else if (Person::players[i]->howactive >= typesleeping) {
4830             Person::players[i]->targetheadyaw = Person::players[i]->targetyaw;
4831             Person::players[i]->targetheadpitch = 0;
4832         } else {
4833             if (Person::players[i]->interestdelay <= 0) {
4834                 Person::players[i]->interestdelay = .7 + (float)(abs(Random() % 100)) / 100;
4835                 Person::players[i]->headtarget = Person::players[i]->coords;
4836                 Person::players[i]->headtarget.x += (float)(abs(Random() % 200) - 100) / 100;
4837                 Person::players[i]->headtarget.z += (float)(abs(Random() % 200) - 100) / 100;
4838                 Person::players[i]->headtarget.y += (float)(abs(Random() % 200) - 100) / 300;
4839                 Person::players[i]->headtarget += Person::players[i]->facing * 1.5;
4840             }
4841             Person::players[i]->targetheadyaw = 180 - roughDirectionTo(Person::players[i]->coords, Person::players[i]->headtarget);
4842             Person::players[i]->targetheadpitch = pitchTo(Person::players[i]->coords, Person::players[i]->headtarget);
4843         }
4844     }
4845 }
4846
4847
4848
4849 void updateSettingsMenu()
4850 {
4851     char sbuf[256];
4852     if ((float)newscreenwidth > (float)newscreenheight * 1.61 || (float)newscreenwidth < (float)newscreenheight * 1.59)
4853         sprintf (sbuf, "Resolution: %d*%d", (int)newscreenwidth, (int)newscreenheight);
4854     else
4855         sprintf (sbuf, "Resolution: %d*%d (widescreen)", (int)newscreenwidth, (int)newscreenheight);
4856     Menu::setText(0, sbuf);
4857     Menu::setText(14, fullscreen ? "Fullscreen: On" : "Fullscreen: Off");
4858     if (newdetail == 0) Menu::setText(1, "Detail: Low");
4859     if (newdetail == 1) Menu::setText(1, "Detail: Medium");
4860     if (newdetail == 2) Menu::setText(1, "Detail: High");
4861     if (bloodtoggle == 0) Menu::setText(2, "Blood: Off");
4862     if (bloodtoggle == 1) Menu::setText(2, "Blood: On, low detail");
4863     if (bloodtoggle == 2) Menu::setText(2, "Blood: On, high detail (slower)");
4864     if (difficulty == 0) Menu::setText(3, "Difficulty: Easier");
4865     if (difficulty == 1) Menu::setText(3, "Difficulty: Difficult");
4866     if (difficulty == 2) Menu::setText(3, "Difficulty: Insane");
4867     Menu::setText(4, ismotionblur ? "Blur Effects: Enabled (less compatible)" : "Blur Effects: Disabled (more compatible)");
4868     Menu::setText(5, decals ? "Decals: Enabled (slower)" : "Decals: Disabled");
4869     Menu::setText(6, musictoggle ? "Music: Enabled" : "Music: Disabled");
4870     Menu::setText(9, invertmouse ? "Invert mouse: Yes" : "Invert mouse: No");
4871     sprintf (sbuf, "Mouse Speed: %d", (int)(usermousesensitivity * 5));
4872     Menu::setText(10, sbuf);
4873     sprintf (sbuf, "Volume: %d%%", (int)(volume * 100));
4874     Menu::setText(11, sbuf);
4875     Menu::setText(13, showdamagebar ? "Damage Bar: On" : "Damage Bar: Off");
4876     if (newdetail == detail && newscreenheight == (int)screenheight && newscreenwidth == (int)screenwidth)
4877         sprintf (sbuf, "Back");
4878     else
4879         sprintf (sbuf, "Back (some changes take effect next time Lugaru is opened)");
4880     Menu::setText(8, sbuf);
4881 }
4882
4883 void updateStereoConfigMenu()
4884 {
4885     char sbuf[256];
4886     sprintf(sbuf, "Stereo mode: %s", StereoModeName(newstereomode));
4887     Menu::setText(0, sbuf);
4888     sprintf(sbuf, "Stereo separation: %.3f", stereoseparation);
4889     Menu::setText(1, sbuf);
4890     sprintf(sbuf, "Reverse stereo: %s", stereoreverse ? "Yes" : "No");
4891     Menu::setText(2, sbuf);
4892 }
4893
4894 void updateControlsMenu()
4895 {
4896     Menu::setText(0, (string)"Forwards: " + (keyselect == 0 ? "_" : Input::keyToChar(forwardkey)));
4897     Menu::setText(1, (string)"Back: "    + (keyselect == 1 ? "_" : Input::keyToChar(backkey)));
4898     Menu::setText(2, (string)"Left: "    + (keyselect == 2 ? "_" : Input::keyToChar(leftkey)));
4899     Menu::setText(3, (string)"Right: "   + (keyselect == 3 ? "_" : Input::keyToChar(rightkey)));
4900     Menu::setText(4, (string)"Crouch: "  + (keyselect == 4 ? "_" : Input::keyToChar(crouchkey)));
4901     Menu::setText(5, (string)"Jump: "    + (keyselect == 5 ? "_" : Input::keyToChar(jumpkey)));
4902     Menu::setText(6, (string)"Draw: "    + (keyselect == 6 ? "_" : Input::keyToChar(drawkey)));
4903     Menu::setText(7, (string)"Throw: "   + (keyselect == 7 ? "_" : Input::keyToChar(throwkey)));
4904     Menu::setText(8, (string)"Attack: "  + (keyselect == 8 ? "_" : Input::keyToChar(attackkey)));
4905     if (debugmode)
4906         Menu::setText(9, (string)"Console: " + (keyselect == 9 ? "_" : Input::keyToChar(consolekey)));
4907 }
4908
4909 /*
4910 Values of mainmenu :
4911 1 Main menu
4912 2 Menu pause (resume/end game)
4913 3 Option menu
4914 4 Controls configuration menu
4915 5 Main game menu (choose level or challenge)
4916 6 Deleting user menu
4917 7 User managment menu (select/add)
4918 8 Choose difficulty menu
4919 9 Challenge level selection menu
4920 10 End of the campaign congratulation (is that really a menu?)
4921 11 Same that 9 ??? => unused
4922 18 stereo configuration
4923 */
4924
4925 void Game::LoadMenu()
4926 {
4927     Menu::clearMenu();
4928     switch (mainmenu) {
4929     case 1:
4930     case 2:
4931         Menu::addImage(0, Mainmenuitems[0], 150, 480 - 128, 256, 128);
4932         Menu::addButtonImage(1, Mainmenuitems[mainmenu == 1 ? 1 : 5], 18, 480 - 152 - 32, 128, 32);
4933         Menu::addButtonImage(2, Mainmenuitems[2], 18, 480 - 228 - 32, 112, 32);
4934         Menu::addButtonImage(3, Mainmenuitems[mainmenu == 1 ? 3 : 6], 18, 480 - 306 - 32, mainmenu == 1 ? 68 : 132, 32);
4935         break;
4936     case 3:
4937         Menu::addButton( 0, "", 10 + 20, 440);
4938         Menu::addButton(14, "", 10 + 400, 440);
4939         Menu::addButton( 1, "", 10 + 60, 405);
4940         Menu::addButton( 2, "", 10 + 70, 370);
4941         Menu::addButton( 3, "", 10 + 20 - 1000, 335 - 1000);
4942         Menu::addButton( 4, "", 10   , 335);
4943         Menu::addButton( 5, "", 10 + 60, 300);
4944         Menu::addButton( 6, "", 10 + 70, 265);
4945         Menu::addButton( 9, "", 10   , 230);
4946         Menu::addButton(10, "", 20   , 195);
4947         Menu::addButton(11, "", 10 + 60, 160);
4948         Menu::addButton(13, "", 30   , 125);
4949         Menu::addButton( 7, "-Configure Controls-", 10 + 15, 90);
4950         Menu::addButton(12, "-Configure Stereo -", 10 + 15, 55);
4951         Menu::addButton(8, "Back", 10, 10);
4952         updateSettingsMenu();
4953         break;
4954     case 4:
4955         Menu::addButton(0, "", 10   , 400);
4956         Menu::addButton(1, "", 10 + 40, 360);
4957         Menu::addButton(2, "", 10 + 40, 320);
4958         Menu::addButton(3, "", 10 + 30, 280);
4959         Menu::addButton(4, "", 10 + 20, 240);
4960         Menu::addButton(5, "", 10 + 40, 200);
4961         Menu::addButton(6, "", 10 + 40, 160);
4962         Menu::addButton(7, "", 10 + 30, 120);
4963         Menu::addButton(8, "", 10 + 20, 80);
4964         if (debugmode)
4965             Menu::addButton(9, "", 10 + 10, 40);
4966         Menu::addButton(debugmode ? 10 : 9, "Back", 10, 10);
4967         updateControlsMenu();
4968         break;
4969     case 5: {
4970         LoadCampaign();
4971         Menu::addLabel(-1, accountactive->getName(), 5, 400);
4972         Menu::addButton(1, "Tutorial", 5, 300);
4973         Menu::addButton(2, "Challenge", 5, 240);
4974         Menu::addButton(3, "Delete User", 400, 10);
4975         Menu::addButton(4, "Main Menu", 5, 10);
4976         Menu::addButton(5, "Change User", 5, 180);
4977         Menu::addButton(6, "Campaign : " + accountactive->getCurrentCampaign(), 200, 420);
4978
4979         //show campaign map
4980         //with (2,-5) offset from old code
4981         Menu::addImage(-1, Mainmenuitems[7], 150 + 2, 60 - 5, 400, 400);
4982         //show levels
4983         int numlevels = accountactive->getCampaignChoicesMade();
4984         numlevels += numlevels > 0 ? campaignlevels[numlevels - 1].nextlevel.size() : 1;
4985         for (int i = 0; i < numlevels; i++) {
4986             XYZ midpoint = campaignlevels[i].getCenter();
4987             float itemsize = campaignlevels[i].getWidth();
4988             const bool active = i >= accountactive->getCampaignChoicesMade();
4989             if (!active)
4990                 itemsize /= 2;
4991
4992             if (i >= 1) {
4993                 XYZ start = campaignlevels[i - 1].getCenter();
4994                 Menu::addMapLine(start.x, start.y, midpoint.x - start.x, midpoint.y - start.y, 0.5, active ? 1 : 0.5, active ? 1 : 0.5, 0, 0);
4995             }
4996             Menu::addMapMarker(NB_CAMPAIGN_MENU_ITEM + i, Mapcircletexture,
4997                                midpoint.x - itemsize / 2, midpoint.y - itemsize / 2, itemsize, itemsize, active ? 1 : 0.5, 0, 0);
4998
4999             if (active) {
5000                 Menu::addMapLabel(-2, campaignlevels[i].description,
5001                                   campaignlevels[i].getStartX() + 10,
5002                                   campaignlevels[i].getStartY() - 4);
5003             }
5004         }
5005     }
5006     break;
5007     case 6:
5008         Menu::addLabel(-1, "Are you sure you want to delete this user?", 10, 400);
5009         Menu::addButton(1, "Yes", 10, 360);
5010         Menu::addButton(2, "No", 10, 320);
5011         break;
5012     case 7:
5013         if (Account::getNbAccounts() < 8)
5014             Menu::addButton(0, "New User", 10, 400);
5015         else
5016             Menu::addLabel(0, "No More Users", 10, 400);
5017         Menu::addLabel(-2, "", 20, 400);
5018         Menu::addButton(Account::getNbAccounts() + 1, "Back", 10, 10);
5019         for (int i = 0; i < Account::getNbAccounts(); i++)
5020             Menu::addButton(i + 1, Account::get(i)->getName(), 10, 340 - 20 * (i + 1));
5021         break;
5022     case 8:
5023         Menu::addButton(0, "Easier", 10, 400);
5024         Menu::addButton(1, "Difficult", 10, 360);
5025         Menu::addButton(2, "Insane", 10, 320);
5026         break;
5027     case 9:
5028         for (int i = 0; i < numchallengelevels; i++) {
5029             char temp[255];
5030             string name = "";
5031             sprintf (temp, "Level %d", i + 1);
5032             for (int j = strlen(temp); j < 17; j++)
5033                 strcat(temp, " ");
5034             name += temp;
5035             sprintf (temp, "%d", (int)accountactive->getHighScore(i));
5036             for (int j = strlen(temp); j < (32 - 17); j++)
5037                 strcat(temp, " ");
5038             name += temp;
5039             sprintf (temp, "%d:", (int)(((int)accountactive->getFastTime(i) - (int)(accountactive->getFastTime(i)) % 60) / 60));
5040             if ((int)(accountactive->getFastTime(i)) % 60 < 10)
5041                 strcat(temp, "0");
5042             name += temp;
5043             sprintf (temp, "%d", (int)(accountactive->getFastTime(i)) % 60);
5044             name += temp;
5045
5046             Menu::addButton(i, name, 10, 400 - i * 25, i > accountactive->getProgress() ? 0.5 : 1, 0, 0);
5047         }
5048
5049         Menu::addButton(-1, "             High Score      Best Time", 10, 440);
5050         Menu::addButton(numchallengelevels, "Back", 10, 10);
5051         break;
5052     case 10: {
5053         Menu::addLabel(0, "Congratulations!", 220, 330);
5054         Menu::addLabel(1, "You have avenged your family and", 140, 300);
5055         Menu::addLabel(2, "restored peace to the island of Lugaru.", 110, 270);
5056         Menu::addButton(3, "Back", 10, 10);
5057         char sbuf[256];
5058         sprintf(sbuf, "Your score:         %d", (int)accountactive->getCampaignScore());
5059         Menu::addLabel(4, sbuf, 190, 200);
5060         sprintf(sbuf, "Highest score:      %d", (int)accountactive->getCampaignHighScore());
5061         Menu::addLabel(5, sbuf, 190, 180);
5062     }
5063     break;
5064     case 18:
5065         Menu::addButton(0, "", 70, 400);
5066         Menu::addButton(1, "", 10, 360);
5067         Menu::addButton(2, "", 40, 320);
5068         Menu::addButton(3, "Back", 10, 10);
5069         updateStereoConfigMenu();
5070         break;
5071     }
5072 }
5073
5074 extern set<pair<int,int>> resolutions;
5075
5076 void MenuTick()
5077 {
5078     //menu buttons
5079     selected = Menu::getSelected(mousecoordh * 640 / screenwidth, 480 - mousecoordv * 480 / screenheight);
5080
5081     // some specific case where we do something even if the left mouse button is not pressed.
5082     if ((mainmenu == 5) && (endgame == 2)) {
5083         accountactive->endGame();
5084         endgame = 0;
5085     }
5086     if (mainmenu == 10)
5087         endgame = 2;
5088     if (mainmenu == 18 && Input::isKeyPressed(MOUSEBUTTON2) && selected == 1) {
5089         stereoseparation -= 0.001;
5090         updateStereoConfigMenu();
5091     }
5092
5093     static int oldmainmenu = mainmenu;
5094
5095     if (Input::MouseClicked() && (selected >= 0)) { // handling of the left mouse clic in menus
5096         set<pair<int,int>>::iterator newscreenresolution;
5097         switch (mainmenu) {
5098         case 1:
5099         case 2:
5100             switch (selected) {
5101             case 1:
5102                 if (gameon) { //resume
5103                     mainmenu = 0;
5104                     pause_sound(stream_menutheme);
5105                     resume_stream(leveltheme);
5106                 } else { //new game
5107                     fireSound(firestartsound);
5108                     flash();
5109                     mainmenu = (accountactive ? 5 : 7);
5110                     selected = -1;
5111                 }
5112                 break;
5113             case 2: //options
5114                 fireSound();
5115                 flash();
5116                 mainmenu = 3;
5117                 if (newdetail > 2)
5118                     newdetail = detail;
5119                 if (newdetail < 0)
5120                     newdetail = detail;
5121                 if (newscreenwidth > 3000)
5122                     newscreenwidth = screenwidth;
5123                 if (newscreenwidth < 0)
5124                     newscreenwidth = screenwidth;
5125                 if (newscreenheight > 3000)
5126                     newscreenheight = screenheight;
5127                 if (newscreenheight < 0)
5128                     newscreenheight = screenheight;
5129                 break;
5130             case 3:
5131                 fireSound();
5132                 flash();
5133                 if (gameon) { //end game
5134                     gameon = 0;
5135                     mainmenu = 1;
5136                 } else { //quit
5137                     tryquit = 1;
5138                     pause_sound(stream_menutheme);
5139                 }
5140                 break;
5141             }
5142             break;
5143         case 3:
5144             fireSound();
5145             switch (selected) {
5146             case 0:
5147                 newscreenresolution = resolutions.find(make_pair(newscreenwidth, newscreenheight));
5148                 /* Next one (end() + 1 is also end() so the ++ is safe even if it was not found) */
5149                 newscreenresolution++;
5150                 if (newscreenresolution == resolutions.end()) {
5151                     /* It was the last one (or not found), go back to the beginning */
5152                     newscreenresolution = resolutions.begin();
5153                 }
5154                 newscreenwidth  = newscreenresolution->first;
5155                 newscreenheight = newscreenresolution->second;
5156                 break;
5157             case 1:
5158                 newdetail++;
5159                 if (newdetail > 2)
5160                     newdetail = 0;
5161                 break;
5162             case 2:
5163                 bloodtoggle++;
5164                 if (bloodtoggle > 2)
5165                     bloodtoggle = 0;
5166                 break;
5167             case 3:
5168                 difficulty++;
5169                 if (difficulty > 2)
5170                     difficulty = 0;
5171                 break;
5172             case 4:
5173                 ismotionblur = !ismotionblur;
5174                 break;
5175             case 5:
5176                 decals = !decals;
5177                 break;
5178             case 6:
5179                 musictoggle = !musictoggle;
5180                 if (musictoggle) {
5181                     emit_stream_np(stream_menutheme);
5182                 } else {
5183                     pause_sound(leveltheme);
5184                     pause_sound(stream_fighttheme);
5185                     pause_sound(stream_menutheme);
5186
5187                     for (int i = 0; i < 4; i++) {
5188                         oldmusicvolume[i] = 0;
5189                         musicvolume[i] = 0;
5190                     }
5191                 }
5192                 break;
5193             case 7: // controls
5194                 flash();
5195                 mainmenu = 4;
5196                 selected = -1;
5197                 keyselect = -1;
5198                 break;
5199             case 8:
5200                 flash();
5201                 SaveSettings();
5202                 mainmenu = gameon ? 2 : 1;
5203                 break;
5204             case 9:
5205                 invertmouse = !invertmouse;
5206                 break;
5207             case 10:
5208                 usermousesensitivity += .2;
5209                 if (usermousesensitivity > 2)
5210                     usermousesensitivity = .2;
5211                 break;
5212             case 11:
5213                 volume += .1f;
5214                 if (volume > 1.0001f)
5215                     volume = 0;
5216                 OPENAL_SetSFXMasterVolume((int)(volume * 255));
5217                 break;
5218             case 12:
5219                 flash();
5220                 newstereomode = stereomode;
5221                 mainmenu = 18;
5222                 keyselect = -1;
5223                 break;
5224             case 13:
5225                 showdamagebar = !showdamagebar;
5226                 break;
5227             case 14:
5228                 toggleFullscreen();
5229                 break;
5230             }
5231             updateSettingsMenu();
5232             break;
5233         case 4:
5234             if (!waiting) {
5235                 fireSound();
5236                 if (selected < (debugmode ? 10 : 9) && keyselect == -1)
5237                     keyselect = selected;
5238                 if (keyselect != -1)
5239                     setKeySelected();
5240                 if (selected == (debugmode ? 10 : 9)) {
5241                     flash();
5242                     mainmenu = 3;
5243                 }
5244             }
5245             updateControlsMenu();
5246             break;
5247         case 5:
5248             fireSound();
5249             flash();
5250             if ((selected - NB_CAMPAIGN_MENU_ITEM >= accountactive->getCampaignChoicesMade())) {
5251                 startbonustotal = 0;
5252
5253                 loading = 2;
5254                 loadtime = 0;
5255                 targetlevel = 7;
5256                 if (firstload)
5257                     TickOnceAfter();
5258                 else
5259                     LoadStuff();
5260                 whichchoice = selected - NB_CAMPAIGN_MENU_ITEM - accountactive->getCampaignChoicesMade();
5261                 actuallevel = (accountactive->getCampaignChoicesMade() > 0 ? campaignlevels[accountactive->getCampaignChoicesMade() - 1].nextlevel[whichchoice] : 0);
5262                 visibleloading = 1;
5263                 stillloading = 1;
5264                 Loadlevel(campaignlevels[actuallevel].mapname.c_str());
5265                 campaign = 1;
5266                 mainmenu = 0;
5267                 gameon = 1;
5268                 pause_sound(stream_menutheme);
5269             }
5270             switch (selected) {
5271             case 1:
5272                 startbonustotal = 0;
5273
5274                 loading = 2;
5275                 loadtime = 0;
5276                 targetlevel = -1;
5277                 if (firstload) {
5278                     TickOnceAfter();
5279                 } else
5280                     LoadStuff();
5281                 Loadlevel(-1);
5282
5283                 mainmenu = 0;
5284                 gameon = 1;
5285                 pause_sound(stream_menutheme);
5286                 break;
5287             case 2:
5288                 mainmenu = 9;
5289                 break;
5290             case 3:
5291                 mainmenu = 6;
5292                 break;
5293             case 4:
5294                 mainmenu = (gameon ? 2 : 1);
5295                 break;
5296             case 5:
5297                 mainmenu = 7;
5298                 break;
5299             case 6:
5300                 vector<string> campaigns = ListCampaigns();
5301                 vector<string>::iterator c;
5302                 if ((c = find(campaigns.begin(), campaigns.end(), accountactive->getCurrentCampaign())) == campaigns.end()) {
5303                     if (!campaigns.empty())
5304                         accountactive->setCurrentCampaign(campaigns.front());
5305                 } else {
5306                     c++;
5307                     if (c == campaigns.end())
5308                         c = campaigns.begin();
5309                     accountactive->setCurrentCampaign(*c);
5310                 }
5311                 LoadMenu();
5312                 break;
5313             }
5314             break;
5315         case 6:
5316             fireSound();
5317             if (selected == 1) {
5318                 flash();
5319                 accountactive = Account::destroy(accountactive);
5320                 mainmenu = 7;
5321             } else if (selected == 2) {
5322                 flash();
5323                 mainmenu = 5;
5324             }
5325             break;
5326         case 7:
5327             fireSound();
5328             if (selected == 0 && Account::getNbAccounts() < 8) {
5329                 entername = 1;
5330             } else if (selected < Account::getNbAccounts() + 1) {
5331                 flash();
5332                 mainmenu = 5;
5333                 accountactive = Account::get(selected - 1);
5334             } else if (selected == Account::getNbAccounts() + 1) {
5335                 flash();
5336                 if (accountactive)
5337                     mainmenu = 5;
5338                 else
5339                     mainmenu = 1;
5340                 displaytext[0].clear();
5341                 displayselected = 0;
5342                 entername = 0;
5343             }
5344             break;
5345         case 8:
5346             fireSound();
5347             flash();
5348             if (selected <= 2)
5349                 accountactive->setDifficulty(selected);
5350             mainmenu = 5;
5351             break;
5352         case 9:
5353             if (selected < numchallengelevels && selected <= accountactive->getProgress()) {
5354                 fireSound();
5355                 flash();
5356
5357                 startbonustotal = 0;
5358
5359                 loading = 2;
5360                 loadtime = 0;
5361                 targetlevel = selected;
5362                 if (firstload)
5363                     TickOnceAfter();
5364                 else
5365                     LoadStuff();
5366                 Loadlevel(selected);
5367                 campaign = 0;
5368
5369                 mainmenu = 0;
5370                 gameon = 1;
5371                 pause_sound(stream_menutheme);
5372             }
5373             if (selected == numchallengelevels) {
5374                 fireSound();
5375                 flash();
5376                 mainmenu = 5;
5377             }
5378             break;
5379         case 10:
5380             if (selected == 3) {
5381                 fireSound();
5382                 flash();
5383                 mainmenu = 5;
5384             }
5385             break;
5386         case 18:
5387             if (selected == 1)
5388                 stereoseparation += 0.001;
5389             else {
5390                 fireSound();
5391                 if (selected == 0) {
5392                     newstereomode = (StereoMode)(newstereomode + 1);
5393                     while (!CanInitStereo(newstereomode)) {
5394                         printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode), newstereomode);
5395                         newstereomode = (StereoMode)(newstereomode + 1);
5396                         if (newstereomode >= stereoCount)
5397                             newstereomode = stereoNone;
5398                     }
5399                 } else if (selected == 2) {
5400                     stereoreverse = !stereoreverse;
5401                 } else if (selected == 3) {
5402                     flash();
5403                     mainmenu = 3;
5404
5405                     stereomode = newstereomode;
5406                     InitStereo(stereomode);
5407                 }
5408             }
5409             updateStereoConfigMenu();
5410             break;
5411         }
5412     }
5413
5414     OPENAL_SetFrequency(channels[stream_menutheme], 22050);
5415
5416     if (entername) {
5417         inputText(displaytext[0], &displayselected);
5418         if (!waiting) { // the input as finished
5419             if (!displaytext[0].empty()) { // with enter
5420                 accountactive = Account::add(string(displaytext[0]));
5421
5422                 mainmenu = 8;
5423
5424                 flash();
5425
5426                 fireSound(firestartsound);
5427
5428                 displaytext[0].clear();
5429
5430                 displayselected = 0;
5431             }
5432             entername = 0;
5433             LoadMenu();
5434         }
5435
5436         displayblinkdelay -= multiplier;
5437         if (displayblinkdelay <= 0) {
5438             displayblinkdelay = .3;
5439             displayblink = !displayblink;
5440         }
5441     }
5442
5443     if (entername) {
5444         Menu::setText(0, displaytext[0], 20, 400, -1, -1);
5445         Menu::setText(-2, displayblink ? "_" : "", 20 + displayselected * 10, 400, -1, -1);
5446     }
5447
5448     if (oldmainmenu != mainmenu)
5449         LoadMenu();
5450     oldmainmenu = mainmenu;
5451
5452 }
5453
5454 void Game::Tick()
5455 {
5456     static XYZ facing, flatfacing;
5457     static int target;
5458
5459     for (int i = 0; i < 15; i++) {
5460         displaytime[i] += multiplier;
5461     }
5462
5463     keyboardfrozen = false;
5464     Input::Tick();
5465
5466     if (Input::isKeyPressed(SDL_SCANCODE_F6)) {
5467         if (Input::isKeyDown(SDL_SCANCODE_LSHIFT))
5468             stereoreverse = true;
5469         else
5470             stereoreverse = false;
5471
5472         if (stereoreverse)
5473             printf("Stereo reversed\n");
5474         else
5475             printf("Stereo unreversed\n");
5476     }
5477
5478     if (Input::isKeyDown(SDL_SCANCODE_F7)) {
5479         if (Input::isKeyDown(SDL_SCANCODE_LSHIFT))
5480             stereoseparation -= 0.001;
5481         else
5482             stereoseparation -= 0.010;
5483         printf("Stereo decreased increased to %f\n", stereoseparation);
5484     }
5485
5486     if (Input::isKeyDown(SDL_SCANCODE_F8)) {
5487         if (Input::isKeyDown(SDL_SCANCODE_LSHIFT))
5488             stereoseparation += 0.001;
5489         else
5490             stereoseparation += 0.010;
5491         printf("Stereo separation increased to %f\n", stereoseparation);
5492     }
5493
5494
5495     if (Input::isKeyPressed(SDL_SCANCODE_TAB) && tutoriallevel) {
5496         if (tutorialstage != 51)
5497             tutorialstagetime = tutorialmaxtime;
5498         emit_sound_np(consolefailsound, 128.);
5499     }
5500
5501     /*
5502     Values of mainmenu :
5503     1 Main menu
5504     2 Menu pause (resume/end game)
5505     3 Option menu
5506     4 Controls configuration menu
5507     5 Main game menu (choose level or challenge)
5508     6 Deleting user menu
5509     7 User managment menu (select/add)
5510     8 Choose difficulty menu
5511     9 Challenge level selection menu
5512     10 End of the campaign congratulation (is that really a menu?)
5513     11 Same that 9 ??? => unused
5514     18 stereo configuration
5515     */
5516
5517     if (!console) {
5518         //campaign over?
5519         if (mainmenu && endgame == 1)
5520             mainmenu = 10;
5521         //go to level select after completing a campaign level
5522         if (campaign && winfreeze && mainmenu == 0 && campaignlevels[actuallevel].choosenext == 1) {
5523             mainmenu = 5;
5524             gameon = 0;
5525             winfreeze = 0;
5526             fireSound();
5527             flash();
5528             if (musictoggle) {
5529                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
5530                 emit_stream_np(stream_menutheme);
5531                 pause_sound(leveltheme);
5532             }
5533             LoadMenu();
5534         }
5535         //escape key pressed
5536         if (Input::isKeyPressed(SDL_SCANCODE_ESCAPE) &&
5537                 (gameon || mainmenu == 0 || (mainmenu >= 3 && mainmenu != 8 && !(mainmenu == 7 && entername)))) {
5538             selected = -1;
5539             if (mainmenu == 0 && !winfreeze)
5540                 mainmenu = 2; //pause
5541             else if (mainmenu == 1 || mainmenu == 2) {
5542                 mainmenu = 0; //unpause
5543             }
5544             //play menu theme
5545             if (musictoggle && (mainmenu == 1 || mainmenu == 2)) {
5546                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
5547                 emit_stream_np(stream_menutheme);
5548                 pause_sound(leveltheme);
5549             }
5550             //on resume, play level music
5551             if (!mainmenu) {
5552                 pause_sound(stream_menutheme);
5553                 resume_stream(leveltheme);
5554             }
5555             //finished with settings menu
5556             if (mainmenu == 3) {
5557                 SaveSettings();
5558             }
5559             //effects
5560             if (mainmenu >= 3 && mainmenu != 8) {
5561                 fireSound();
5562                 flash();
5563             }
5564             //go back
5565             switch (mainmenu) {
5566             case 3:
5567             case 5:
5568                 mainmenu = gameon ? 2 : 1;
5569                 break;
5570             case 4:
5571             case 18:
5572                 mainmenu = 3;
5573                 break;
5574             case 6:
5575             case 7:
5576             case 9:
5577             case 10:
5578                 mainmenu = 5;
5579                 break;
5580             }
5581         }
5582     }
5583
5584     if (mainmenu) {
5585         MenuTick();
5586     }
5587
5588     if (!mainmenu) {
5589         if (hostile == 1)
5590             hostiletime += multiplier;
5591         else
5592             hostiletime = 0;
5593         if (!winfreeze)
5594             leveltime += multiplier;
5595
5596         //keys
5597         if (Input::isKeyPressed(SDL_SCANCODE_V) && debugmode) {
5598             freeze = !freeze;
5599             if (freeze) {
5600                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
5601             }
5602         }
5603
5604         if (Input::isKeyPressed(consolekey) && debugmode) {
5605             console = !console;
5606             if (console) {
5607                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
5608             } else {
5609                 freeze = 0;
5610                 waiting = false;
5611             }
5612         }
5613
5614         if (console)
5615             freeze = 1;
5616         if (console && !Input::isKeyDown(SDL_SCANCODE_LGUI)) {
5617             inputText(consoletext[0], &consoleselected);
5618             if (!waiting) {
5619                 if (!consoletext[0].empty()) {
5620                     cmd_dispatch(consoletext[0]);
5621                     for (int k = 14; k >= 1; k--) {
5622                         consoletext[k] = consoletext[k - 1];
5623                     }
5624                     consoletext[0].clear();
5625                     consoleselected = 0;
5626                 }
5627             }
5628
5629             consoleblinkdelay -= multiplier;
5630             if (consoleblinkdelay <= 0) {
5631                 consoleblinkdelay = .3;
5632                 consoleblink = !consoleblink;
5633             }
5634         }
5635
5636         static int oldwinfreeze;
5637         if (winfreeze && !oldwinfreeze) {
5638             OPENAL_SetFrequency(OPENAL_ALL, 0.001);
5639             emit_sound_np(consolesuccesssound);
5640         }
5641         if (winfreeze == 0)
5642             oldwinfreeze = winfreeze;
5643         else
5644             oldwinfreeze++;
5645
5646         if ((Input::isKeyPressed(jumpkey) || Input::isKeyPressed(SDL_SCANCODE_SPACE)) && !campaign)
5647             if (winfreeze)
5648                 winfreeze = 0;
5649         if ((Input::isKeyDown(SDL_SCANCODE_ESCAPE)) && !campaign && gameon) {
5650             if (console) {
5651                 console = false;
5652                 freeze = 0;
5653             } else if (winfreeze) {
5654                 mainmenu = 9;
5655                 gameon = 0;
5656             }
5657         }
5658
5659
5660
5661         if (!freeze && !winfreeze && !(mainmenu && gameon) && (gameon || !gamestarted)) {
5662
5663             //dialogues
5664             static float talkdelay = 0;
5665
5666             if (indialogue != -1)
5667                 talkdelay = 1;
5668             talkdelay -= multiplier;
5669
5670             if (talkdelay <= 0 && indialogue == -1 && animation[Person::players[0]->animTarget].height != highheight)
5671                 for (int i = 0; i < numdialogues; i++) {
5672                     unsigned realdialoguetype;
5673                     bool special;
5674                     /* FIXME - Seems like modulo done with ifs */
5675                     if (dialoguetype[i] > 49) {
5676                         realdialoguetype = dialoguetype[i] - 50;
5677                         special = 1;
5678                     } else if (dialoguetype[i] > 39) {
5679                         realdialoguetype = dialoguetype[i] - 40;
5680                         special = 1;
5681                     } else if (dialoguetype[i] > 29) {
5682                         realdialoguetype = dialoguetype[i] - 30;
5683                         special = 1;
5684                     } else if (dialoguetype[i] > 19) {
5685                         realdialoguetype = dialoguetype[i] - 20;
5686                         special = 1;
5687                     } else if (dialoguetype[i] > 9) {
5688                         realdialoguetype = dialoguetype[i] - 10;
5689                         special = 1;
5690                     } else {
5691                         realdialoguetype = dialoguetype[i];
5692                         special = 0;
5693                     }
5694                     if ((!hostile || dialoguetype[i] > 40 && dialoguetype[i] < 50) &&
5695                             realdialoguetype < Person::players.size() &&
5696                             realdialoguetype > 0 &&
5697                             (dialoguegonethrough[i] == 0 || !special) &&
5698                             (special || Input::isKeyPressed(attackkey))) {
5699                         if (distsq(&Person::players[0]->coords, &Person::players[realdialoguetype]->coords) < 6 ||
5700                                 Person::players[realdialoguetype]->howactive >= typedead1 ||
5701                                 dialoguetype[i] > 40 && dialoguetype[i] < 50) {
5702                             whichdialogue = i;
5703                             for (int j = 0; j < numdialogueboxes[whichdialogue]; j++) {
5704                                 Person::players[participantfocus[whichdialogue][j]]->coords = participantlocation[whichdialogue][participantfocus[whichdialogue][j]];
5705                                 Person::players[participantfocus[whichdialogue][j]]->yaw = participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
5706                                 Person::players[participantfocus[whichdialogue][j]]->targetyaw = participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
5707                                 Person::players[participantfocus[whichdialogue][j]]->velocity = 0;
5708                                 Person::players[participantfocus[whichdialogue][j]]->animTarget = Person::players[participantfocus[whichdialogue][j]]->getIdle();
5709                                 Person::players[participantfocus[whichdialogue][j]]->frameTarget = 0;
5710                             }
5711                             directing = 0;
5712                             indialogue = 0;
5713                             dialoguetime = 0;
5714                             dialoguegonethrough[i]++;
5715                             if (dialogueboxsound[whichdialogue][indialogue] != 0) {
5716                                 playdialogueboxsound();
5717                             }
5718                         }
5719                     }
5720                 }
5721
5722             windvar += multiplier;
5723             smoketex += multiplier;
5724             tutorialstagetime += multiplier;
5725
5726             //hotspots
5727             static float hotspotvisual[40];
5728             if (numhotspots) {
5729                 XYZ hotspotsprite;
5730                 if (editorenabled)
5731                     for (int i = 0; i < numhotspots; i++)
5732                         hotspotvisual[i] -= multiplier / 320;
5733
5734                 for (int i = 0; i < numhotspots; i++) {
5735                     while (hotspotvisual[i] < 0) {
5736                         hotspotsprite = 0;
5737                         hotspotsprite.x = float(abs(Random() % 100000)) / 100000 * hotspotsize[i];
5738                         hotspotsprite = DoRotation(hotspotsprite, 0, 0, Random() % 360);
5739                         hotspotsprite = DoRotation(hotspotsprite, 0, Random() % 360, 0);
5740                         hotspotsprite += hotspot[i];
5741                         Sprite::MakeSprite(breathsprite, hotspotsprite, hotspotsprite * 0, 1, 0.5, 0, 7, 0.4);
5742                         hotspotvisual[i] += 0.1 / hotspotsize[i] / hotspotsize[i] / hotspotsize[i];
5743                     }
5744                 }
5745
5746                 for (int i = 0; i < numhotspots; i++) {
5747                     if (hotspottype[i] <= 10 && hotspottype[i] > 0) {
5748                         hotspot[i] = Person::players[hotspottype[i]]->coords;
5749                     }
5750                 }
5751             }
5752
5753             //Tutorial
5754             if (tutoriallevel) {
5755                 doTutorial();
5756             }
5757
5758             //bonuses
5759             if (tutoriallevel != 1) {
5760                 if (bonustime == 0 &&
5761                         bonus != solidhit &&
5762                         bonus != spinecrusher &&
5763                         bonus != tracheotomy &&
5764                         bonus != backstab &&
5765                         bonusvalue > 10) {
5766                     emit_sound_np(consolesuccesssound);
5767                 }
5768             } else if (bonustime == 0) {
5769                 emit_sound_np(fireendsound);
5770             }
5771             if (bonustime == 0) {
5772                 if (bonus != solidhit &&
5773                         bonus != twoxcombo &&
5774                         bonus != threexcombo &&
5775                         bonus != fourxcombo &&
5776                         bonus != megacombo)
5777                     bonusnum[bonus]++;
5778                 else
5779                     bonusnum[bonus] += 0.15;
5780                 if (tutoriallevel)
5781                     bonusvalue = 0;
5782                 bonusvalue /= bonusnum[bonus];
5783                 bonustotal += bonusvalue;
5784             }
5785             bonustime += multiplier;
5786
5787             //snow effects
5788             if (environment == snowyenvironment) {
5789                 precipdelay -= multiplier;
5790                 while (precipdelay < 0) {
5791                     precipdelay += .04;
5792                     if (!detail)
5793                         precipdelay += .04;
5794                     XYZ footvel, footpoint;
5795
5796                     footvel = 0;
5797                     footpoint = viewer + viewerfacing * 6;
5798                     footpoint.y += ((float)abs(Random() % 1200)) / 100 - 6;
5799                     footpoint.x += ((float)abs(Random() % 1200)) / 100 - 6;
5800                     footpoint.z += ((float)abs(Random() % 1200)) / 100 - 6;
5801                     Sprite::MakeSprite(snowsprite, footpoint, footvel, 1, 1, 1, .1, 1);
5802                 }
5803             }
5804
5805
5806             doAerialAcrobatics();
5807
5808
5809             static XYZ oldviewer;
5810
5811             //control keys
5812             if (indialogue == -1) {
5813                 Person::players[0]->forwardkeydown = Input::isKeyDown(forwardkey);
5814                 Person::players[0]->leftkeydown = Input::isKeyDown(leftkey);
5815                 Person::players[0]->backkeydown = Input::isKeyDown(backkey);
5816                 Person::players[0]->rightkeydown = Input::isKeyDown(rightkey);
5817                 Person::players[0]->jumpkeydown = Input::isKeyDown(jumpkey);
5818                 Person::players[0]->crouchkeydown = Input::isKeyDown(crouchkey);
5819                 Person::players[0]->drawkeydown = Input::isKeyDown(drawkey);
5820                 Person::players[0]->throwkeydown = Input::isKeyDown(throwkey);
5821             } else {
5822                 Person::players[0]->forwardkeydown = 0;
5823                 Person::players[0]->leftkeydown = 0;
5824                 Person::players[0]->backkeydown = 0;
5825                 Person::players[0]->rightkeydown = 0;
5826                 Person::players[0]->jumpkeydown = 0;
5827                 Person::players[0]->crouchkeydown = 0;
5828                 Person::players[0]->drawkeydown = 0;
5829                 Person::players[0]->throwkeydown = 0;
5830             }
5831
5832             if (!Person::players[0]->jumpkeydown)
5833                 Person::players[0]->jumpclimb = 0;
5834
5835
5836             if (indialogue != -1) {
5837                 cameramode = 1;
5838                 if (directing) {
5839                     facing = 0;
5840                     facing.z = -1;
5841
5842                     facing = DoRotation(facing, -pitch, 0, 0);
5843                     facing = DoRotation(facing, 0, 0 - yaw, 0);
5844
5845                     flatfacing = 0;
5846                     flatfacing.z = -1;
5847
5848                     flatfacing = DoRotation(flatfacing, 0, -yaw, 0);
5849
5850                     if (Input::isKeyDown(forwardkey))
5851                         viewer += facing * multiplier * 4;
5852                     if (Input::isKeyDown(backkey))
5853                         viewer -= facing * multiplier * 4;
5854                     if (Input::isKeyDown(leftkey))
5855                         viewer += DoRotation(flatfacing * multiplier, 0, 90, 0) * 4;
5856                     if (Input::isKeyDown(rightkey))
5857                         viewer += DoRotation(flatfacing * multiplier, 0, -90, 0) * 4;
5858                     if (Input::isKeyDown(jumpkey))
5859                         viewer.y += multiplier * 4;
5860                     if (Input::isKeyDown(crouchkey))
5861                         viewer.y -= multiplier * 4;
5862                     if (     Input::isKeyPressed(SDL_SCANCODE_1) ||
5863                              Input::isKeyPressed(SDL_SCANCODE_2) ||
5864                              Input::isKeyPressed(SDL_SCANCODE_3) ||
5865                              Input::isKeyPressed(SDL_SCANCODE_4) ||
5866                              Input::isKeyPressed(SDL_SCANCODE_5) ||
5867                              Input::isKeyPressed(SDL_SCANCODE_6) ||
5868                              Input::isKeyPressed(SDL_SCANCODE_7) ||
5869                              Input::isKeyPressed(SDL_SCANCODE_8) ||
5870                              Input::isKeyPressed(SDL_SCANCODE_9) ||
5871                              Input::isKeyPressed(SDL_SCANCODE_0) ||
5872                              Input::isKeyPressed(SDL_SCANCODE_MINUS)) {
5873                         int whichend;
5874                         if (Input::isKeyPressed(SDL_SCANCODE_1)) whichend = 1;
5875                         if (Input::isKeyPressed(SDL_SCANCODE_2)) whichend = 2;
5876                         if (Input::isKeyPressed(SDL_SCANCODE_3)) whichend = 3;
5877                         if (Input::isKeyPressed(SDL_SCANCODE_4)) whichend = 4;
5878                         if (Input::isKeyPressed(SDL_SCANCODE_5)) whichend = 5;
5879                         if (Input::isKeyPressed(SDL_SCANCODE_6)) whichend = 6;
5880                         if (Input::isKeyPressed(SDL_SCANCODE_7)) whichend = 7;
5881                         if (Input::isKeyPressed(SDL_SCANCODE_8)) whichend = 8;
5882                         if (Input::isKeyPressed(SDL_SCANCODE_9)) whichend = 9;
5883                         if (Input::isKeyPressed(SDL_SCANCODE_0)) whichend = 0;
5884                         if (Input::isKeyPressed(SDL_SCANCODE_MINUS))
5885                             whichend = -1;
5886                         if (whichend != -1) {
5887                             participantfocus[whichdialogue][indialogue] = whichend;
5888                             participantlocation[whichdialogue][whichend] = Person::players[whichend]->coords;
5889                             participantyaw[whichdialogue][whichend] = Person::players[whichend]->yaw;
5890                         }
5891                         if (whichend == -1) {
5892                             participantfocus[whichdialogue][indialogue] = -1;
5893                         }
5894                         if (Person::players[participantfocus[whichdialogue][indialogue]]->dead) {
5895                             indialogue = -1;
5896                             directing = 0;
5897                             cameramode = 0;
5898                         }
5899                         dialoguecamera[whichdialogue][indialogue] = viewer;
5900                         dialoguecamerayaw[whichdialogue][indialogue] = yaw;
5901                         dialoguecamerapitch[whichdialogue][indialogue] = pitch;
5902                         indialogue++;
5903                         if (indialogue < numdialogueboxes[whichdialogue]) {
5904                             if (dialogueboxsound[whichdialogue][indialogue] != 0) {
5905                                 playdialogueboxsound();
5906                             }
5907                         }
5908
5909                         for (unsigned j = 0; j < Person::players.size(); j++) {
5910                             participantfacing[whichdialogue][indialogue][j] = participantfacing[whichdialogue][indialogue - 1][j];
5911                         }
5912                     }
5913                     //TODO: should these be KeyDown or KeyPressed?
5914                     if (     Input::isKeyDown(SDL_SCANCODE_KP_1) ||
5915                              Input::isKeyDown(SDL_SCANCODE_KP_2) ||
5916                              Input::isKeyDown(SDL_SCANCODE_KP_3) ||
5917                              Input::isKeyDown(SDL_SCANCODE_KP_4) ||
5918                              Input::isKeyDown(SDL_SCANCODE_KP_5) ||
5919                              Input::isKeyDown(SDL_SCANCODE_KP_6) ||
5920                              Input::isKeyDown(SDL_SCANCODE_KP_7) ||
5921                              Input::isKeyDown(SDL_SCANCODE_KP_8) ||
5922                              Input::isKeyDown(SDL_SCANCODE_KP_9) ||
5923                              Input::isKeyDown(SDL_SCANCODE_KP_0)) {
5924                         int whichend;
5925                         if (Input::isKeyDown(SDL_SCANCODE_KP_1)) whichend = 1;
5926                         if (Input::isKeyDown(SDL_SCANCODE_KP_2)) whichend = 2;
5927                         if (Input::isKeyDown(SDL_SCANCODE_KP_3)) whichend = 3;
5928                         if (Input::isKeyDown(SDL_SCANCODE_KP_4)) whichend = 4;
5929                         if (Input::isKeyDown(SDL_SCANCODE_KP_5)) whichend = 5;
5930                         if (Input::isKeyDown(SDL_SCANCODE_KP_6)) whichend = 6;
5931                         if (Input::isKeyDown(SDL_SCANCODE_KP_7)) whichend = 7;
5932                         if (Input::isKeyDown(SDL_SCANCODE_KP_8)) whichend = 8;
5933                         if (Input::isKeyDown(SDL_SCANCODE_KP_9)) whichend = 9;
5934                         if (Input::isKeyDown(SDL_SCANCODE_KP_0)) whichend = 0;
5935                         participantfacing[whichdialogue][indialogue][whichend] = facing;
5936                     }
5937                     if (indialogue >= numdialogueboxes[whichdialogue]) {
5938                         indialogue = -1;
5939                         directing = 0;
5940                         cameramode = 0;
5941                     }
5942                 }
5943                 if (!directing) {
5944                     pause_sound(whooshsound);
5945                     viewer = dialoguecamera[whichdialogue][indialogue];
5946                     viewer.y = max((double)viewer.y, terrain.getHeight(viewer.x, viewer.z) + .1);
5947                     yaw = dialoguecamerayaw[whichdialogue][indialogue];
5948                     pitch = dialoguecamerapitch[whichdialogue][indialogue];
5949                     if (dialoguetime > 0.5)
5950                         if (     Input::isKeyPressed(SDL_SCANCODE_1) ||
5951                                  Input::isKeyPressed(SDL_SCANCODE_2) ||
5952                                  Input::isKeyPressed(SDL_SCANCODE_3) ||
5953                                  Input::isKeyPressed(SDL_SCANCODE_4) ||
5954                                  Input::isKeyPressed(SDL_SCANCODE_5) ||
5955                                  Input::isKeyPressed(SDL_SCANCODE_6) ||
5956                                  Input::isKeyPressed(SDL_SCANCODE_7) ||
5957                                  Input::isKeyPressed(SDL_SCANCODE_8) ||
5958                                  Input::isKeyPressed(SDL_SCANCODE_9) ||
5959                                  Input::isKeyPressed(SDL_SCANCODE_0) ||
5960                                  Input::isKeyPressed(SDL_SCANCODE_MINUS) ||
5961                                  Input::isKeyPressed(attackkey)) {
5962                             indialogue++;
5963                             if (indialogue < numdialogueboxes[whichdialogue]) {
5964                                 if (dialogueboxsound[whichdialogue][indialogue] != 0) {
5965                                     playdialogueboxsound();
5966                                     if (dialogueboxsound[whichdialogue][indialogue] == -5) {
5967                                         hotspot[numhotspots] = Person::players[0]->coords;
5968                                         hotspotsize[numhotspots] = 10;
5969                                         hotspottype[numhotspots] = -1;
5970
5971                                         numhotspots++;
5972                                     }
5973                                     if (dialogueboxsound[whichdialogue][indialogue] == -6) {
5974                                         hostile = 1;
5975                                     }
5976
5977                                     if (Person::players[participantfocus[whichdialogue][indialogue]]->dead) {
5978                                         indialogue = -1;
5979                                         directing = 0;
5980                                         cameramode = 0;
5981                                     }
5982                                 }
5983                             }
5984                         }
5985                     if (indialogue >= numdialogueboxes[whichdialogue]) {
5986                         indialogue = -1;
5987                         directing = 0;
5988                         cameramode = 0;
5989                         if (dialoguetype[whichdialogue] > 19 && dialoguetype[whichdialogue] < 30) {
5990                             hostile = 1;
5991                         }
5992                         if (dialoguetype[whichdialogue] > 29 && dialoguetype[whichdialogue] < 40) {
5993                             windialogue = true;
5994                         }
5995                         if (dialoguetype[whichdialogue] > 49 && dialoguetype[whichdialogue] < 60) {
5996                             hostile = 1;
5997                             for (unsigned i = 1; i < Person::players.size(); i++) {
5998                                 Person::players[i]->aitype = attacktypecutoff;
5999                             }
6000                         }
6001                     }
6002                 }
6003             }
6004
6005             if (!Person::players[0]->jumpkeydown) {
6006                 Person::players[0]->jumptogglekeydown = 0;
6007             }
6008             if (Person::players[0]->jumpkeydown &&
6009                     Person::players[0]->animTarget != jumpupanim &&
6010                     Person::players[0]->animTarget != jumpdownanim &&
6011                     !Person::players[0]->isFlip())
6012                 Person::players[0]->jumptogglekeydown = 1;
6013
6014
6015             dialoguetime += multiplier;
6016             hawkyaw += multiplier * 25;
6017             realhawkcoords = 0;
6018             realhawkcoords.x = 25;
6019             realhawkcoords = DoRotation(realhawkcoords, 0, hawkyaw, 0) + hawkcoords;
6020             hawkcalldelay -= multiplier / 2;
6021
6022             if (hawkcalldelay <= 0) {
6023                 emit_sound_at(hawksound, realhawkcoords);
6024
6025                 hawkcalldelay = 16 + abs(Random() % 8);
6026             }
6027
6028             doDebugKeys();
6029
6030             doAttacks();
6031
6032             doPlayerCollisions();
6033
6034             doJumpReversals();
6035
6036             for (unsigned k = 0; k < Person::players.size(); k++)
6037                 if (k != 0 && Person::players[k]->immobile)
6038                     Person::players[k]->coords = Person::players[k]->realoldcoords;
6039
6040             for (unsigned k = 0; k < Person::players.size(); k++) {
6041                 if (!isnormal(Person::players[k]->coords.x) || !isnormal(Person::players[k]->coords.y) || !isnormal(Person::players[k]->coords.z)) {
6042                     if (!isnormal(Person::players[k]->coords.x) || !isnormal(Person::players[k]->coords.y) || !isnormal(Person::players[k]->coords.z)) {
6043                         Person::players[k]->DoDamage(1000);
6044                     }
6045                 }
6046             }
6047
6048             //respawn
6049             static bool respawnkeydown;
6050             if (!editorenabled &&
6051                     (whichlevel != -2 &&
6052                      (Input::isKeyDown(SDL_SCANCODE_Z) &&
6053                       Input::isKeyDown(SDL_SCANCODE_LGUI) &&
6054                       debugmode) ||
6055                      (Input::isKeyDown(jumpkey) &&
6056                       !respawnkeydown &&
6057                       !oldattackkey &&
6058                       Person::players[0]->dead))) {
6059                 targetlevel = whichlevel;
6060                 loading = 1;
6061                 leveltime = 5;
6062             }
6063             if (!Input::isKeyDown(jumpkey))
6064                 respawnkeydown = 0;
6065             if (Input::isKeyDown(jumpkey))
6066                 respawnkeydown = 1;
6067
6068
6069
6070
6071             static bool movekey;
6072
6073             //?
6074             for (unsigned i = 0; i < Person::players.size(); i++) {
6075                 static float oldtargetyaw;
6076                 if (!Person::players[i]->skeleton.free) {
6077                     oldtargetyaw = Person::players[i]->targetyaw;
6078                     if (i == 0 && indialogue == -1) {
6079                         //TODO: refactor repetitive code
6080                         if (!animation[Person::players[0]->animTarget].attack &&
6081                                 Person::players[0]->animTarget != staggerbackhighanim &&
6082                                 Person::players[0]->animTarget != staggerbackhardanim &&
6083                                 Person::players[0]->animTarget != crouchremoveknifeanim &&
6084                                 Person::players[0]->animTarget != removeknifeanim &&
6085                                 Person::players[0]->animTarget != backhandspringanim &&
6086                                 Person::players[0]->animTarget != dodgebackanim &&
6087                                 Person::players[0]->animTarget != walljumprightkickanim &&
6088                                 Person::players[0]->animTarget != walljumpleftkickanim) {
6089                             if (cameramode)
6090                                 Person::players[0]->targetyaw = 0;
6091                             else
6092                                 Person::players[0]->targetyaw = -yaw + 180;
6093                         }
6094
6095                         facing = 0;
6096                         facing.z = -1;
6097
6098                         flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
6099                         if (cameramode) {
6100                             facing = flatfacing;
6101                         } else {
6102                             facing = DoRotation(facing, -pitch, 0, 0);
6103                             facing = DoRotation(facing, 0, 0 - yaw, 0);
6104                         }
6105
6106                         Person::players[0]->lookyaw = -yaw;
6107
6108                         Person::players[i]->targetheadyaw = yaw;
6109                         Person::players[i]->targetheadpitch = pitch;
6110                     }
6111                     if (i != 0 && Person::players[i]->aitype == playercontrolled && indialogue == -1) {
6112                         if (!animation[Person::players[i]->animTarget].attack &&
6113                                 Person::players[i]->animTarget != staggerbackhighanim &&
6114                                 Person::players[i]->animTarget != staggerbackhardanim &&
6115                                 Person::players[i]->animTarget != crouchremoveknifeanim &&
6116                                 Person::players[i]->animTarget != removeknifeanim &&
6117                                 Person::players[i]->animTarget != backhandspringanim &&
6118                                 Person::players[i]->animTarget != dodgebackanim &&
6119                                 Person::players[i]->animTarget != walljumprightkickanim &&
6120                                 Person::players[i]->animTarget != walljumpleftkickanim) {
6121                             Person::players[i]->targetyaw = -Person::players[i]->lookyaw + 180;
6122                         }
6123
6124                         facing = 0;
6125                         facing.z = -1;
6126
6127                         flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
6128
6129                         facing = DoRotation(facing, -Person::players[i]->lookpitch, 0, 0);
6130                         facing = DoRotation(facing, 0, 0 - Person::players[i]->lookyaw, 0);
6131
6132                         Person::players[i]->targetheadyaw = Person::players[i]->lookyaw;
6133                         Person::players[i]->targetheadpitch = Person::players[i]->lookpitch;
6134                     }
6135                     if (indialogue != -1) {
6136                         Person::players[i]->targetheadyaw = 180 - roughDirection(participantfacing[whichdialogue][indialogue][i]);
6137                         Person::players[i]->targetheadpitch = pitchOf(participantfacing[whichdialogue][indialogue][i]);
6138                     }
6139
6140                     if (leveltime < .5)
6141                         numenvsounds = 0;
6142
6143                     Person::players[i]->avoidsomething = 0;
6144
6145                     //avoid flaming things
6146                     for (int j = 0; j < objects.numobjects; j++)
6147                         if (objects.onfire[j])
6148                             if (distsq(&Person::players[i]->coords, &objects.position[j]) < sq(objects.scale[j]) * 200)
6149                                 if (     distsq(&Person::players[i]->coords, &objects.position[j]) <
6150                                          distsq(&Person::players[i]->coords, &Person::players[0]->coords)) {
6151                                     Person::players[i]->collided = 0;
6152                                     Person::players[i]->avoidcollided = 1;
6153                                     if (Person::players[i]->avoidsomething == 0 ||
6154                                             distsq(&Person::players[i]->coords, &objects.position[j]) <
6155                                             distsq(&Person::players[i]->coords, &Person::players[i]->avoidwhere)) {
6156                                         Person::players[i]->avoidwhere = objects.position[j];
6157                                         Person::players[i]->avoidsomething = 1;
6158                                     }
6159                                 }
6160
6161                     //avoid flaming players
6162                     for (unsigned j = 0; j < Person::players.size(); j++)
6163                         if (Person::players[j]->onfire)
6164                             if (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < sq(0.3) * 200)
6165                                 if (     distsq(&Person::players[i]->coords, &Person::players[j]->coords) <
6166                                          distsq(&Person::players[i]->coords, &Person::players[0]->coords)) {
6167                                     Person::players[i]->collided = 0;
6168                                     Person::players[i]->avoidcollided = 1;
6169                                     if (Person::players[i]->avoidsomething == 0 ||
6170                                             distsq(&Person::players[i]->coords, &Person::players[j]->coords) <
6171                                             distsq(&Person::players[i]->coords, &Person::players[i]->avoidwhere)) {
6172                                         Person::players[i]->avoidwhere = Person::players[j]->coords;
6173                                         Person::players[i]->avoidsomething = 1;
6174                                     }
6175                                 }
6176
6177                     if (Person::players[i]->collided > .8)
6178                         Person::players[i]->avoidcollided = 0;
6179
6180                     doAI(i);
6181
6182                     if (animation[Person::players[i]->animTarget].attack == reversed) {
6183                         //Person::players[i]->targetyaw=Person::players[i]->yaw;
6184                         Person::players[i]->forwardkeydown = 0;
6185                         Person::players[i]->leftkeydown = 0;
6186                         Person::players[i]->backkeydown = 0;
6187                         Person::players[i]->rightkeydown = 0;
6188                         Person::players[i]->jumpkeydown = 0;
6189                         Person::players[i]->attackkeydown = 0;
6190                         //Person::players[i]->crouchkeydown=0;
6191                         Person::players[i]->throwkeydown = 0;
6192                     }
6193
6194                     if (indialogue != -1) {
6195                         Person::players[i]->forwardkeydown = 0;
6196                         Person::players[i]->leftkeydown = 0;
6197                         Person::players[i]->backkeydown = 0;
6198                         Person::players[i]->rightkeydown = 0;
6199                         Person::players[i]->jumpkeydown = 0;
6200                         Person::players[i]->crouchkeydown = 0;
6201                         Person::players[i]->drawkeydown = 0;
6202                         Person::players[i]->throwkeydown = 0;
6203                     }
6204
6205                     if (Person::players[i]->collided < -.3)
6206                         Person::players[i]->collided = -.3;
6207                     if (Person::players[i]->collided > 1)
6208                         Person::players[i]->collided = 1;
6209                     Person::players[i]->collided -= multiplier * 4;
6210                     Person::players[i]->whichdirectiondelay -= multiplier;
6211                     if (Person::players[i]->avoidcollided < -.3 || Person::players[i]->whichdirectiondelay <= 0) {
6212                         Person::players[i]->avoidcollided = -.3;
6213                         Person::players[i]->whichdirection = abs(Random() % 2);
6214                         Person::players[i]->whichdirectiondelay = .4;
6215                     }
6216                     if (Person::players[i]->avoidcollided > 1)
6217                         Person::players[i]->avoidcollided = 1;
6218                     Person::players[i]->avoidcollided -= multiplier / 4;
6219                     if (!Person::players[i]->skeleton.free) {
6220                         Person::players[i]->stunned -= multiplier;
6221                         Person::players[i]->surprised -= multiplier;
6222                     }
6223                     if (i != 0 && Person::players[i]->surprised <= 0 &&
6224                             Person::players[i]->aitype == attacktypecutoff &&
6225                             !Person::players[i]->dead &&
6226                             !Person::players[i]->skeleton.free &&
6227                             animation[Person::players[i]->animTarget].attack == neutral)
6228                         numresponded = 1;
6229
6230                     if (!Person::players[i]->throwkeydown)
6231                         Person::players[i]->throwtogglekeydown = 0;
6232
6233                     //pick up weapon
6234                     if (Person::players[i]->throwkeydown && !Person::players[i]->throwtogglekeydown) {
6235                         if (Person::players[i]->weaponactive == -1 &&
6236                                 Person::players[i]->num_weapons < 2 &&
6237                                 (Person::players[i]->isIdle() ||
6238                                  Person::players[i]->isCrouch() ||
6239                                  Person::players[i]->animTarget == sneakanim ||
6240                                  Person::players[i]->animTarget == rollanim ||
6241                                  Person::players[i]->animTarget == backhandspringanim ||
6242                                  Person::players[i]->isFlip() ||
6243                                  Person::players[i]->aitype != playercontrolled)) {
6244                             for (unsigned j = 0; j < weapons.size(); j++) {
6245                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
6246                                         Person::players[i]->aitype == playercontrolled) &&
6247                                         weapons[j].owner == -1 &&
6248                                         Person::players[i]->weaponactive == -1)
6249                                     if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2) {
6250                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 2) {
6251                                             if (Person::players[i]->isCrouch() ||
6252                                                     Person::players[i]->animTarget == sneakanim ||
6253                                                     Person::players[i]->isRun() ||
6254                                                     Person::players[i]->isIdle() ||
6255                                                     Person::players[i]->aitype != playercontrolled) {
6256                                                 Person::players[i]->throwtogglekeydown = 1;
6257                                                 Person::players[i]->setAnimation(crouchremoveknifeanim);
6258                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[j].position);
6259                                                 Person::players[i]->hasvictim = 0;
6260                                             }
6261                                             if (Person::players[i]->animTarget == rollanim || Person::players[i]->animTarget == backhandspringanim) {
6262                                                 Person::players[i]->throwtogglekeydown = 1;
6263                                                 Person::players[i]->hasvictim = 0;
6264
6265                                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
6266                                                         Person::players[i]->aitype == playercontrolled) &&
6267                                                         weapons[j].owner == -1 ||
6268                                                         Person::players[i]->victim &&
6269                                                         weapons[j].owner == int(Person::players[i]->victim->id))
6270                                                     if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2 && Person::players[i]->weaponactive == -1)
6271                                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 1 || Person::players[i]->victim) {
6272                                                             if (weapons[j].getType() != staff)
6273                                                                 emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
6274
6275                                                             Person::players[i]->takeWeapon(j);
6276                                                         }
6277                                             }
6278                                         } else if ((Person::players[i]->isIdle() ||
6279                                                     Person::players[i]->isFlip() ||
6280                                                     Person::players[i]->aitype != playercontrolled) &&
6281                                                    distsq(&Person::players[i]->coords, &weapons[j].position) < 5 &&
6282                                                    Person::players[i]->coords.y < weapons[j].position.y) {
6283                                             if (!Person::players[i]->isFlip()) {
6284                                                 Person::players[i]->throwtogglekeydown = 1;
6285                                                 Person::players[i]->setAnimation(removeknifeanim);
6286                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[j].position);
6287                                             }
6288                                             if (Person::players[i]->isFlip()) {
6289                                                 Person::players[i]->throwtogglekeydown = 1;
6290                                                 Person::players[i]->hasvictim = 0;
6291
6292                                                 for (unsigned k = 0; k < weapons.size(); k++) {
6293                                                     if (Person::players[i]->weaponactive == -1)
6294                                                         if ((weapons[k].velocity.x == 0 && weapons[k].velocity.y == 0 && weapons[k].velocity.z == 0 ||
6295                                                                 Person::players[i]->aitype == playercontrolled) &&
6296                                                                 weapons[k].owner == -1 ||
6297                                                                 Person::players[i]->victim &&
6298                                                                 weapons[k].owner == int(Person::players[i]->victim->id))
6299                                                             if (distsqflat(&Person::players[i]->coords, &weapons[k].position) < 3 &&
6300                                                                     Person::players[i]->weaponactive == -1) {
6301                                                                 if (weapons[k].getType() != staff)
6302                                                                     emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
6303
6304                                                                 Person::players[i]->takeWeapon(k);
6305                                                             }
6306                                                 }
6307                                             }
6308                                         }
6309                                     }
6310                             }
6311                             if (Person::players[i]->isCrouch() ||
6312                                     Person::players[i]->animTarget == sneakanim ||
6313                                     Person::players[i]->isRun() ||
6314                                     Person::players[i]->isIdle() || Person::players[i]->animTarget == rollanim ||
6315                                     Person::players[i]->animTarget == backhandspringanim) {
6316                                 if (Person::players.size() > 1)
6317                                     for (unsigned j = 0; j < Person::players.size(); j++) {
6318                                         if (Person::players[i]->weaponactive == -1)
6319                                             if (j != i)
6320                                                 if (Person::players[j]->num_weapons &&
6321                                                         Person::players[j]->skeleton.free &&
6322                                                         distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 2/*&&Person::players[j]->dead*/ &&
6323                                                         (((Person::players[j]->skeleton.forward.y < 0 &&
6324                                                            Person::players[j]->weaponstuckwhere == 0) ||
6325                                                           (Person::players[j]->skeleton.forward.y > 0 &&
6326                                                            Person::players[j]->weaponstuckwhere == 1)) ||
6327                                                          Person::players[j]->weaponstuck == -1 ||
6328                                                          Person::players[j]->num_weapons > 1)) {
6329                                                     if (Person::players[i]->animTarget != rollanim && Person::players[i]->animTarget != backhandspringanim) {
6330                                                         Person::players[i]->throwtogglekeydown = 1;
6331                                                         Person::players[i]->victim = Person::players[j];
6332                                                         Person::players[i]->hasvictim = 1;
6333                                                         Person::players[i]->setAnimation(crouchremoveknifeanim);
6334                                                         Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[j]->coords);
6335                                                     }
6336                                                     if (Person::players[i]->animTarget == rollanim || Person::players[i]->animTarget == backhandspringanim) {
6337                                                         Person::players[i]->throwtogglekeydown = 1;
6338                                                         Person::players[i]->victim = Person::players[j];
6339                                                         Person::players[i]->hasvictim = 1;
6340                                                         int k = Person::players[j]->weaponids[0];
6341                                                         if (Person::players[i]->hasvictim) {
6342                                                             bool fleshstuck;
6343                                                             fleshstuck = 0;
6344                                                             if (Person::players[i]->victim->weaponstuck != -1) {
6345                                                                 if (Person::players[i]->victim->weaponids[Person::players[i]->victim->weaponstuck] == k) {
6346                                                                     fleshstuck = 1;
6347                                                                 }
6348                                                             }
6349                                                             if (!fleshstuck) {
6350                                                                 if (weapons[k].getType() != staff)
6351                                                                     emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
6352                                                             }
6353                                                             if (fleshstuck)
6354                                                                 emit_sound_at(fleshstabremovesound, Person::players[i]->coords, 128.);
6355
6356                                                             if (weapons[k].owner != -1) {
6357                                                                 if (Person::players[i]->victim->num_weapons == 1)
6358                                                                     Person::players[i]->victim->num_weapons = 0;
6359                                                                 else
6360                                                                     Person::players[i]->victim->num_weapons = 1;
6361
6362                                                                 Person::players[i]->victim->skeleton.longdead = 0;
6363                                                                 Person::players[i]->victim->skeleton.free = 1;
6364                                                                 Person::players[i]->victim->skeleton.broken = 0;
6365
6366                                                                 for (int l = 0; l < Person::players[i]->victim->skeleton.num_joints; l++) {
6367                                                                     Person::players[i]->victim->skeleton.joints[l].velchange = 0;
6368                                                                     Person::players[i]->victim->skeleton.joints[l].locked = 0;
6369                                                                 }
6370
6371                                                                 XYZ relative;
6372                                                                 relative = 0;
6373                                                                 relative.y = 10;
6374                                                                 Normalise(&relative);
6375                                                                 XYZ footvel, footpoint;
6376                                                                 footvel = 0;
6377                                                                 footpoint = weapons[k].position;
6378                                                                 if (Person::players[i]->victim->weaponstuck != -1) {
6379                                                                     if (Person::players[i]->victim->weaponids[Person::players[i]->victim->weaponstuck] == k) {
6380                                                                         if (bloodtoggle)
6381                                                                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
6382                                                                         weapons[k].bloody = 2;
6383                                                                         weapons[k].blooddrip = 5;
6384                                                                         Person::players[i]->victim->weaponstuck = -1;
6385                                                                         Person::players[i]->victim->bloodloss += 2000;
6386                                                                         Person::players[i]->victim->DoDamage(2000);
6387                                                                     }
6388                                                                 }
6389                                                                 if (Person::players[i]->victim->num_weapons > 0) {
6390                                                                     if (Person::players[i]->victim->weaponstuck != 0 && Person::players[i]->victim->weaponstuck != -1)
6391                                                                         Person::players[i]->victim->weaponstuck = 0;
6392                                                                     if (Person::players[i]->victim->weaponids[0] == k)
6393                                                                         Person::players[i]->victim->weaponids[0] = Person::players[i]->victim->weaponids[Person::players[i]->victim->num_weapons];
6394                                                                 }
6395
6396                                                                 Person::players[i]->victim->weaponactive = -1;
6397
6398                                                                 Person::players[i]->victim->jointVel(abdomen) += relative * 6;
6399                                                                 Person::players[i]->victim->jointVel(neck) += relative * 6;
6400                                                                 Person::players[i]->victim->jointVel(rightshoulder) += relative * 6;
6401                                                                 Person::players[i]->victim->jointVel(leftshoulder) += relative * 6;
6402                                                             }
6403                                                             Person::players[i]->takeWeapon(k);
6404                                                         }
6405                                                     }
6406                                                 }
6407                                     }
6408                             }
6409                         }
6410                         if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
6411                             if (weapons[Person::players[i]->weaponids[0]].getType() == knife) {
6412                                 if (Person::players[i]->isIdle() ||
6413                                         Person::players[i]->isRun() ||
6414                                         Person::players[i]->isCrouch() ||
6415                                         Person::players[i]->animTarget == sneakanim ||
6416                                         Person::players[i]->isFlip())
6417                                     if (Person::players.size() > 1)
6418                                         for (unsigned j = 0; j < Person::players.size(); j++) {
6419                                             if (i != j)
6420                                                 if (tutoriallevel != 1 || tutorialstage == 49)
6421                                                     if (hostile)
6422                                                         if (normaldotproduct(Person::players[i]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0 &&
6423                                                                 distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 100 &&
6424                                                                 distsq(&Person::players[i]->coords, &Person::players[j]->coords) > 1.5 &&
6425                                                                 !Person::players[j]->skeleton.free &&
6426                                                                 -1 == checkcollide(DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0)*Person::players[j]->scale + Person::players[j]->coords, DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)*Person::players[i]->scale + Person::players[i]->coords)) {
6427                                                             if (!Person::players[i]->isFlip()) {
6428                                                                 Person::players[i]->throwtogglekeydown = 1;
6429                                                                 Person::players[i]->victim = Person::players[j];
6430                                                                 Person::players[i]->setAnimation(knifethrowanim);
6431                                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[j]->coords);
6432                                                                 Person::players[i]->targettilt2 = pitchTo(Person::players[i]->coords, Person::players[j]->coords);
6433                                                             }
6434                                                             if (Person::players[i]->isFlip()) {
6435                                                                 if (Person::players[i]->weaponactive != -1) {
6436                                                                     Person::players[i]->throwtogglekeydown = 1;
6437                                                                     Person::players[i]->victim = Person::players[j];
6438                                                                     XYZ aim;
6439                                                                     aim = Person::players[i]->victim->coords + DoRotation(Person::players[i]->victim->jointPos(abdomen), 0, Person::players[i]->victim->yaw, 0) * Person::players[i]->victim->scale + Person::players[i]->victim->velocity * findDistance(&Person::players[i]->victim->coords, &Person::players[i]->coords) / 50 - (Person::players[i]->coords + DoRotation(Person::players[i]->jointPos(righthand), 0, Person::players[i]->yaw, 0) * Person::players[i]->scale);
6440                                                                     Normalise(&aim);
6441
6442                                                                     aim = DoRotation(aim, (float)abs(Random() % 30) - 15, (float)abs(Random() % 30) - 15, 0);
6443
6444                                                                     weapons[Person::players[i]->weaponids[0]].thrown(aim * 50, false);
6445                                                                     Person::players[i]->num_weapons--;
6446                                                                     if (Person::players[i]->num_weapons) {
6447                                                                         Person::players[i]->weaponids[0] = Person::players[i]->weaponids[Person::players[i]->num_weapons];
6448                                                                     }
6449                                                                     Person::players[i]->weaponactive = -1;
6450                                                                 }
6451                                                             }
6452                                                         }
6453                                         }
6454                             }
6455                         }
6456                         if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
6457                             if (Person::players[i]->isCrouch() || Person::players[i]->animTarget == sneakanim) {
6458                                 Person::players[i]->throwtogglekeydown = 1;
6459                                 XYZ tempVelocity = Person::players[i]->velocity * .2;
6460                                 if (tempVelocity.x == 0)
6461                                     tempVelocity.x = .1;
6462                                 weapons[Person::players[i]->weaponids[0]].drop(tempVelocity, tempVelocity, false);
6463                                 Person::players[i]->num_weapons--;
6464                                 if (Person::players[i]->num_weapons) {
6465                                     Person::players[i]->weaponids[0] = Person::players[i]->weaponids[Person::players[i]->num_weapons];
6466                                     if (Person::players[i]->weaponstuck == Person::players[i]->num_weapons)
6467                                         Person::players[i]->weaponstuck = 0;
6468                                 }
6469
6470                                 Person::players[i]->weaponactive = -1;
6471                                 for (unsigned j = 0; j < Person::players.size(); j++) {
6472                                     Person::players[j]->wentforweapon = 0;
6473                                 }
6474                             }
6475                         }
6476
6477                     }
6478
6479                     //draw weapon
6480                     if (i == 0 || !Person::players[0]->dead || (Person::players[i]->weaponactive != -1)) {
6481                         if (Person::players[i]->drawkeydown && !Person::players[i]->drawtogglekeydown ||
6482                                 (Person::players[i]->num_weapons == 2) &&
6483                                 (Person::players[i]->weaponactive == -1) &&
6484                                 Person::players[i]->isIdle() ||
6485                                 Person::players[0]->dead &&
6486                                 (Person::players[i]->weaponactive != -1) &&
6487                                 i != 0) {
6488                             bool isgood = true;
6489                             if (Person::players[i]->weaponactive != -1)
6490                                 if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == staff)
6491                                     isgood = false;
6492                             if (isgood && Person::players[i]->creature != wolftype) {
6493                                 if (Person::players[i]->isIdle() && Person::players[i]->num_weapons && weapons[Person::players[i]->weaponids[0]].getType() == knife) {
6494                                     Person::players[i]->setAnimation(drawrightanim);
6495                                     Person::players[i]->drawtogglekeydown = 1;
6496                                 }
6497                                 if ((Person::players[i]->isIdle() ||
6498                                         (Person::players[i]->aitype != playercontrolled &&
6499                                          Person::players[0]->weaponactive != -1 &&
6500                                          Person::players[i]->isRun())) &&
6501                                         Person::players[i]->num_weapons &&
6502                                         weapons[Person::players[i]->weaponids[0]].getType() == sword) {
6503                                     Person::players[i]->setAnimation(drawleftanim);
6504                                     Person::players[i]->drawtogglekeydown = 1;
6505                                 }
6506                                 if (Person::players[i]->isCrouch() && Person::players[i]->num_weapons && weapons[Person::players[i]->weaponids[0]].getType() == knife) {
6507                                     Person::players[i]->setAnimation(crouchdrawrightanim);
6508                                     Person::players[i]->drawtogglekeydown = 1;
6509                                 }
6510                             }
6511                         }
6512                     }
6513
6514                     //clean weapon
6515                     if (Person::players[i]->weaponactive != -1) {
6516                         if (Person::players[i]->isCrouch() &&
6517                                 weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].bloody &&
6518                                 bloodtoggle &&
6519                                 Person::players[i]->onterrain &&
6520                                 Person::players[i]->num_weapons &&
6521                                 Person::players[i]->attackkeydown &&
6522                                 musictype != stream_fighttheme) {
6523                             if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == knife)
6524                                 Person::players[i]->setAnimation(crouchstabanim);
6525                             if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == sword)
6526                                 Person::players[i]->setAnimation(swordgroundstabanim);
6527                             Person::players[i]->hasvictim = 0;
6528                         }
6529                     }
6530
6531                     if (!Person::players[i]->drawkeydown)
6532                         Person::players[i]->drawtogglekeydown = 0;
6533
6534                     XYZ absflatfacing;
6535                     if (i == 0) {
6536                         absflatfacing = 0;
6537                         absflatfacing.z = -1;
6538
6539                         absflatfacing = DoRotation(absflatfacing, 0, -yaw, 0);
6540                     } else
6541                         absflatfacing = flatfacing;
6542
6543                     if (indialogue != -1) {
6544                         Person::players[i]->forwardkeydown = 0;
6545                         Person::players[i]->leftkeydown = 0;
6546                         Person::players[i]->backkeydown = 0;
6547                         Person::players[i]->rightkeydown = 0;
6548                         Person::players[i]->jumpkeydown = 0;
6549                         Person::players[i]->crouchkeydown = 0;
6550                         Person::players[i]->drawkeydown = 0;
6551                         Person::players[i]->throwkeydown = 0;
6552                     }
6553                     movekey = 0;
6554                     //Do controls
6555                     if (!animation[Person::players[i]->animTarget].attack &&
6556                             Person::players[i]->animTarget != staggerbackhighanim &&
6557                             Person::players[i]->animTarget != staggerbackhardanim &&
6558                             Person::players[i]->animTarget != backhandspringanim &&
6559                             Person::players[i]->animTarget != dodgebackanim) {
6560                         if (!Person::players[i]->forwardkeydown)
6561                             Person::players[i]->forwardstogglekeydown = 0;
6562                         if (Person::players[i]->crouchkeydown) {
6563                             //Crouch
6564                             target = -2;
6565                             if (i == 0) {
6566                                 Person::players[i]->superruntoggle = 1;
6567                                 if (Person::players.size() > 1)
6568                                     for (unsigned j = 0; j < Person::players.size(); j++)
6569                                         if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->aitype == passivetype)
6570                                             if (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 16)
6571                                                 Person::players[i]->superruntoggle = 0;
6572                             }
6573
6574                             if (Person::players.size() > 1)
6575                                 for (unsigned j = 0; j < Person::players.size(); j++) {
6576                                     if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->victim && Person::players[i]->lowreversaldelay <= 0) {
6577                                         if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
6578                                                 Person::players[j]->victim == Person::players[i] &&
6579                                                 (Person::players[j]->animTarget == sweepanim ||
6580                                                  Person::players[j]->animTarget == upunchanim ||
6581                                                  Person::players[j]->animTarget == wolfslapanim ||
6582                                                  ((Person::players[j]->animTarget == swordslashanim ||
6583                                                    Person::players[j]->animTarget == knifeslashstartanim ||
6584                                                    Person::players[j]->animTarget == staffhitanim ||
6585                                                    Person::players[j]->animTarget == staffspinhitanim) &&
6586                                                   distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 2))) {
6587                                             if (target >= 0)
6588                                                 target = -1;
6589                                             else
6590                                                 target = j;
6591                                         }
6592                                     }
6593                                 }
6594                             if (target >= 0)
6595                                 Person::players[target]->Reverse();
6596                             Person::players[i]->lowreversaldelay = .5;
6597
6598                             if (Person::players[i]->isIdle()) {
6599                                 Person::players[i]->setAnimation(Person::players[i]->getCrouch());
6600                                 Person::players[i]->transspeed = 10;
6601                             }
6602                             if (Person::players[i]->isRun() ||
6603                                     (Person::players[i]->isStop() &&
6604                                      (Person::players[i]->leftkeydown ||
6605                                       Person::players[i]->rightkeydown ||
6606                                       Person::players[i]->forwardkeydown ||
6607                                       Person::players[i]->backkeydown))) {
6608                                 Person::players[i]->setAnimation(rollanim);
6609                                 Person::players[i]->transspeed = 20;
6610                             }
6611                         }
6612                         if (!Person::players[i]->crouchkeydown) {
6613                             //Uncrouch
6614                             if (!Person::players[i]->isRun() && Person::players[i]->animTarget != sneakanim && i == 0)
6615                                 Person::players[i]->superruntoggle = 0;
6616                             target = -2;
6617                             if (Person::players[i]->isCrouch()) {
6618                                 if (Person::players.size() > 1)
6619                                     for (unsigned j = 0; j < Person::players.size(); j++) {
6620                                         if (j != i &&
6621                                                 !Person::players[j]->skeleton.free &&
6622                                                 Person::players[j]->victim &&
6623                                                 Person::players[i]->highreversaldelay <= 0) {
6624                                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
6625                                                     Person::players[j]->victim == Person::players[i] &&
6626                                                     (Person::players[j]->animTarget == spinkickanim) &&
6627                                                     Person::players[i]->isCrouch()) {
6628                                                 if (target >= 0)
6629                                                     target = -1;
6630                                                 else
6631                                                     target = j;
6632                                             }
6633                                         }
6634                                     }
6635                                 if (target >= 0)
6636                                     Person::players[target]->Reverse();
6637                                 Person::players[i]->highreversaldelay = .5;
6638
6639                                 if (Person::players[i]->isCrouch()) {
6640                                     if (!Person::players[i]->wasCrouch()) {
6641                                         Person::players[i]->animCurrent = Person::players[i]->getCrouch();
6642                                         Person::players[i]->frameCurrent = 0;
6643                                     }
6644                                     Person::players[i]->setAnimation(Person::players[i]->getIdle());
6645                                     Person::players[i]->transspeed = 10;
6646                                 }
6647                             }
6648                             if (Person::players[i]->animTarget == sneakanim) {
6649                                 Person::players[i]->setAnimation(Person::players[i]->getIdle());
6650                                 Person::players[i]->transspeed = 10;
6651                             }
6652                         }
6653                         if (Person::players[i]->forwardkeydown) {
6654                             if (Person::players[i]->isIdle() ||
6655                                     (Person::players[i]->isStop() &&
6656                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
6657                                     (Person::players[i]->isLanding() &&
6658                                      Person::players[i]->frameTarget > 0 &&
6659                                      !Person::players[i]->jumpkeydown) ||
6660                                     (Person::players[i]->isLandhard() &&
6661                                      Person::players[i]->frameTarget > 0 &&
6662                                      !Person::players[i]->jumpkeydown &&
6663                                      Person::players[i]->crouchkeydown)) {
6664                                 if (Person::players[i]->aitype == passivetype)
6665                                     Person::players[i]->setAnimation(walkanim);
6666                                 else
6667                                     Person::players[i]->setAnimation(Person::players[i]->getRun());
6668                             }
6669                             if (Person::players[i]->isCrouch()) {
6670                                 Person::players[i]->animTarget = sneakanim;
6671                                 if (Person::players[i]->wasCrouch())
6672                                     Person::players[i]->target = 0;
6673                                 Person::players[i]->frameTarget = 0;
6674                             }
6675                             if (Person::players[i]->animTarget == hanganim/*&&(!Person::players[i]->forwardstogglekeydown||Person::players[i]->aitype!=playercontrolled)*/) {
6676                                 Person::players[i]->setAnimation(climbanim);
6677                                 Person::players[i]->frameTarget = 1;
6678                                 Person::players[i]->jumpclimb = 1;
6679                             }
6680                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
6681                                 Person::players[i]->velocity += absflatfacing * 5 * multiplier;
6682                             }
6683                             Person::players[i]->forwardstogglekeydown = 1;
6684                             movekey = 1;
6685                         }
6686                         if (Person::players[i]->rightkeydown) {
6687                             if (Person::players[i]->isIdle() ||
6688                                     (Person::players[i]->isStop() &&
6689                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
6690                                     (Person::players[i]->isLanding() &&
6691                                      Person::players[i]->frameTarget > 0 &&
6692                                      !Person::players[i]->jumpkeydown) ||
6693                                     (Person::players[i]->isLandhard() &&
6694                                      Person::players[i]->frameTarget > 0 &&
6695                                      !Person::players[i]->jumpkeydown &&
6696                                      Person::players[i]->crouchkeydown)) {
6697                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
6698                             }
6699                             if (Person::players[i]->isCrouch()) {
6700                                 Person::players[i]->animTarget = sneakanim;
6701                                 if (Person::players[i]->wasCrouch())
6702                                     Person::players[i]->target = 0;
6703                                 Person::players[i]->frameTarget = 0;
6704                             }
6705                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
6706                                 Person::players[i]->velocity += DoRotation(absflatfacing * 5 * multiplier, 0, -90, 0);
6707                             }
6708                             Person::players[i]->targetyaw -= 90;
6709                             if (Person::players[i]->forwardkeydown)
6710                                 Person::players[i]->targetyaw += 45;
6711                             if (Person::players[i]->backkeydown)
6712                                 Person::players[i]->targetyaw -= 45;
6713                             movekey = 1;
6714                         }
6715                         if ( Person::players[i]->leftkeydown) {
6716                             if (Person::players[i]->isIdle() ||
6717                                     (Person::players[i]->isStop() &&
6718                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
6719                                     (Person::players[i]->isLanding() &&
6720                                      Person::players[i]->frameTarget > 0 &&
6721                                      !Person::players[i]->jumpkeydown) ||
6722                                     (Person::players[i]->isLandhard() &&
6723                                      Person::players[i]->frameTarget > 0 &&
6724                                      !Person::players[i]->jumpkeydown &&
6725                                      Person::players[i]->crouchkeydown)) {
6726                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
6727                             }
6728                             if (Person::players[i]->isCrouch()) {
6729                                 Person::players[i]->animTarget = sneakanim;
6730                                 if (Person::players[i]->wasCrouch())
6731                                     Person::players[i]->target = 0;
6732                                 Person::players[i]->frameTarget = 0;
6733                             }
6734                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
6735                                 Person::players[i]->velocity -= DoRotation(absflatfacing * 5 * multiplier, 0, -90, 0);
6736                             }
6737                             Person::players[i]->targetyaw += 90;
6738                             if (Person::players[i]->forwardkeydown)
6739                                 Person::players[i]->targetyaw -= 45;
6740                             if (Person::players[i]->backkeydown)
6741                                 Person::players[i]->targetyaw += 45;
6742                             movekey = 1;
6743                         }
6744                         if (Person::players[i]->backkeydown) {
6745                             if (Person::players[i]->isIdle() ||
6746                                     (Person::players[i]->isStop() &&
6747                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
6748                                     (Person::players[i]->isLanding() &&
6749                                      Person::players[i]->frameTarget > 0 &&
6750                                      !Person::players[i]->jumpkeydown) ||
6751                                     (Person::players[i]->isLandhard() &&
6752                                      Person::players[i]->frameTarget > 0 &&
6753                                      !Person::players[i]->jumpkeydown &&
6754                                      Person::players[i]->crouchkeydown)) {
6755                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
6756                             }
6757                             if (Person::players[i]->isCrouch()) {
6758                                 Person::players[i]->animTarget = sneakanim;
6759                                 if (Person::players[i]->wasCrouch())
6760                                     Person::players[i]->target = 0;
6761                                 Person::players[i]->frameTarget = 0;
6762                             }
6763                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
6764                                 Person::players[i]->velocity -= absflatfacing * 5 * multiplier;
6765                             }
6766                             if (Person::players[i]->animTarget == hanganim) {
6767                                 Person::players[i]->animCurrent = jumpdownanim;
6768                                 Person::players[i]->animTarget = jumpdownanim;
6769                                 Person::players[i]->target = 0;
6770                                 Person::players[i]->frameCurrent = 0;
6771                                 Person::players[i]->frameTarget = 1;
6772                                 Person::players[i]->velocity = 0;
6773                                 Person::players[i]->velocity.y += gravity;
6774                                 Person::players[i]->coords.y -= 1.4;
6775                                 Person::players[i]->grabdelay = 1;
6776                             }
6777                             if ( !Person::players[i]->leftkeydown && !Person::players[i]->rightkeydown)
6778                                 Person::players[i]->targetyaw += 180;
6779                             movekey = 1;
6780                         }
6781                         if ((Person::players[i]->jumpkeydown && !Person::players[i]->jumpclimb) || Person::players[i]->jumpstart) {
6782                             if ((((Person::players[i]->isLanding() && Person::players[i]->frameTarget >= 3) ||
6783                                     Person::players[i]->isRun() ||
6784                                     Person::players[i]->animTarget == walkanim ||
6785                                     Person::players[i]->isCrouch() ||
6786                                     Person::players[i]->animTarget == sneakanim) &&
6787                                     Person::players[i]->jumppower > 1) &&
6788                                     ((Person::players[i]->animTarget != rabbitrunninganim &&
6789                                       Person::players[i]->animTarget != wolfrunninganim) || i != 0)) {
6790                                 Person::players[i]->jumpstart = 0;
6791                                 Person::players[i]->setAnimation(jumpupanim);
6792                                 Person::players[i]->yaw = Person::players[i]->targetyaw;
6793                                 Person::players[i]->transspeed = 20;
6794                                 Person::players[i]->FootLand(0, 1);
6795                                 Person::players[i]->FootLand(1, 1);
6796
6797                                 facing = 0;
6798                                 facing.z = -1;
6799                                 flatfacing = DoRotation(facing, 0, Person::players[i]->targetyaw + 180, 0);
6800
6801                                 if (movekey)
6802                                     Person::players[i]->velocity = flatfacing * Person::players[i]->speed * 45 * Person::players[i]->scale;
6803                                 if (!movekey)
6804                                     Person::players[i]->velocity = 0;
6805
6806                                 //Dodge sweep?
6807                                 target = -2;
6808                                 if (Person::players.size() > 1)
6809                                     for (unsigned j = 0; j < Person::players.size(); j++) {
6810                                         if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->victim) {
6811                                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
6812                                                     (Person::players[j]->victim == Person::players[i]) &&
6813                                                     (Person::players[j]->animTarget == sweepanim)) {
6814                                                 if (target >= 0)
6815                                                     target = -1;
6816                                                 else
6817                                                     target = j;
6818                                             }
6819                                         }
6820                                     }
6821                                 if (target >= 0)
6822                                     Person::players[i]->velocity.y = 1;
6823                                 else
6824                                     if (Person::players[i]->crouchkeydown || Person::players[i]->aitype != playercontrolled) {
6825                                     Person::players[i]->velocity.y = 7;
6826                                     Person::players[i]->crouchtogglekeydown = 1;
6827                                 } else Person::players[i]->velocity.y = 5;
6828
6829                                 if (mousejump && i == 0 && debugmode) {
6830                                     if (!Person::players[i]->isLanding())
6831                                         Person::players[i]->tempdeltav = deltav;
6832                                     if (Person::players[i]->tempdeltav < 0)
6833                                         Person::players[i]->velocity.y -= (float)(Person::players[i]->tempdeltav) / multiplier / 1000;
6834                                 }
6835
6836                                 Person::players[i]->coords.y += .2;
6837                                 Person::players[i]->jumppower -= 1;
6838
6839                                 if (!i)
6840                                     emit_sound_at(whooshsound, Person::players[i]->coords, 128.);
6841
6842                                 emit_sound_at(jumpsound, Person::players[i]->coords, 128.);
6843                             }
6844                             if ((Person::players[i]->isIdle()) && Person::players[i]->jumppower > 1) {
6845                                 Person::players[i]->setAnimation(Person::players[i]->getLanding());
6846                                 Person::players[i]->frameTarget = 2;
6847                                 Person::players[i]->landhard = 0;
6848                                 Person::players[i]->jumpstart = 1;
6849                                 Person::players[i]->tempdeltav = deltav;
6850                             }
6851                             if (Person::players[i]->animTarget == jumpupanim &&
6852                                     (((!floatjump &&
6853                                        !editorenabled) ||
6854                                       !debugmode) ||
6855                                      Person::players[i]->aitype != playercontrolled)) {
6856                                 if (Person::players[i]->jumppower > multiplier * 6) {
6857                                     Person::players[i]->velocity.y += multiplier * 6;
6858                                     Person::players[i]->jumppower -= multiplier * 6;
6859                                 }
6860                                 if (Person::players[i]->jumppower <= multiplier * 6) {
6861                                     Person::players[i]->velocity.y += Person::players[i]->jumppower;
6862                                     Person::players[i]->jumppower = 0;
6863                                 }
6864                             }
6865                             if (((floatjump || editorenabled) && debugmode) && i == 0)
6866                                 Person::players[i]->velocity.y += multiplier * 30;
6867                         }
6868
6869                         if (!movekey) {
6870                             if (Person::players[i]->isRun() || Person::players[i]->animTarget == walkanim)
6871                                 Person::players[i]->setAnimation(Person::players[i]->getStop());
6872                             if (Person::players[i]->animTarget == sneakanim) {
6873                                 Person::players[i]->animTarget = Person::players[i]->getCrouch();
6874                                 if (Person::players[i]->animCurrent == sneakanim)
6875                                     Person::players[i]->target = 0;
6876                                 Person::players[i]->frameTarget = 0;
6877                             }
6878                         }
6879                         if (Person::players[i]->animTarget == walkanim &&
6880                                 (Person::players[i]->aitype == attacktypecutoff ||
6881                                  Person::players[i]->aitype == searchtype ||
6882                                  (Person::players[i]->aitype == passivetype &&
6883                                   Person::players[i]->numwaypoints <= 1)))
6884                             Person::players[i]->setAnimation(Person::players[i]->getStop());
6885                         if (Person::players[i]->isRun() && (Person::players[i]->aitype == passivetype))
6886                             Person::players[i]->setAnimation(Person::players[i]->getStop());
6887                     }
6888                 }
6889                 if (Person::players[i]->animTarget == rollanim)
6890                     Person::players[i]->targetyaw = oldtargetyaw;
6891             }
6892
6893             //Rotation
6894             for (unsigned k = 0; k < Person::players.size(); k++) {
6895                 if (fabs(Person::players[k]->yaw - Person::players[k]->targetyaw) > 180) {
6896                     if (Person::players[k]->yaw > Person::players[k]->targetyaw)
6897                         Person::players[k]->yaw -= 360;
6898                     else
6899                         Person::players[k]->yaw += 360;
6900                 }
6901
6902                 //stop to turn in right direction
6903                 if (fabs(Person::players[k]->yaw - Person::players[k]->targetyaw) > 90 && (Person::players[k]->isRun() || Person::players[k]->animTarget == walkanim))
6904                     Person::players[k]->setAnimation(Person::players[k]->getStop());
6905
6906                 if (Person::players[k]->animTarget == backhandspringanim || Person::players[k]->animTarget == dodgebackanim)
6907                     Person::players[k]->targettilt = 0;
6908
6909                 if (Person::players[k]->animTarget != jumpupanim &&
6910                         Person::players[k]->animTarget != backhandspringanim &&
6911                         Person::players[k]->animTarget != jumpdownanim &&
6912                         !Person::players[k]->isFlip()) {
6913                     Person::players[k]->targettilt = 0;
6914                     if (Person::players[k]->jumppower < 0 && !Person::players[k]->jumpkeydown)
6915                         Person::players[k]->jumppower = 0;
6916                     Person::players[k]->jumppower += multiplier * 7;
6917                     if (Person::players[k]->isCrouch())
6918                         Person::players[k]->jumppower += multiplier * 7;
6919                     if (Person::players[k]->jumppower > 5)
6920                         Person::players[k]->jumppower = 5;
6921                 }
6922
6923                 if (Person::players[k]->isRun())
6924                     Person::players[k]->targettilt = (Person::players[k]->yaw - Person::players[k]->targetyaw) / 4;
6925
6926                 Person::players[k]->tilt = stepTowardf(Person::players[k]->tilt, Person::players[k]->targettilt, multiplier * 150);
6927                 Person::players[k]->grabdelay -= multiplier;
6928             }
6929
6930             //do animations
6931             for (unsigned k = 0; k < Person::players.size(); k++) {
6932                 Person::players[k]->DoAnimations();
6933                 Person::players[k]->whichpatchx = Person::players[k]->coords.x / (terrain.size / subdivision * terrain.scale);
6934                 Person::players[k]->whichpatchz = Person::players[k]->coords.z / (terrain.size / subdivision * terrain.scale);
6935             }
6936
6937             //do stuff
6938             objects.DoStuff();
6939
6940             for (int j = numenvsounds - 1; j >= 0; j--) {
6941                 envsoundlife[j] -= multiplier;
6942                 if (envsoundlife[j] < 0) {
6943                     numenvsounds--;
6944                     envsoundlife[j] = envsoundlife[numenvsounds];
6945                     envsound[j] = envsound[numenvsounds];
6946                 }
6947             }
6948             if (slomo)
6949                 OPENAL_SetFrequency(OPENAL_ALL, slomofreq);
6950             else
6951                 OPENAL_SetFrequency(OPENAL_ALL, 22050);
6952
6953             if (tutoriallevel == 1) {
6954                 XYZ temp;
6955                 XYZ temp2;
6956                 XYZ temp3;
6957                 XYZ oldtemp;
6958                 XYZ oldtemp2;
6959                 temp.x = 1011;
6960                 temp.y = 84;
6961                 temp.z = 491;
6962                 temp2.x = 1025;
6963                 temp2.y = 75;
6964                 temp2.z = 447;
6965                 temp3.x = 1038;
6966                 temp3.y = 76;
6967                 temp3.z = 453;
6968                 oldtemp = temp;
6969                 oldtemp2 = temp2;
6970                 if (tutorialstage >= 51)
6971                     if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) {
6972                         OPENAL_StopSound(OPENAL_ALL);  // hack...OpenAL renderer isn't stopping music after tutorial goes to level menu...
6973                         OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6974
6975                         emit_stream_np(stream_menutheme);
6976
6977                         gameon = 0;
6978                         mainmenu = 5;
6979
6980                         fireSound();
6981
6982                         flash();
6983                     }
6984                 if (tutorialstage < 51)
6985                     if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) {
6986                         emit_sound_at(fireendsound, Person::players[0]->coords);
6987
6988                         Person::players[0]->coords = (oldtemp + oldtemp2) / 2;
6989
6990                         flash();
6991                     }
6992                 if (tutorialstage >= 14 && tutorialstage < 50)
6993                     if (distsq(&temp, &Person::players[1]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[1]->coords) < 4) {
6994                         emit_sound_at(fireendsound, Person::players[1]->coords);
6995
6996                         for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
6997                             if (Random() % 2 == 0) {
6998                                 if (!Person::players[1]->skeleton.free)
6999                                     temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
7000                                 if (Person::players[1]->skeleton.free)
7001                                     temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
7002                                 if (!Person::players[1]->skeleton.free)
7003                                     temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords;
7004                                 if (Person::players[1]->skeleton.free)
7005                                     temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
7006                                 Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
7007                             }
7008                         }
7009
7010                         Person::players[1]->coords = (oldtemp + oldtemp2) / 2;
7011                         for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
7012                             Person::players[1]->skeleton.joints[i].velocity = 0;
7013                             if (Random() % 2 == 0) {
7014                                 if (!Person::players[1]->skeleton.free)
7015                                     temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
7016                                 if (Person::players[1]->skeleton.free)
7017                                     temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
7018                                 if (!Person::players[1]->skeleton.free)
7019                                     temp = DoRotation(DoRotation(DoRotation(Person::players[1]->skeleton.joints[i].position, 0, 0, Person::players[1]->tilt), Person::players[1]->tilt2, 0, 0), 0, Person::players[1]->yaw, 0) * Person::players[1]->scale + Person::players[1]->coords;
7020                                 if (Person::players[1]->skeleton.free)
7021                                     temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
7022                                 Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
7023                             }
7024                         }
7025                     }
7026             }
7027
7028
7029             //3d sound
7030             static float gLoc[3];
7031             gLoc[0] = viewer.x;
7032             gLoc[1] = viewer.y;
7033             gLoc[2] = viewer.z;
7034             static float vel[3];
7035             vel[0] = (viewer.x - oldviewer.x) / multiplier;
7036             vel[1] = (viewer.y - oldviewer.y) / multiplier;
7037             vel[2] = (viewer.z - oldviewer.z) / multiplier;
7038
7039             //Set orientation with forward and up vectors
7040             static XYZ upvector;
7041             upvector = 0;
7042             upvector.z = -1;
7043
7044             upvector = DoRotation(upvector, -pitch + 90, 0, 0);
7045             upvector = DoRotation(upvector, 0, 0 - yaw, 0);
7046
7047             facing = 0;
7048             facing.z = -1;
7049
7050             facing = DoRotation(facing, -pitch, 0, 0);
7051             facing = DoRotation(facing, 0, 0 - yaw, 0);
7052
7053
7054             static float ori[6];
7055             ori[0] = -facing.x;
7056             ori[1] = facing.y;
7057             ori[2] = -facing.z;
7058             ori[3] = -upvector.x;
7059             ori[4] = upvector.y;
7060             ori[5] = -upvector.z;
7061
7062             OPENAL_3D_Listener_SetAttributes(&gLoc[0], &vel[0], ori[0], ori[1], ori[2], ori[3], ori[4], ori[5]);
7063             OPENAL_Update();
7064
7065             oldviewer = viewer;
7066         }
7067     }
7068
7069     if (Input::isKeyPressed(SDL_SCANCODE_F1))
7070         Screenshot();
7071 }
7072
7073 void Game::TickOnce()
7074 {
7075     if (mainmenu)
7076         yaw += multiplier * 5;
7077     else if (directing || indialogue == -1) {
7078         yaw += deltah * .7;
7079         if (!invertmouse)
7080             pitch += deltav * .7;
7081         if (invertmouse)
7082             pitch -= deltav * .7;
7083         if (pitch > 90)
7084             pitch = 90;
7085         if (pitch < -70)
7086             pitch = -70;
7087     }
7088 }
7089
7090 void Game::TickOnceAfter()
7091 {
7092     static XYZ colviewer;
7093     static XYZ coltarget;
7094     static XYZ target;
7095     static XYZ col;
7096     static XYZ facing;
7097     static float changedelay;
7098     static bool alldead;
7099     static float unseendelay;
7100     static float cameraspeed;
7101
7102     if (!mainmenu) {
7103         static int oldmusictype = musictype;
7104
7105         if (environment == snowyenvironment)
7106             leveltheme = stream_snowtheme;
7107         if (environment == grassyenvironment)
7108             leveltheme = stream_grasstheme;
7109         if (environment == desertenvironment)
7110             leveltheme = stream_deserttheme;
7111
7112         realthreat = 0;
7113
7114         musictype = leveltheme;
7115         for (unsigned i = 0; i < Person::players.size(); i++) {
7116             if ((Person::players[i]->aitype == attacktypecutoff ||
7117                     Person::players[i]->aitype == getweapontype ||
7118                     Person::players[i]->aitype == gethelptype ||
7119                     Person::players[i]->aitype == searchtype) &&
7120                     !Person::players[i]->dead/*&&Person::players[i]->surprised<=0*/ &&
7121                     (Person::players[i]->animTarget != sneakattackedanim &&
7122                      Person::players[i]->animTarget != knifesneakattackedanim &&
7123                      Person::players[i]->animTarget != swordsneakattackedanim)) {
7124                 musictype = stream_fighttheme;
7125                 realthreat = 1;
7126             }
7127         }
7128         if (Person::players[0]->dead)
7129             musictype = stream_menutheme;
7130
7131
7132         if (musictype == stream_fighttheme)
7133             unseendelay = 1;
7134
7135         if (oldmusictype == stream_fighttheme && musictype != stream_fighttheme) {
7136             unseendelay -= multiplier;
7137             if (unseendelay > 0)
7138                 musictype = stream_fighttheme;
7139         }
7140
7141
7142         if (loading == 2) {
7143             musictype = stream_menutheme;
7144             musicvolume[2] = 512;
7145             musicvolume[0] = 0;
7146             musicvolume[1] = 0;
7147             musicvolume[3] = 0;
7148         }
7149
7150         if (musictoggle)
7151             if (musictype != oldmusictype && musictype == stream_fighttheme)
7152                 emit_sound_np(alarmsound);
7153         musicselected = musictype;
7154
7155         if (musicselected == leveltheme)
7156             musicvolume[0] += multiplier * 450;
7157         else
7158             musicvolume[0] -= multiplier * 450;
7159         if (musicselected == stream_fighttheme)
7160             musicvolume[1] += multiplier * 450;
7161         else
7162             musicvolume[1] -= multiplier * 450;
7163         if (musicselected == stream_menutheme)
7164             musicvolume[2] += multiplier * 450;
7165         else
7166             musicvolume[2] -= multiplier * 450;
7167
7168         for (int i = 0; i < 3; i++) {
7169             if (musicvolume[i] < 0)
7170                 musicvolume[i] = 0;
7171             if (musicvolume[i] > 512)
7172                 musicvolume[i] = 512;
7173         }
7174
7175         if (musicvolume[2] > 128 && !loading && !mainmenu)
7176             musicvolume[2] = 128;
7177
7178         if (musictoggle) {
7179             if (musicvolume[0] > 0 && oldmusicvolume[0] <= 0)
7180                 emit_stream_np(leveltheme, musicvolume[0]);
7181             if (musicvolume[1] > 0 && oldmusicvolume[1] <= 0)
7182                 emit_stream_np(stream_fighttheme, musicvolume[1]);
7183             if (musicvolume[2] > 0 && oldmusicvolume[2] <= 0)
7184                 emit_stream_np(stream_menutheme, musicvolume[2]);
7185             if (musicvolume[0] <= 0 && oldmusicvolume[0] > 0)
7186                 pause_sound(leveltheme);
7187             if (musicvolume[1] <= 0 && oldmusicvolume[1] > 0)
7188                 pause_sound(stream_fighttheme);
7189             if (musicvolume[2] <= 0 && oldmusicvolume[2] > 0)
7190                 pause_sound(stream_menutheme);
7191
7192             if (musicvolume[0] != oldmusicvolume[0])
7193                 OPENAL_SetVolume(channels[leveltheme], musicvolume[0]);
7194             if (musicvolume[1] != oldmusicvolume[1])
7195                 OPENAL_SetVolume(channels[stream_fighttheme], musicvolume[1]);
7196             if (musicvolume[2] != oldmusicvolume[2])
7197                 OPENAL_SetVolume(channels[stream_menutheme], musicvolume[2]);
7198
7199             for (int i = 0; i < 3; i++)
7200                 oldmusicvolume[i] = musicvolume[i];
7201         } else {
7202             pause_sound(leveltheme);
7203             pause_sound(stream_fighttheme);
7204             pause_sound(stream_menutheme);
7205
7206             for (int i = 0; i < 4; i++) {
7207                 oldmusicvolume[i] = 0;
7208                 musicvolume[i] = 0;
7209             }
7210         }
7211
7212         killhotspot = 2;
7213         for (int i = 0; i < numhotspots; i++) {
7214             if (hotspottype[i] > 10 && hotspottype[i] < 20) {
7215                 if (Person::players[hotspottype[i] - 10]->dead == 0)
7216                     killhotspot = 0;
7217                 else if (killhotspot == 2)
7218                     killhotspot = 1;
7219             }
7220         }
7221         if (killhotspot == 2)
7222             killhotspot = 0;
7223
7224
7225         winhotspot = false;
7226         for (int i = 0; i < numhotspots; i++)
7227             if (hotspottype[i] == -1)
7228                 if (distsq(&Person::players[0]->coords, &hotspot[i]) < hotspotsize[i])
7229                     winhotspot = true;
7230
7231         int numalarmed = 0;
7232         for (unsigned i = 1; i < Person::players.size(); i++)
7233             if (!Person::players[i]->dead && Person::players[i]->aitype == attacktypecutoff && Person::players[i]->surprised <= 0)
7234                 numalarmed++;
7235         if (numalarmed > maxalarmed)
7236             maxalarmed = numalarmed;
7237
7238         if (changedelay <= 0 && !loading && !editorenabled && gameon && !tutoriallevel && changedelay != -999 && !won) {
7239             if (Person::players[0]->dead && changedelay <= 0) {
7240                 changedelay = 1;
7241                 targetlevel = whichlevel;
7242             }
7243             alldead = true;
7244             for (unsigned i = 1; i < Person::players.size(); i++) {
7245                 if (!Person::players[i]->dead && Person::players[i]->howactive < typedead1) {
7246                     alldead = false;
7247                     break;
7248                 }
7249             }
7250
7251
7252             if (alldead && !Person::players[0]->dead && maptype == mapkilleveryone) {
7253                 changedelay = 1;
7254                 targetlevel = whichlevel + 1;
7255                 if (targetlevel > numchallengelevels - 1)
7256                     targetlevel = 0;
7257             }
7258             if (winhotspot || windialogue) {
7259                 changedelay = 0.1;
7260                 targetlevel = whichlevel + 1;
7261                 if (targetlevel > numchallengelevels - 1)
7262                     targetlevel = 0;
7263             }
7264
7265
7266             if (killhotspot) {
7267                 changedelay = 1;
7268                 targetlevel = whichlevel + 1;
7269                 if (targetlevel > numchallengelevels - 1)
7270                     targetlevel = 0;
7271             }
7272
7273             if (changedelay > 0 && !Person::players[0]->dead && !won) {
7274                 //high scores, awards, win
7275                 if (campaign) {
7276                     accountactive->winCampaignLevel(whichchoice, bonustotal, leveltime);
7277                     scoreadded = 1;
7278                 } else {
7279                     accountactive->winLevel(whichlevel, bonustotal - startbonustotal, leveltime);
7280                 }
7281                 won = 1;
7282             }
7283         }
7284
7285         if (!winfreeze) {
7286
7287             if (leveltime < 1) {
7288                 loading = 0;
7289                 changedelay = .1;
7290                 alldead = false;
7291                 winhotspot = false;
7292                 killhotspot = 0;
7293             }
7294
7295             if (!editorenabled && gameon && !mainmenu) {
7296                 if (changedelay != -999)
7297                     changedelay -= multiplier / 7;
7298                 if (Person::players[0]->dead)
7299                     targetlevel = whichlevel;
7300                 if (loading == 2 && !campaign) {
7301                     flash();
7302
7303                     fireSound(firestartsound);
7304
7305                     if (!Person::players[0]->dead && targetlevel != whichlevel)
7306                         startbonustotal = bonustotal;
7307                     if (Person::players[0]->dead)
7308                         Loadlevel(whichlevel);
7309                     else
7310                         Loadlevel(targetlevel);
7311
7312                     fireSound();
7313
7314                     loading = 3;
7315                 }
7316                 if (loading == 2 && targetlevel == whichlevel) {
7317                     flash();
7318                     loadtime = 0;
7319
7320                     fireSound(firestartsound);
7321
7322                     Loadlevel(campaignlevels[accountactive->getCampaignChoicesMade()].mapname.c_str());
7323
7324                     fireSound();
7325
7326                     loading = 3;
7327                 }
7328                 if (changedelay <= -999 &&
7329                         whichlevel != -2 &&
7330                         !loading &&
7331                         (Person::players[0]->dead ||
7332                          (alldead && maptype == mapkilleveryone) ||
7333                          (winhotspot) ||
7334                          (killhotspot)))
7335                     loading = 1;
7336                 if ((Person::players[0]->dead ||
7337                         (alldead && maptype == mapkilleveryone) ||
7338                         (winhotspot) ||
7339                         (windialogue) ||
7340                         (killhotspot)) &&
7341                         changedelay <= 0) {
7342                     if (whichlevel != -2 && !loading && !Person::players[0]->dead) {
7343                         winfreeze = true;
7344                         changedelay = -999;
7345                     }
7346                     if (Person::players[0]->dead)
7347                         loading = 1;
7348                 }
7349             }
7350
7351             if (campaign) {
7352                 // campaignchoosenext determines what to do when the level is complete:
7353                 // 0 = load next level
7354                 // 1 = go back to level select screen
7355                 // 2 = stealthload next level
7356                 if (mainmenu == 0 && winfreeze && (campaignlevels[actuallevel].choosenext) == 1) {
7357                     if (campaignlevels[actuallevel].nextlevel.empty())
7358                         endgame = 1;
7359                 } else if (mainmenu == 0 && winfreeze) {
7360                     stealthloading = (campaignlevels[actuallevel].choosenext == 2);
7361
7362                     if (!stealthloading) {
7363                         fireSound(firestartsound);
7364
7365                         flash();
7366                     }
7367
7368                     startbonustotal = 0;
7369
7370                     LoadCampaign();
7371
7372                     loading = 2;
7373                     loadtime = 0;
7374                     targetlevel = 7;
7375                     if (!firstload)
7376                         LoadStuff();
7377                     whichchoice = 0;
7378                     actuallevel = campaignlevels[actuallevel].nextlevel.front();
7379                     visibleloading = 1;
7380                     stillloading = 1;
7381                     Loadlevel(campaignlevels[actuallevel].mapname.c_str());
7382                     campaign = 1;
7383                     mainmenu = 0;
7384                     gameon = 1;
7385                     pause_sound(stream_menutheme);
7386
7387                     stealthloading = 0;
7388                 }
7389             }
7390
7391             if (loading == 3)
7392                 loading = 0;
7393
7394         }
7395
7396         oldmusictype = musictype;
7397     }
7398
7399     facing = 0;
7400     facing.z = -1;
7401
7402     facing = DoRotation(facing, -pitch, 0, 0);
7403     facing = DoRotation(facing, 0, 0 - yaw, 0);
7404     viewerfacing = facing;
7405
7406     if (!cameramode) {
7407         if ((animation[Person::players[0]->animTarget].attack != 3 && animation[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
7408             target = Person::players[0]->coords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
7409         else
7410             target = Person::players[0]->oldcoords + Person::players[0]->currentoffset * (1 - Person::players[0]->target) * Person::players[0]->scale + Person::players[0]->targetoffset * Person::players[0]->target * Person::players[0]->scale - Person::players[0]->facing * .05;
7411         target.y += .1;
7412         if (Person::players[0]->skeleton.free) {
7413             for (int i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
7414                 if (Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y > target.y)
7415                     target.y = Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y;
7416             }
7417             target.y += .1;
7418         }
7419         if (Person::players[0]->skeleton.free != 2) {
7420             cameraspeed = 20;
7421             if (findLengthfast(&Person::players[0]->velocity) > 400) {
7422                 cameraspeed = 20 + (findLength(&Person::players[0]->velocity) - 20) * .96;
7423             }
7424             if (Person::players[0]->skeleton.free == 0 && Person::players[0]->animTarget != hanganim && Person::players[0]->animTarget != climbanim)
7425                 target.y += 1.4;
7426             coltarget = target - cameraloc;
7427             if (findLengthfast(&coltarget) < multiplier * multiplier * 400)
7428                 cameraloc = target;
7429             else {
7430                 Normalise(&coltarget);
7431                 if (Person::players[0]->animTarget != hanganim && Person::players[0]->animTarget != climbanim && Person::players[0]->animCurrent != climbanim && Person::players[0]->currentoffset.x == 0)
7432                     cameraloc = cameraloc + coltarget * multiplier * cameraspeed;
7433                 else
7434                     cameraloc = cameraloc + coltarget * multiplier * 8;
7435             }
7436             if (editorenabled)
7437                 cameraloc = target;
7438             cameradist += multiplier * 5;
7439             if (cameradist > 2.3)
7440                 cameradist = 2.3;
7441             viewer = cameraloc - facing * cameradist;
7442             colviewer = viewer;
7443             coltarget = cameraloc;
7444             objects.SphereCheckPossible(&colviewer, findDistance(&colviewer, &coltarget));
7445             if (terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz])
7446                 for (int j = 0; j < terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz]; j++) {
7447                     int i = terrain.patchobjects[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz][j];
7448                     colviewer = viewer;
7449                     coltarget = cameraloc;
7450                     if (objects.model[i].LineCheckPossible(&colviewer, &coltarget, &col, &objects.position[i], &objects.yaw[i]) != -1)
7451                         viewer = col;
7452                 }
7453             if (terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz])
7454                 for (int j = 0; j < terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz]; j++) {
7455                     int i = terrain.patchobjects[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz][j];
7456                     colviewer = viewer;
7457                     if (objects.model[i].SphereCheck(&colviewer, .15, &col, &objects.position[i], &objects.yaw[i]) != -1) {
7458                         viewer = colviewer;
7459                     }
7460                 }
7461             cameradist = findDistance(&viewer, &target);
7462             viewer.y = max((double)viewer.y, terrain.getHeight(viewer.x, viewer.z) + .6);
7463             if (cameraloc.y < terrain.getHeight(cameraloc.x, cameraloc.z)) {
7464                 cameraloc.y = terrain.getHeight(cameraloc.x, cameraloc.z);
7465             }
7466         }
7467         if (camerashake > .8)
7468             camerashake = .8;
7469         woozy += multiplier;
7470         if (Person::players[0]->dead)
7471             camerashake = 0;
7472         if (Person::players[0]->dead)
7473             woozy = 0;
7474         camerashake -= multiplier * 2;
7475         blackout -= multiplier * 2;
7476         if (camerashake < 0)
7477             camerashake = 0;
7478         if (blackout < 0)
7479             blackout = 0;
7480         if (camerashake) {
7481             viewer.x += (float)(Random() % 100) * .0005 * camerashake;
7482             viewer.y += (float)(Random() % 100) * .0005 * camerashake;
7483             viewer.z += (float)(Random() % 100) * .0005 * camerashake;
7484         }
7485     }
7486 }
7487