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