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