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