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