]> git.jsancho.org Git - lugaru.git/blob - Source/GameTick.cpp
Handle the case where the current campaign has been deleted since last game.
[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 #if PLATFORM_UNIX
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #else
27 #include <direct.h>
28 #endif
29
30 #include <limits>
31 #include <ctime>
32 #include <dirent.h>
33 #include "Game.h"
34 #include "openal_wrapper.h"
35 #include "Settings.h"
36 #include "Input.h"
37 #include "Animation.h"
38 #include "Awards.h"
39 #include "Menu.h"
40
41 #include <algorithm>
42
43 using namespace std;
44 using namespace Game;
45
46 // Added more evilness needed for MSVC
47 #ifdef _MSC_VER
48 #define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n)
49 #define snprintf(buf, size, format, ...) _sprintf_p(buf, size, format)
50 #endif
51
52
53 extern float multiplier;
54 extern XYZ viewer;
55 extern int environment;
56 extern Terrain terrain;
57 extern float screenwidth, screenheight;
58 extern float gravity;
59 extern int detail;
60 extern float texdetail;
61 extern Objects objects;
62 extern int slomo;
63 extern float slomodelay;
64 extern bool floatjump;
65 extern float volume;
66 extern Light light;
67 extern float camerashake;
68 extern float woozy;
69 extern float blackout;
70 extern bool cellophane;
71 extern bool musictoggle;
72 extern int difficulty;
73 extern int bloodtoggle;
74 extern bool invertmouse;
75 extern float windvar;
76 extern float precipdelay;
77 extern XYZ viewerfacing;
78 extern bool ambientsound;
79 extern bool mousejump;
80 extern float viewdistance;
81 extern bool freeze;
82 extern bool keyboardfrozen;
83 extern bool loadingstuff;
84 extern XYZ windvector;
85 extern bool debugmode;
86 static int leveltheme;
87 extern int mainmenu;
88 extern int oldmainmenu;
89 extern bool visibleloading;
90 extern XYZ envsound[30];
91 extern float envsoundvol[30];
92 extern int numenvsounds;
93 extern float envsoundlife[30];
94 extern float usermousesensitivity;
95 extern bool ismotionblur;
96 extern bool showdamagebar; // (des)activate the damage bar
97 extern bool decals;
98 extern float tintr, tintg, tintb;
99 extern bool skyboxtexture;
100 extern float skyboxr;
101 extern float skyboxg;
102 extern float skyboxb;
103 extern float skyboxlightr;
104 extern float skyboxlightg;
105 extern float skyboxlightb;
106 extern float fadestart;
107 extern float slomospeed;
108 extern float slomofreq;
109 extern int tutoriallevel;
110 extern float smoketex;
111 extern float tutorialstagetime;
112 extern int tutorialstage;
113 extern float tutorialmaxtime;
114 extern float tutorialsuccess;
115 extern bool againbonus;
116 extern bool reversaltrain;
117 extern bool canattack;
118 extern bool cananger;
119 extern float damagedealt;
120 extern int maptype;
121 extern int editoractive;
122 extern int editorpathtype;
123 extern TGAImageRec texture;
124
125 extern float hostiletime;
126
127 extern bool gamestarted;
128
129 extern int numhotspots;
130 extern int killhotspot;
131 extern XYZ hotspot[40];
132 extern int hotspottype[40];
133 extern float hotspotsize[40];
134 extern char hotspottext[40][256];
135 extern int currenthotspot;
136
137 extern int hostile;
138
139 extern bool stillloading;
140 extern bool winfreeze;
141
142 extern bool campaign;
143
144
145
146 void Loadlevel(int which);
147 void Loadlevel(const char *name);
148
149
150
151 class CampaignLevel
152 {
153 private:
154     int width;
155     struct Position {
156         int x, y;
157     };
158 public:
159     std::string mapname;
160     std::string description;
161     int choosenext;
162     /*
163     0 = Immediately load next level at the end of this one.
164     1 = Go back to the world map.
165     2 = Don't bring up the Fiery loading screen. Maybe other things, I've not investigated.
166     */
167     //int numnext; // 0 on final level. As David said: he meant to add story branching, but he eventually hadn't.
168     std::vector<int> nextlevel;
169     Position location;
170     CampaignLevel() : width(10) {
171         choosenext = 1;
172         location.x = 0;
173         location.y = 0;
174     }
175     int getStartX() {
176         return 30 + 120 + location.x * 400 / 512;
177     }
178     int getStartY() {
179         return 30 + 30 + (512 - location.y) * 400 / 512;
180     }
181     int getEndX() {
182         return getStartX() + width;
183     }
184     int getEndY() {
185         return getStartY() + width;
186     }
187     XYZ getCenter() {
188         XYZ center;
189         center.x = getStartX() + width / 2;
190         center.y = getStartY() + width / 2;
191         return center;
192     }
193     int getWidth() {
194         return width;
195     }
196     istream& operator<< (istream& is) {
197         is.ignore(256, ':');
198         is.ignore(256, ':');
199         is.ignore(256, ' ');
200         is >> mapname;
201         is.ignore(256, ':');
202         is >> description;
203         for (unsigned pos = description.find('_'); pos != string::npos; pos = description.find('_', pos)) {
204             description.replace(pos, 1, 1, ' ');
205         }
206         is.ignore(256, ':');
207         is >> choosenext;
208         is.ignore(256, ':');
209         int numnext, next;
210         is >> numnext;
211         for (int j = 0; j < numnext; j++) {
212             is.ignore(256, ':');
213             is >> next;
214             nextlevel.push_back(next - 1);
215         }
216         is.ignore(256, ':');
217         is >> location.x;
218         is.ignore(256, ':');
219         is >> location.y;
220         return is;
221     }
222     friend istream& operator>> (istream& is, CampaignLevel& cl) {
223         return cl << is;
224     }
225 };
226
227 int indemo = 0;
228 bool won = false;
229 int entername = 0;
230 vector<CampaignLevel> campaignlevels;
231 int whichchoice = 0;
232 int actuallevel = 0;
233 bool winhotspot = false;
234 bool windialogue = false;
235 bool realthreat = 0;
236 XYZ cameraloc;
237 float cameradist = 0;
238 bool oldattackkey = 0;
239 int whichlevel = 0;
240 float musicvolume[4] = {};
241 float oldmusicvolume[4] = {};
242 int musicselected = 0;
243
244
245
246 static const char *rabbitskin[] = {
247     ":Data:Textures:Fur3.jpg",
248     ":Data:Textures:Fur.jpg",
249     ":Data:Textures:Fur2.jpg",
250     ":Data:Textures:Lynx.jpg",
251     ":Data:Textures:Otter.jpg",
252     ":Data:Textures:Opal.jpg",
253     ":Data:Textures:Sable.jpg",
254     ":Data:Textures:Chocolate.jpg",
255     ":Data:Textures:BW2.jpg",
256     ":Data:Textures:WB2.jpg"
257 };
258
259 static const char *wolfskin[] = {
260     ":Data:Textures:Wolf.jpg",
261     ":Data:Textures:Darkwolf.jpg",
262     ":Data:Textures:Snowwolf.jpg"
263 };
264
265 #define STATIC_ASSERT(x) extern int s_a_dummy[2 * (!!(x)) - 1];
266 STATIC_ASSERT (rabbittype == 0 && wolftype == 1)
267
268 static const char **creatureskin[] = {rabbitskin, wolfskin};
269
270 /* Return true if PFX is a prefix of STR (case-insensitive).  */
271 static bool stripfx(const char *str, const char *pfx)
272 {
273     return !strncasecmp(str, pfx, strlen(pfx));
274 }
275
276 static const char *cmd_names[] = {
277 #define DECLARE_COMMAND(cmd) #cmd,
278 #include "ConsoleCmds.h"
279 #undef  DECLARE_COMMAND
280 };
281
282 typedef void (*console_handler)(const char *args);
283
284 #define DECLARE_COMMAND(cmd) static void ch_##cmd(const char *args);
285 #include "ConsoleCmds.h"
286 #undef  DECLARE_COMMAND
287
288 static console_handler cmd_handlers[] = {
289 #define DECLARE_COMMAND(cmd) ch_##cmd,
290 #include "ConsoleCmds.h"
291 #undef  DECLARE_COMMAND
292 };
293
294
295
296 // utility functions
297
298 // TODO: this is slightly incorrect
299 inline float roughDirection(XYZ vec)
300 {
301     Normalise(&vec);
302     float angle = -asin(-vec.x) * 180 / M_PI;
303     if (vec.z < 0)
304         angle = 180 - angle;
305     return angle;
306 }
307 inline float roughDirectionTo(XYZ start, XYZ end)
308 {
309     return roughDirection(end - start);
310 }
311 inline float pitchOf(XYZ vec)
312 {
313     Normalise(&vec);
314     return -asin(vec.y) * 180 / M_PI;
315 }
316 inline float pitchTo(XYZ start, XYZ end)
317 {
318     return pitchOf(end - start);
319 }
320 inline float sq(float n)
321 {
322     return n * n;
323 }
324 inline float stepTowardf(float from, float to, float by)
325 {
326     if (fabs(from - to) < by)
327         return to;
328     else if (from > to)
329         return from - by;
330     else
331         return from + by;
332 }
333
334 void playdialogueboxsound()
335 {
336     XYZ temppos;
337     temppos = Person::players[participantfocus[whichdialogue][indialogue]]->coords;
338     temppos = temppos - viewer;
339     Normalise(&temppos);
340     temppos += viewer;
341
342     int sound = -1;
343     switch (dialogueboxsound[whichdialogue][indialogue]) {
344     case -6:
345         sound = alarmsound;
346         break;
347     case -4:
348         sound = consolefailsound;
349         break;
350     case -3:
351         sound = consolesuccesssound;
352         break;
353     case -2:
354         sound = firestartsound;
355         break;
356     case -1:
357         sound = fireendsound;
358         break;
359     case 1:
360         sound = rabbitchitter;
361         break;
362     case 2:
363         sound = rabbitchitter2;
364         break;
365     case 3:
366         sound = rabbitpainsound;
367         break;
368     case 4:
369         sound = rabbitpain1sound;
370         break;
371     case 5:
372         sound = rabbitattacksound;
373         break;
374     case 6:
375         sound = rabbitattack2sound;
376         break;
377     case 7:
378         sound = rabbitattack3sound;
379         break;
380     case 8:
381         sound = rabbitattack4sound;
382         break;
383     case 9:
384         sound = growlsound;
385         break;
386     case 10:
387         sound = growl2sound;
388         break;
389     case 11:
390         sound = snarlsound;
391         break;
392     case 12:
393         sound = snarl2sound;
394         break;
395     case 13:
396         sound = barksound;
397         break;
398     case 14:
399         sound = bark2sound;
400         break;
401     case 15:
402         sound = bark3sound;
403         break;
404     case 16:
405         sound = barkgrowlsound;
406         break;
407     default:
408         break;
409     }
410     if (sound != -1)
411         emit_sound_at(sound, temppos);
412 }
413
414 // ================================================================
415
416 bool AddClothes(const char *fileName, GLubyte *array)
417 {
418     LOGFUNC;
419     //Load Image
420     unsigned char fileNamep[256];
421     CopyCStringToPascal(fileName, fileNamep);
422     bool opened;
423     opened = upload_image( fileNamep , 1);
424
425     float alphanum;
426     //Is it valid?
427     if (opened) {
428         if (tintr > 1) tintr = 1;
429         if (tintg > 1) tintg = 1;
430         if (tintb > 1) tintb = 1;
431
432         if (tintr < 0) tintr = 0;
433         if (tintg < 0) tintg = 0;
434         if (tintb < 0) tintb = 0;
435
436         int bytesPerPixel = texture.bpp / 8;
437
438         int tempnum = 0;
439         alphanum = 255;
440         for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
441             if (bytesPerPixel == 3)
442                 alphanum = 255;
443             else if ((i + 1) % 4 == 0)
444                 alphanum = texture.data[i];
445             //alphanum/=2;
446             if ((i + 1) % 4 || bytesPerPixel == 3) {
447                 if ((i % 4) == 0)
448                     texture.data[i] *= tintr;
449                 if ((i % 4) == 1)
450                     texture.data[i] *= tintg;
451                 if ((i % 4) == 2)
452                     texture.data[i] *= tintb;
453                 array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
454                 tempnum++;
455             }
456         }
457     } else
458         return 0;
459     return 1;
460 }
461
462
463
464 static void ch_quit(const char *args)
465 {
466     tryquit = 1;
467 }
468
469 static void ch_map(const char *args)
470 {
471     Loadlevel(args);
472     whichlevel = -2;
473     campaign = 0;
474 }
475
476 static void ch_save(const char *args)
477 {
478     char buf[64];
479     snprintf(buf, 63, ":Data:Maps:%s", args);
480
481     int mapvers = 12;
482
483     FILE *tfile;
484     tfile = fopen( ConvertFileName(buf), "wb" );
485     fpackf(tfile, "Bi", mapvers);
486     fpackf(tfile, "Bi", maptype);
487     fpackf(tfile, "Bi", hostile);
488     fpackf(tfile, "Bf Bf", viewdistance, fadestart);
489     fpackf(tfile, "Bb Bf Bf Bf", skyboxtexture, skyboxr, skyboxg, skyboxb);
490     fpackf(tfile, "Bf Bf Bf", skyboxlightr, skyboxlightg, skyboxlightb);
491     fpackf(tfile, "Bf Bf Bf Bf Bf Bi", Person::players[0]->coords.x, Person::players[0]->coords.y, Person::players[0]->coords.z,
492            Person::players[0]->yaw, Person::players[0]->targetyaw, Person::players[0]->num_weapons);
493     if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
494         for (int j = 0; j < Person::players[0]->num_weapons; j++)
495             fpackf(tfile, "Bi", weapons[Person::players[0]->weaponids[j]].getType());
496
497     fpackf(tfile, "Bf Bf Bf", Person::players[0]->armorhead, Person::players[0]->armorhigh, Person::players[0]->armorlow);
498     fpackf(tfile, "Bf Bf Bf", Person::players[0]->protectionhead, Person::players[0]->protectionhigh, Person::players[0]->protectionlow);
499     fpackf(tfile, "Bf Bf Bf", Person::players[0]->metalhead, Person::players[0]->metalhigh, Person::players[0]->metallow);
500     fpackf(tfile, "Bf Bf", Person::players[0]->power, Person::players[0]->speedmult);
501
502     fpackf(tfile, "Bi", Person::players[0]->numclothes);
503
504     fpackf(tfile, "Bi Bi", Person::players[0]->whichskin, Person::players[0]->creature);
505
506     fpackf(tfile, "Bi", numdialogues);
507
508     for (int k = 0; k < numdialogues; k++) {
509         fpackf(tfile, "Bi", numdialogueboxes[k]);
510         fpackf(tfile, "Bi", dialoguetype[k]);
511         for (int l = 0; l < 10; l++) {
512             fpackf(tfile, "Bf Bf Bf", participantlocation[k][l].x, participantlocation[k][l].y, participantlocation[k][l].z);
513             fpackf(tfile, "Bf", participantyaw[k][l]);
514         }
515         for (int l = 0; l < numdialogueboxes[k]; l++) {
516             fpackf(tfile, "Bi", dialogueboxlocation[k][l]);
517             fpackf(tfile, "Bf", dialogueboxcolor[k][l][0]);
518             fpackf(tfile, "Bf", dialogueboxcolor[k][l][1]);
519             fpackf(tfile, "Bf", dialogueboxcolor[k][l][2]);
520             fpackf(tfile, "Bi", dialogueboxsound[k][l]);
521
522             int templength = strlen(dialoguetext[k][l]);
523             fpackf(tfile, "Bi", (templength));
524             for (int m = 0; m < templength; m++) {
525                 fpackf(tfile, "Bb", dialoguetext[k][l][m]);
526                 if (dialoguetext[k][l][m] == '\0')
527                     break;
528             }
529
530             templength = strlen(dialoguename[k][l]);
531             fpackf(tfile, "Bi", templength);
532             for (int m = 0; m < templength; m++) {
533                 fpackf(tfile, "Bb", dialoguename[k][l][m]);
534                 if (dialoguename[k][l][m] == '\0')
535                     break;
536             }
537
538             fpackf(tfile, "Bf Bf Bf", dialoguecamera[k][l].x, dialoguecamera[k][l].y, dialoguecamera[k][l].z);
539             fpackf(tfile, "Bi", participantfocus[k][l]);
540             fpackf(tfile, "Bi", participantaction[k][l]);
541
542             for (int m = 0; m < 10; m++)
543                 fpackf(tfile, "Bf Bf Bf", participantfacing[k][l][m].x, participantfacing[k][l][m].y, participantfacing[k][l][m].z);
544
545             fpackf(tfile, "Bf Bf", dialoguecamerayaw[k][l], dialoguecamerapitch[k][l]);
546         }
547     }
548
549     for (int k = 0; k < Person::players[0]->numclothes; k++) {
550         int templength = strlen(Person::players[0]->clothes[k]);
551         fpackf(tfile, "Bi", templength);
552         for (int l = 0; l < templength; l++)
553             fpackf(tfile, "Bb", Person::players[0]->clothes[k][l]);
554         fpackf(tfile, "Bf Bf Bf", Person::players[0]->clothestintr[k], Person::players[0]->clothestintg[k], Person::players[0]->clothestintb[k]);
555     }
556
557     fpackf(tfile, "Bi", environment);
558
559     fpackf(tfile, "Bi", objects.numobjects);
560
561     for (int k = 0; k < objects.numobjects; k++)
562         fpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", objects.type[k], objects.yaw[k], objects.pitch[k],
563                objects.position[k].x, objects.position[k].y, objects.position[k].z, objects.scale[k]);
564
565     fpackf(tfile, "Bi", numhotspots);
566     for (int i = 0; i < numhotspots; i++) {
567         fpackf(tfile, "Bi Bf Bf Bf Bf", hotspottype[i], hotspotsize[i], hotspot[i].x, hotspot[i].y, hotspot[i].z);
568         int templength = strlen(hotspottext[i]);
569         fpackf(tfile, "Bi", templength);
570         for (int l = 0; l < templength; l++)
571             fpackf(tfile, "Bb", hotspottext[i][l]);
572     }
573
574     fpackf(tfile, "Bi", Person::players.size());
575     if (Person::players.size() > maxplayers) {
576         cout << "Warning: this level contains more players than allowed" << endl;
577     }
578     for (int j = 1; j < Person::players.size(); j++) {
579         fpackf(tfile, "Bi Bi Bf Bf Bf Bi Bi Bf Bb Bf", Person::players[j]->whichskin, Person::players[j]->creature,
580                Person::players[j]->coords.x, Person::players[j]->coords.y, Person::players[j]->coords.z,
581                Person::players[j]->num_weapons, Person::players[j]->howactive, Person::players[j]->scale, Person::players[j]->immobile, Person::players[j]->yaw);
582         if (Person::players[j]->num_weapons < 5)
583             for (int k = 0; k < Person::players[j]->num_weapons; k++)
584                 fpackf(tfile, "Bi", weapons[Person::players[j]->weaponids[k]].getType());
585         if (Person::players[j]->numwaypoints < 30) {
586             fpackf(tfile, "Bi", Person::players[j]->numwaypoints);
587             for (int k = 0; k < Person::players[j]->numwaypoints; k++) {
588                 fpackf(tfile, "Bf", Person::players[j]->waypoints[k].x);
589                 fpackf(tfile, "Bf", Person::players[j]->waypoints[k].y);
590                 fpackf(tfile, "Bf", Person::players[j]->waypoints[k].z);
591                 fpackf(tfile, "Bi", Person::players[j]->waypointtype[k]);
592             }
593             fpackf(tfile, "Bi", Person::players[j]->waypoint);
594         } else {
595             Person::players[j]->numwaypoints = 0;
596             Person::players[j]->waypoint = 0;
597             fpackf(tfile, "Bi Bi Bi", Person::players[j]->numwaypoints, Person::players[j]->waypoint, Person::players[j]->waypoint);
598         }
599
600         fpackf(tfile, "Bf Bf Bf", Person::players[j]->armorhead, Person::players[j]->armorhigh, Person::players[j]->armorlow);
601         fpackf(tfile, "Bf Bf Bf", Person::players[j]->protectionhead, Person::players[j]->protectionhigh, Person::players[j]->protectionlow);
602         fpackf(tfile, "Bf Bf Bf", Person::players[j]->metalhead, Person::players[j]->metalhigh, Person::players[j]->metallow);
603         fpackf(tfile, "Bf Bf", Person::players[j]->power, Person::players[j]->speedmult);
604
605         float headprop, bodyprop, armprop, legprop;
606         if (Person::players[j]->creature == wolftype) {
607             headprop = Person::players[j]->proportionhead.x / 1.1;
608             bodyprop = Person::players[j]->proportionbody.x / 1.1;
609             armprop = Person::players[j]->proportionarms.x / 1.1;
610             legprop = Person::players[j]->proportionlegs.x / 1.1;
611         } else if (Person::players[j]->creature == rabbittype) {
612             headprop = Person::players[j]->proportionhead.x / 1.2;
613             bodyprop = Person::players[j]->proportionbody.x / 1.05;
614             armprop = Person::players[j]->proportionarms.x / 1.00;
615             legprop = Person::players[j]->proportionlegs.x / 1.1;
616         }
617
618         fpackf(tfile, "Bf Bf Bf Bf", headprop, bodyprop, armprop, legprop);
619
620         fpackf(tfile, "Bi", Person::players[j]->numclothes);
621         if (Person::players[j]->numclothes)
622             for (int k = 0; k < Person::players[j]->numclothes; k++) {
623                 int templength;
624                 templength = strlen(Person::players[j]->clothes[k]);
625                 fpackf(tfile, "Bi", templength);
626                 for (int l = 0; l < templength; l++)
627                     fpackf(tfile, "Bb", Person::players[j]->clothes[k][l]);
628                 fpackf(tfile, "Bf Bf Bf", Person::players[j]->clothestintr[k], Person::players[j]->clothestintg[k], Person::players[j]->clothestintb[k]);
629             }
630     }
631
632     fpackf(tfile, "Bi", numpathpoints);
633     for (int j = 0; j < numpathpoints; j++) {
634         fpackf(tfile, "Bf Bf Bf Bi", pathpoint[j].x, pathpoint[j].y, pathpoint[j].z, numpathpointconnect[j]);
635         for (int k = 0; k < numpathpointconnect[j]; k++)
636             fpackf(tfile, "Bi", pathpointconnect[j][k]);
637     }
638
639     fpackf(tfile, "Bf Bf Bf Bf", mapcenter.x, mapcenter.y, mapcenter.z, mapradius);
640
641     fclose(tfile);
642 }
643
644 static void ch_cellar(const char *args)
645 {
646     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:Furdarko.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
647 }
648
649 static void ch_tint(const char *args)
650 {
651     sscanf(args, "%f%f%f", &tintr, &tintg, &tintb);
652 }
653
654 static void ch_tintr(const char *args)
655 {
656     tintr = atof(args);
657 }
658
659 static void ch_tintg(const char *args)
660 {
661     tintg = atof(args);
662 }
663
664 static void ch_tintb(const char *args)
665 {
666     tintb = atof(args);
667 }
668
669 static void ch_speed(const char *args)
670 {
671     Person::players[0]->speedmult = atof(args);
672 }
673
674 static void ch_strength(const char *args)
675 {
676     Person::players[0]->power = atof(args);
677 }
678
679 static void ch_power(const char *args)
680 {
681     Person::players[0]->power = atof(args);
682 }
683
684 static void ch_size(const char *args)
685 {
686     Person::players[0]->scale = atof(args) * .2;
687 }
688
689 static int findClosestPlayer()
690 {
691     int closest = -1;
692     float closestdist = std::numeric_limits<float>::max();
693
694     for (int i = 1; i < Person::players.size(); i++) {
695         float distance = distsq(&Person::players[i]->coords, &Person::players[0]->coords);
696         if (distance < closestdist) {
697             closestdist = distance;
698             closest = i;
699         }
700     }
701     return closest;
702 }
703
704 static int findClosestObject()
705 {
706     int closest = -1;
707     float closestdist = std::numeric_limits<float>::max();
708
709     for (int i = 0; i < objects.numobjects; i++) {
710         float distance = distsq(&objects.position[i], &Person::players[0]->coords);
711         if (distance < closestdist) {
712             closestdist = distance;
713             closest = i;
714         }
715     }
716     return closest;
717 }
718
719 static void ch_sizenear(const char *args)
720 {
721     int closest = findClosestPlayer();
722     if (closest >= 0)
723         Person::players[closest]->scale = atof(args) * .2;
724 }
725
726 static void set_proportion(int pnum, const char *args)
727 {
728     float headprop, bodyprop, armprop, legprop;
729
730     sscanf(args, "%f%f%f%f", &headprop, &bodyprop, &armprop, &legprop);
731
732     if (Person::players[pnum]->creature == wolftype) {
733         Person::players[pnum]->proportionhead = 1.1 * headprop;
734         Person::players[pnum]->proportionbody = 1.1 * bodyprop;
735         Person::players[pnum]->proportionarms = 1.1 * armprop;
736         Person::players[pnum]->proportionlegs = 1.1 * legprop;
737     } else if (Person::players[pnum]->creature == rabbittype) {
738         Person::players[pnum]->proportionhead = 1.2 * headprop;
739         Person::players[pnum]->proportionbody = 1.05 * bodyprop;
740         Person::players[pnum]->proportionarms = 1.00 * armprop;
741         Person::players[pnum]->proportionlegs = 1.1 * legprop;
742         Person::players[pnum]->proportionlegs.y = 1.05 * legprop;
743     }
744 }
745
746 static void ch_proportion(const char *args)
747 {
748     set_proportion(0, args);
749 }
750
751 static void ch_proportionnear(const char *args)
752 {
753     int closest = findClosestPlayer();
754     if (closest >= 0)
755         set_proportion(closest, args);
756 }
757
758 static void set_protection(int pnum, const char *args)
759 {
760     float head, high, low;
761     sscanf(args, "%f%f%f", &head, &high, &low);
762
763     Person::players[pnum]->protectionhead = head;
764     Person::players[pnum]->protectionhigh = high;
765     Person::players[pnum]->protectionlow  = low;
766 }
767
768 static void ch_protection(const char *args)
769 {
770     set_protection(0, args);
771 }
772
773 static void ch_protectionnear(const char *args)
774 {
775     int closest = findClosestPlayer();
776     if (closest >= 0)
777         set_protection(closest, args);
778 }
779
780 static void set_armor(int pnum, const char *args)
781 {
782     float head, high, low;
783     sscanf(args, "%f%f%f", &head, &high, &low);
784
785     Person::players[pnum]->armorhead = head;
786     Person::players[pnum]->armorhigh = high;
787     Person::players[pnum]->armorlow  = low;
788 }
789
790 static void ch_armor(const char *args)
791 {
792     set_armor(0, args);
793 }
794
795 static void ch_armornear(const char *args)
796 {
797     int closest = findClosestPlayer();
798     if (closest >= 0)
799         set_armor(closest, args);
800 }
801
802 static void ch_protectionreset(const char *args)
803 {
804     set_protection(0, "1 1 1");
805     set_armor(0, "1 1 1");
806 }
807
808 static void set_metal(int pnum, const char *args)
809 {
810     float head, high, low;
811     sscanf(args, "%f%f%f", &head, &high, &low);
812
813     Person::players[pnum]->metalhead = head;
814     Person::players[pnum]->metalhigh = high;
815     Person::players[pnum]->metallow  = low;
816 }
817
818 static void ch_metal(const char *args)
819 {
820     set_metal(0, args);
821 }
822
823 static void set_noclothes(int pnum, const char *args)
824 {
825     Person::players[pnum]->numclothes = 0;
826     Person::players[pnum]->skeleton.drawmodel.textureptr.load(
827         creatureskin[Person::players[pnum]->creature][Person::players[pnum]->whichskin], 1,
828         &Person::players[pnum]->skeleton.skinText[0], &Person::players[pnum]->skeleton.skinsize);
829 }
830
831 static void ch_noclothes(const char *args)
832 {
833     set_noclothes(0, args);
834 }
835
836 static void ch_noclothesnear(const char *args)
837 {
838     int closest = findClosestPlayer();
839     if (closest >= 0)
840         set_noclothes(closest, args);
841 }
842
843
844 static void set_clothes(int pnum, const char *args)
845 {
846     char buf[64];
847     snprintf(buf, 63, ":Data:Textures:%s.png", args);
848
849     if (!AddClothes(buf, &Person::players[pnum]->skeleton.skinText[pnum]))
850         return;
851
852     Person::players[pnum]->DoMipmaps();
853     strcpy(Person::players[pnum]->clothes[Person::players[pnum]->numclothes], buf);
854     Person::players[pnum]->clothestintr[Person::players[pnum]->numclothes] = tintr;
855     Person::players[pnum]->clothestintg[Person::players[pnum]->numclothes] = tintg;
856     Person::players[pnum]->clothestintb[Person::players[pnum]->numclothes] = tintb;
857     Person::players[pnum]->numclothes++;
858 }
859
860 static void ch_clothes(const char *args)
861 {
862     set_clothes(0, args);
863 }
864
865 static void ch_clothesnear(const char *args)
866 {
867     int closest = findClosestPlayer();
868     if (closest >= 0)
869         set_clothes(closest, args);
870 }
871
872 static void ch_belt(const char *args)
873 {
874     Person::players[0]->skeleton.clothes = !Person::players[0]->skeleton.clothes;
875 }
876
877
878 static void ch_cellophane(const char *args)
879 {
880     cellophane = !cellophane;
881     float mul = (cellophane ? 0 : 1);
882
883     for (auto player : Person::players) {
884         player->proportionhead.z = player->proportionhead.x * mul;
885         player->proportionbody.z = player->proportionbody.x * mul;
886         player->proportionarms.z = player->proportionarms.x * mul;
887         player->proportionlegs.z = player->proportionlegs.x * mul;
888     }
889 }
890
891 static void ch_funnybunny(const char *args)
892 {
893     Person::players[0]->skeleton.id = 0;
894     Person::players[0]->skeleton.Load(":Data:Skeleton:Basic Figure", ":Data:Skeleton:Basic Figurelow",
895                             ":Data:Skeleton:Rabbitbelt", ":Data:Models:Body.solid",
896                             ":Data:Models:Body2.solid", ":Data:Models:Body3.solid",
897                             ":Data:Models:Body4.solid", ":Data:Models:Body5.solid",
898                             ":Data:Models:Body6.solid", ":Data:Models:Body7.solid",
899                             ":Data:Models:Bodylow.solid", ":Data:Models:Belt.solid", 1);
900     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:fur3.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
901     Person::players[0]->creature = rabbittype;
902     Person::players[0]->scale = .2;
903     Person::players[0]->headless = 0;
904     Person::players[0]->damagetolerance = 200;
905     set_proportion(0, "1 1 1 1");
906 }
907
908 static void ch_wolfie(const char *args)
909 {
910     Person::players[0]->skeleton.id = 0;
911     Person::players[0]->skeleton.Load(":Data:Skeleton:Basic Figure Wolf", ":Data:Skeleton:Basic Figure Wolf Low",
912                             ":Data:Skeleton:Rabbitbelt", ":Data:Models:Wolf.solid",
913                             ":Data:Models:Wolf2.solid", ":Data:Models:Wolf3.solid",
914                             ":Data:Models:Wolf4.solid", ":Data:Models:Wolf5.solid",
915                             ":Data:Models:Wolf6.solid", ":Data:Models:Wolf7.solid",
916                             ":Data:Models:Wolflow.solid", ":Data:Models:Belt.solid", 0);
917     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:Wolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
918     Person::players[0]->creature = wolftype;
919     Person::players[0]->damagetolerance = 300;
920     set_proportion(0, "1 1 1 1");
921 }
922
923 static void ch_wolfieisgod(const char *args)
924 {
925     ch_wolfie(args);
926 }
927
928 static void ch_wolf(const char *args)
929 {
930     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:Wolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
931 }
932
933 static void ch_snowwolf(const char *args)
934 {
935     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:SnowWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
936 }
937
938 static void ch_darkwolf(const char *args)
939 {
940     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:DarkWolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
941 }
942
943 static void ch_lizardwolf(const char *args)
944 {
945     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:Lizardwolf.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
946 }
947
948 static void ch_white(const char *args)
949 {
950     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:fur.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
951 }
952
953 static void ch_brown(const char *args)
954 {
955     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:fur3.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
956 }
957
958 static void ch_black(const char *args)
959 {
960     Person::players[0]->skeleton.drawmodel.textureptr.load(":Data:Textures:fur2.jpg", 1, &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
961 }
962
963 static void ch_sizemin(const char *args)
964 {
965     for (int i = 1; i < Person::players.size(); i++)
966         if (Person::players[i]->scale < 0.8 * 0.2)
967             Person::players[i]->scale = 0.8 * 0.2;
968 }
969
970 static void ch_tutorial(const char *args)
971 {
972     tutoriallevel = atoi(args);
973 }
974
975 static void ch_hostile(const char *args)
976 {
977     hostile = atoi(args);
978 }
979
980 static void ch_indemo(const char *args)
981 {
982     indemo = 1;
983     hotspot[numhotspots] = Person::players[0]->coords;
984     hotspotsize[numhotspots] = 0;
985     hotspottype[numhotspots] = -111;
986     strcpy(hotspottext[numhotspots], "mapname");
987     numhotspots++;
988 }
989
990 static void ch_notindemo(const char *args)
991 {
992     indemo = 0;
993     numhotspots--;
994 }
995
996 static void ch_type(const char *args)
997 {
998     int n = sizeof(editortypenames) / sizeof(editortypenames[0]);
999     for (int i = 0; i < n; i++)
1000         if (stripfx(args, editortypenames[i])) {
1001             editoractive = i;
1002             break;
1003         }
1004 }
1005
1006 static void ch_path(const char *args)
1007 {
1008     int n = sizeof(pathtypenames) / sizeof(pathtypenames[0]);
1009     for (int i = 0; i < n; i++)
1010         if (stripfx(args, pathtypenames[i])) {
1011             editorpathtype = i;
1012             break;
1013         }
1014 }
1015
1016 static void ch_hs(const char *args)
1017 {
1018     hotspot[numhotspots] = Person::players[0]->coords;
1019
1020     float size;
1021     int type, shift;
1022     sscanf(args, "%f%d %n", &size, &type, &shift);
1023
1024     hotspotsize[numhotspots] = size;
1025     hotspottype[numhotspots] = type;
1026
1027     strcpy(hotspottext[numhotspots], args + shift);
1028     strcat(hotspottext[numhotspots], "\n");
1029
1030     numhotspots++;
1031 }
1032
1033 static void ch_dialogue(const char *args)
1034 {
1035     int dlg;
1036     char buf1[32], buf2[64];
1037
1038     sscanf(args, "%d %31s", &dlg, buf1);
1039     snprintf(buf2, 63, ":Data:Dialogues:%s.txt", buf1);
1040
1041     dialoguetype[numdialogues] = dlg;
1042
1043     memset(dialoguetext[numdialogues], 0, sizeof(dialoguetext[numdialogues]));
1044     memset(dialoguename[numdialogues], 0, sizeof(dialoguename[numdialogues]));
1045
1046     ifstream ipstream(ConvertFileName(buf2));
1047     ipstream.ignore(256, ':');
1048     ipstream >> numdialogueboxes[numdialogues];
1049     for (int i = 0; i < numdialogueboxes[numdialogues]; i++) {
1050         ipstream.ignore(256, ':');
1051         ipstream.ignore(256, ':');
1052         ipstream.ignore(256, ' ');
1053         ipstream >> dialogueboxlocation[numdialogues][i];
1054         ipstream.ignore(256, ':');
1055         ipstream >> dialogueboxcolor[numdialogues][i][0];
1056         ipstream >> dialogueboxcolor[numdialogues][i][1];
1057         ipstream >> dialogueboxcolor[numdialogues][i][2];
1058         ipstream.ignore(256, ':');
1059         ipstream.getline(dialoguename[numdialogues][i], 64);
1060         ipstream.ignore(256, ':');
1061         ipstream.ignore(256, ' ');
1062         ipstream.getline(dialoguetext[numdialogues][i], 128);
1063         for (int j = 0; j < 128; j++) {
1064             if (dialoguetext[numdialogues][i][j] == '\\')
1065                 dialoguetext[numdialogues][i][j] = '\n';
1066         }
1067         ipstream.ignore(256, ':');
1068         ipstream >> dialogueboxsound[numdialogues][i];
1069     }
1070
1071     for (int i = 0; i < numdialogueboxes[numdialogues]; i++) {
1072         for (int j = 0; j < Person::players.size(); j++) {
1073             participantfacing[numdialogues][i][j] = Person::players[j]->facing;
1074         }
1075     }
1076     ipstream.close();
1077
1078     directing = 1;
1079     indialogue = 0;
1080     whichdialogue = numdialogues;
1081
1082     numdialogues++;
1083 }
1084
1085 static void ch_fixdialogue(const char *args)
1086 {
1087     char buf1[32], buf2[64];
1088     int whichdi;
1089
1090     sscanf(args, "%d %31s", &whichdi, buf1);
1091     snprintf(buf2, 63, ":Data:Dialogues:%s.txt", buf1);
1092
1093     memset(dialoguetext[whichdi], 0, sizeof(dialoguetext[whichdi]));
1094     memset(dialoguename[whichdi], 0, sizeof(dialoguename[whichdi]));
1095
1096     ifstream ipstream(ConvertFileName(buf2));
1097     ipstream.ignore(256, ':');
1098     ipstream >> numdialogueboxes[whichdi];
1099     for (int i = 0; i < numdialogueboxes[whichdi]; i++) {
1100         ipstream.ignore(256, ':');
1101         ipstream.ignore(256, ':');
1102         ipstream.ignore(256, ' ');
1103         ipstream >> dialogueboxlocation[whichdi][i];
1104         ipstream.ignore(256, ':');
1105         ipstream >> dialogueboxcolor[whichdi][i][0];
1106         ipstream >> dialogueboxcolor[whichdi][i][1];
1107         ipstream >> dialogueboxcolor[whichdi][i][2];
1108         ipstream.ignore(256, ':');
1109         ipstream.getline(dialoguename[whichdi][i], 64);
1110         ipstream.ignore(256, ':');
1111         ipstream.ignore(256, ' ');
1112         ipstream.getline(dialoguetext[whichdi][i], 128);
1113         for (int j = 0; j < 128; j++) {
1114             if (dialoguetext[whichdi][i][j] == '\\')
1115                 dialoguetext[whichdi][i][j] = '\n';
1116         }
1117         ipstream.ignore(256, ':');
1118         ipstream >> dialogueboxsound[whichdi][i];
1119     }
1120
1121     ipstream.close();
1122 }
1123
1124 static void ch_fixtype(const char *args)
1125 {
1126     int dlg;
1127     sscanf(args, "%d", &dlg);
1128     dialoguetype[0] = dlg;
1129 }
1130
1131 static void ch_fixrotation(const char *args)
1132 {
1133     participantyaw[whichdialogue][participantfocus[whichdialogue][indialogue]] = Person::players[participantfocus[whichdialogue][indialogue]]->yaw;
1134 }
1135
1136 static void ch_ddialogue(const char *args)
1137 {
1138     if (numdialogues)
1139         numdialogues--;
1140 }
1141
1142 static void ch_dhs(const char *args)
1143 {
1144     if (numhotspots)
1145         numhotspots--;
1146 }
1147
1148 static void ch_immobile(const char *args)
1149 {
1150     Person::players[0]->immobile = 1;
1151 }
1152
1153 static void ch_allimmobile(const char *args)
1154 {
1155     for (int i = 1; i < Person::players.size(); i++)
1156         Person::players[i]->immobile = 1;
1157 }
1158
1159 static void ch_mobile(const char *args)
1160 {
1161     Person::players[0]->immobile = 0;
1162 }
1163
1164 static void ch_default(const char *args)
1165 {
1166     Person::players[0]->armorhead = 1;
1167     Person::players[0]->armorhigh = 1;
1168     Person::players[0]->armorlow = 1;
1169     Person::players[0]->protectionhead = 1;
1170     Person::players[0]->protectionhigh = 1;
1171     Person::players[0]->protectionlow = 1;
1172     Person::players[0]->metalhead = 1;
1173     Person::players[0]->metalhigh = 1;
1174     Person::players[0]->metallow = 1;
1175     Person::players[0]->power = 1;
1176     Person::players[0]->speedmult = 1;
1177     Person::players[0]->scale = 1;
1178
1179     if (Person::players[0]->creature == wolftype) {
1180         Person::players[0]->proportionhead = 1.1;
1181         Person::players[0]->proportionbody = 1.1;
1182         Person::players[0]->proportionarms = 1.1;
1183         Person::players[0]->proportionlegs = 1.1;
1184     } else if (Person::players[0]->creature == rabbittype) {
1185         Person::players[0]->proportionhead = 1.2;
1186         Person::players[0]->proportionbody = 1.05;
1187         Person::players[0]->proportionarms = 1.00;
1188         Person::players[0]->proportionlegs = 1.1;
1189         Person::players[0]->proportionlegs.y = 1.05;
1190     }
1191
1192     Person::players[0]->numclothes = 0;
1193     Person::players[0]->skeleton.drawmodel.textureptr.load(
1194         creatureskin[Person::players[0]->creature][Person::players[0]->whichskin], 1,
1195         &Person::players[0]->skeleton.skinText[0], &Person::players[0]->skeleton.skinsize);
1196
1197     editoractive = typeactive;
1198     Person::players[0]->immobile = 0;
1199 }
1200
1201 static void ch_play(const char *args)
1202 {
1203     int dlg;
1204     sscanf(args, "%d", &dlg);
1205     whichdialogue = dlg;
1206
1207     if (whichdialogue >= numdialogues)
1208         return;
1209
1210     for (int i = 0; i < numdialogueboxes[whichdialogue]; i++) {
1211         Person::players[participantfocus[whichdialogue][i]]->coords = participantlocation[whichdialogue][participantfocus[whichdialogue][i]];
1212         Person::players[participantfocus[whichdialogue][i]]->yaw = participantyaw[whichdialogue][participantfocus[whichdialogue][i]];
1213         Person::players[participantfocus[whichdialogue][i]]->targetyaw = participantyaw[whichdialogue][participantfocus[whichdialogue][i]];
1214         Person::players[participantfocus[whichdialogue][i]]->velocity = 0;
1215         Person::players[participantfocus[whichdialogue][i]]->animTarget = Person::players[participantfocus[whichdialogue][i]]->getIdle();
1216         Person::players[participantfocus[whichdialogue][i]]->frameTarget = 0;
1217     }
1218
1219     directing = 0;
1220     indialogue = 0;
1221
1222     playdialogueboxsound();
1223 }
1224
1225 static void ch_mapkilleveryone(const char *args)
1226 {
1227     maptype = mapkilleveryone;
1228 }
1229
1230 static void ch_mapkillmost(const char *args)
1231 {
1232     maptype = mapkillmost;
1233 }
1234
1235 static void ch_mapkillsomeone(const char *args)
1236 {
1237     maptype = mapkillsomeone;
1238 }
1239
1240 static void ch_mapgosomewhere(const char *args)
1241 {
1242     maptype = mapgosomewhere;
1243 }
1244
1245 static void ch_viewdistance(const char *args)
1246 {
1247     viewdistance = atof(args) * 100;
1248 }
1249
1250 static void ch_fadestart(const char *args)
1251 {
1252     fadestart = atof(args);
1253 }
1254
1255 static void ch_slomo(const char *args)
1256 {
1257     slomospeed = atof(args);
1258     slomo = !slomo;
1259     slomodelay = 1000;
1260 }
1261
1262 static void ch_slofreq(const char *args)
1263 {
1264     slomofreq = atof(args);
1265 }
1266
1267 static void ch_skytint(const char *args)
1268 {
1269     sscanf(args, "%f%f%f", &skyboxr, &skyboxg, &skyboxb);
1270
1271     skyboxlightr = skyboxr;
1272     skyboxlightg = skyboxg;
1273     skyboxlightb = skyboxb;
1274
1275     SetUpLighting();
1276
1277     terrain.DoShadows();
1278     objects.DoShadows();
1279 }
1280
1281 static void ch_skylight(const char *args)
1282 {
1283     sscanf(args, "%f%f%f", &skyboxlightr, &skyboxlightg, &skyboxlightb);
1284
1285     SetUpLighting();
1286
1287     terrain.DoShadows();
1288     objects.DoShadows();
1289 }
1290
1291 static void ch_skybox(const char *args)
1292 {
1293     skyboxtexture = !skyboxtexture;
1294
1295     SetUpLighting();
1296
1297     terrain.DoShadows();
1298     objects.DoShadows();
1299 }
1300
1301 static void cmd_dispatch(const string cmd)
1302 {
1303     int i, n_cmds = sizeof(cmd_names) / sizeof(cmd_names[0]);
1304
1305     for (i = 0; i < n_cmds; i++)
1306         if (cmd.substr(0, cmd.find(' ')) == string(cmd_names[i])) {
1307             cout << "|" << cmd.substr(cmd.find(' ') + 1) << "|" << endl;
1308             cmd_handlers[i](cmd.substr(cmd.find(' ') + 1).c_str());
1309             break;
1310         }
1311     emit_sound_np(i < n_cmds ? consolesuccesssound : consolefailsound);
1312 }
1313
1314 /********************> Tick() <*****/
1315 extern bool save_image(const char * fname);
1316 void Screenshot (void)
1317 {
1318     char temp[1024];
1319     time_t t = time(NULL);
1320     struct tm *tme = localtime(&t);
1321     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);
1322
1323 #if defined(_WIN32)
1324     mkdir("Screenshots");
1325 #else
1326     mkdir("Screenshots", S_IRWXU);
1327 #endif
1328
1329     save_image(temp);
1330 }
1331
1332 void Game::SetUpLighting()
1333 {
1334     if (environment == snowyenvironment)
1335         light.setColors(.65, .65, .7, .4, .4, .44);
1336     if (environment == desertenvironment)
1337         light.setColors(.95, .95, .95, .4, .35, .3);
1338     if (environment == grassyenvironment)
1339         light.setColors(.95, .95, 1, .4, .4, .44);
1340     if (!skyboxtexture)
1341         light.setColors(1, 1, 1, .4, .4, .4);
1342     float average;
1343     average = (skyboxlightr + skyboxlightg + skyboxlightb) / 3;
1344     light.color[0] *= (skyboxlightr + average) / 2;
1345     light.color[1] *= (skyboxlightg + average) / 2;
1346     light.color[2] *= (skyboxlightb + average) / 2;
1347     light.ambient[0] *= (skyboxlightr + average) / 2;
1348     light.ambient[1] *= (skyboxlightg + average) / 2;
1349     light.ambient[2] *= (skyboxlightb + average) / 2;
1350 }
1351
1352 int findPathDist(int start, int end)
1353 {
1354     int smallestcount, count, connected;
1355     int last, last2, last3, last4;
1356     int closest;
1357
1358     smallestcount = 1000;
1359     for (int i = 0; i < 50; i++) {
1360         count = 0;
1361         last = start;
1362         last2 = -1;
1363         last3 = -1;
1364         last4 = -1;
1365         while (last != end && count < 30) {
1366             closest = -1;
1367             for (int j = 0; j < numpathpoints; j++) {
1368                 if (j != last && j != last2 && j != last3 && j != last4) {
1369                     connected = 0;
1370                     if (numpathpointconnect[j])
1371                         for (int k = 0; k < numpathpointconnect[j]; k++) {
1372                             if (pathpointconnect[j][k] == last)connected = 1;
1373                         }
1374                     if (!connected)
1375                         if (numpathpointconnect[last])
1376                             for (int k = 0; k < numpathpointconnect[last]; k++) {
1377                                 if (pathpointconnect[last][k] == j)connected = 1;
1378                             }
1379                     if (connected)
1380                         if (closest == -1 || Random() % 2 == 0) {
1381                             closest = j;
1382                         }
1383                 }
1384             }
1385             last4 = last3;
1386             last3 = last2;
1387             last2 = last;
1388             last = closest;
1389             count++;
1390         }
1391         if (count < smallestcount)
1392             smallestcount = count;
1393     }
1394     return smallestcount;
1395 }
1396
1397 int Game::checkcollide(XYZ startpoint, XYZ endpoint)
1398 {
1399     static XYZ colpoint, colviewer, coltarget;
1400     static float minx, minz, maxx, maxz, miny, maxy;
1401
1402     minx = min(startpoint.x, endpoint.x) - 1;
1403     miny = min(startpoint.y, endpoint.y) - 1;
1404     minz = min(startpoint.z, endpoint.z) - 1;
1405     maxx = max(startpoint.x, endpoint.x) + 1;
1406     maxy = max(startpoint.y, endpoint.y) + 1;
1407     maxz = max(startpoint.z, endpoint.z) + 1;
1408
1409     for (int i = 0; i < objects.numobjects; i++) {
1410         if (     objects.position[i].x > minx - objects.model[i].boundingsphereradius &&
1411                  objects.position[i].x < maxx + objects.model[i].boundingsphereradius &&
1412                  objects.position[i].y > miny - objects.model[i].boundingsphereradius &&
1413                  objects.position[i].y < maxy + objects.model[i].boundingsphereradius &&
1414                  objects.position[i].z > minz - objects.model[i].boundingsphereradius &&
1415                  objects.position[i].z < maxz + objects.model[i].boundingsphereradius) {
1416             if (     objects.type[i] != treeleavestype &&
1417                      objects.type[i] != bushtype &&
1418                      objects.type[i] != firetype) {
1419                 colviewer = startpoint;
1420                 coltarget = endpoint;
1421                 if (objects.model[i].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
1422                     return i;
1423             }
1424         }
1425     }
1426
1427     //if(terrain.lineTerrain(startpoint,endpoint,&colpoint)!=-1)return 1000;
1428
1429     return -1;
1430 }
1431
1432 int Game::checkcollide(XYZ startpoint, XYZ endpoint, int what)
1433 {
1434     static XYZ colpoint, colviewer, coltarget;
1435     static float minx, minz, maxx, maxz, miny, maxy;
1436     static int i; //FIXME: see below
1437
1438     minx = min(startpoint.x, endpoint.x) - 1;
1439     miny = min(startpoint.y, endpoint.y) - 1;
1440     minz = min(startpoint.z, endpoint.z) - 1;
1441     maxx = max(startpoint.x, endpoint.x) + 1;
1442     maxy = max(startpoint.y, endpoint.y) + 1;
1443     maxz = max(startpoint.z, endpoint.z) + 1;
1444
1445     if (what != 1000) {
1446         if (     objects.position[what].x > minx - objects.model[what].boundingsphereradius &&
1447                  objects.position[what].x < maxx + objects.model[what].boundingsphereradius &&
1448                  objects.position[what].y > miny - objects.model[what].boundingsphereradius &&
1449                  objects.position[what].y < maxy + objects.model[what].boundingsphereradius &&
1450                  objects.position[what].z > minz - objects.model[what].boundingsphereradius &&
1451                  objects.position[what].z < maxz + objects.model[what].boundingsphereradius) {
1452             if (     objects.type[what] != treeleavestype &&
1453                      objects.type[what] != bushtype &&
1454                      objects.type[what] != firetype) {
1455                 colviewer = startpoint;
1456                 coltarget = endpoint;
1457                 //FIXME: i/what
1458                 if (objects.model[what].LineCheck(&colviewer, &coltarget, &colpoint, &objects.position[what], &objects.yaw[what]) != -1)
1459                     return i;
1460             }
1461         }
1462     }
1463
1464     if (what == 1000)
1465         if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1)
1466             return 1000;
1467
1468     return -1;
1469 }
1470
1471 void Setenvironment(int which)
1472 {
1473     LOGFUNC;
1474
1475     LOG(" Setting environment...");
1476
1477     float temptexdetail;
1478     environment = which;
1479
1480     pause_sound(stream_snowtheme);
1481     pause_sound(stream_grasstheme);
1482     pause_sound(stream_deserttheme);
1483     pause_sound(stream_wind);
1484     pause_sound(stream_desertambient);
1485
1486
1487     if (environment == snowyenvironment) {
1488         windvector = 0;
1489         windvector.z = 3;
1490         if (ambientsound)
1491             emit_stream_np(stream_wind);
1492
1493         objects.treetextureptr.load(":Data:Textures:snowtree.png", 0, 1);
1494         objects.bushtextureptr.load(":Data:Textures:bushsnow.png", 0, 1);
1495         objects.rocktextureptr.load(":Data:Textures:bouldersnow.jpg", 1, 0);
1496         objects.boxtextureptr.load(":Data:Textures:snowbox.jpg", 1, 0);
1497
1498         footstepsound = footstepsn1;
1499         footstepsound2 = footstepsn2;
1500         footstepsound3 = footstepst1;
1501         footstepsound4 = footstepst2;
1502
1503         terraintexture.load(":Data:Textures:snow.jpg", 1, 0);
1504         terraintexture2.load(":Data:Textures:rock.jpg", 1, 0);
1505
1506         //LoadTexture(":Data:Textures:detailgrain.png",&terraintexture3,1);
1507
1508
1509
1510
1511         temptexdetail = texdetail;
1512         if (texdetail > 1)
1513             texdetail = 4;
1514         skybox->load(   ":Data:Textures:Skybox(snow):Front.jpg",
1515                         ":Data:Textures:Skybox(snow):Left.jpg",
1516                         ":Data:Textures:Skybox(snow):Back.jpg",
1517                         ":Data:Textures:Skybox(snow):Right.jpg",
1518                         ":Data:Textures:Skybox(snow):Up.jpg",
1519                         ":Data:Textures:Skybox(snow):Down.jpg");
1520
1521
1522
1523
1524         texdetail = temptexdetail;
1525     } else if (environment == desertenvironment) {
1526         windvector = 0;
1527         windvector.z = 2;
1528         objects.treetextureptr.load(":Data:Textures:deserttree.png", 0, 1);
1529         objects.bushtextureptr.load(":Data:Textures:bushdesert.png", 0, 1);
1530         objects.rocktextureptr.load(":Data:Textures:boulderdesert.jpg", 1, 0);
1531         objects.boxtextureptr.load(":Data:Textures:desertbox.jpg", 1, 0);
1532
1533
1534         if (ambientsound)
1535             emit_stream_np(stream_desertambient);
1536
1537         footstepsound = footstepsn1;
1538         footstepsound2 = footstepsn2;
1539         footstepsound3 = footstepsn1;
1540         footstepsound4 = footstepsn2;
1541
1542         terraintexture.load(":Data:Textures:sand.jpg", 1, 0);
1543         terraintexture2.load(":Data:Textures:sandslope.jpg", 1, 0);
1544
1545         //LoadTexture(":Data:Textures:detailgrain.png",&terraintexture3,1);
1546
1547
1548
1549         temptexdetail = texdetail;
1550         if (texdetail > 1)
1551             texdetail = 4;
1552         skybox->load(   ":Data:Textures:Skybox(sand):Front.jpg",
1553                         ":Data:Textures:Skybox(sand):Left.jpg",
1554                         ":Data:Textures:Skybox(sand):Back.jpg",
1555                         ":Data:Textures:Skybox(sand):Right.jpg",
1556                         ":Data:Textures:Skybox(sand):Up.jpg",
1557                         ":Data:Textures:Skybox(sand):Down.jpg");
1558
1559
1560
1561
1562         texdetail = temptexdetail;
1563     } else if (environment == grassyenvironment) {
1564         windvector = 0;
1565         windvector.z = 2;
1566         objects.treetextureptr.load(":Data:Textures:tree.png", 0, 1);
1567         objects.bushtextureptr.load(":Data:Textures:bush.png", 0, 1);
1568         objects.rocktextureptr.load(":Data:Textures:boulder.jpg", 1, 0);
1569         objects.boxtextureptr.load(":Data:Textures:grassbox.jpg", 1, 0);
1570
1571         if (ambientsound)
1572             emit_stream_np(stream_wind, 100.);
1573
1574         footstepsound = footstepgr1;
1575         footstepsound2 = footstepgr2;
1576         footstepsound3 = footstepst1;
1577         footstepsound4 = footstepst2;
1578
1579         terraintexture.load(":Data:Textures:grassdirt.jpg", 1, 0);
1580         terraintexture2.load(":Data:Textures:mossrock.jpg", 1, 0);
1581
1582         //LoadTexture(":Data:Textures:detail.png",&terraintexture3,1);
1583
1584
1585
1586         temptexdetail = texdetail;
1587         if (texdetail > 1)
1588             texdetail = 4;
1589         skybox->load(   ":Data:Textures:Skybox(grass):Front.jpg",
1590                         ":Data:Textures:Skybox(grass):Left.jpg",
1591                         ":Data:Textures:Skybox(grass):Back.jpg",
1592                         ":Data:Textures:Skybox(grass):Right.jpg",
1593                         ":Data:Textures:Skybox(grass):Up.jpg",
1594                         ":Data:Textures:Skybox(grass):Down.jpg");
1595
1596
1597
1598         texdetail = temptexdetail;
1599     }
1600     temptexdetail = texdetail;
1601     texdetail = 1;
1602     terrain.load(":Data:Textures:heightmap.png");
1603
1604     texdetail = temptexdetail;
1605 }
1606
1607 void LoadCampaign()
1608 {
1609     if (!accountactive)
1610         return;
1611     ifstream ipstream(ConvertFileName((":Data:Campaigns:" + accountactive->getCurrentCampaign() + ".txt").c_str()));
1612     if (!ipstream.good()) {
1613         if (accountactive->getCurrentCampaign() == "main") {
1614             cerr << "Could not found main campaign!" << endl;
1615             return;
1616         }
1617         cerr << "Could not found campaign \"" << accountactive->getCurrentCampaign() << "\", falling back to main." << endl;
1618         accountactive->setCurrentCampaign("main");
1619         return LoadCampaign();
1620     }
1621     ipstream.ignore(256, ':');
1622     int numlevels;
1623     ipstream >> numlevels;
1624     campaignlevels.clear();
1625     for (int i = 0; i < numlevels; i++) {
1626         CampaignLevel cl;
1627         ipstream >> cl;
1628         campaignlevels.push_back(cl);
1629     }
1630     ipstream.close();
1631
1632     ifstream test(ConvertFileName((":Data:Textures:" + accountactive->getCurrentCampaign() + ":World.png").c_str()));
1633     if (test.good()) {
1634         Mainmenuitems[7].load((":Data:Textures:" + accountactive->getCurrentCampaign() + ":World.png").c_str(), 0, 0);
1635     } else {
1636         Mainmenuitems[7].load(":Data:Textures:World.png", 0, 0);
1637     }
1638
1639     if (accountactive->getCampaignChoicesMade() == 0) {
1640         accountactive->setCampaignScore(0);
1641         accountactive->resetFasttime();
1642     }
1643 }
1644
1645 vector<string> ListCampaigns()
1646 {
1647     DIR *campaigns = opendir(ConvertFileName(":Data:Campaigns"));
1648     struct dirent *campaign = NULL;
1649     if (!campaigns) {
1650         perror("Problem while loading campaigns");
1651         cerr << "campaign folder was : " << ConvertFileName(":Data:Campaigns") << endl;
1652         exit(EXIT_FAILURE);
1653     }
1654     vector<string> campaignNames;
1655     while ((campaign = readdir(campaigns)) != NULL) {
1656         string name(campaign->d_name);
1657         if (name.length() < 5)
1658             continue;
1659         if (!name.compare(name.length() - 4, 4, ".txt")) {
1660             campaignNames.push_back(name.substr(0, name.length() - 4));
1661         }
1662     }
1663     closedir(campaigns);
1664     return campaignNames;
1665 }
1666
1667 void Loadlevel(int which)
1668 {
1669     stealthloading = 0;
1670     whichlevel = which;
1671
1672     if (which == -1) {
1673         tutoriallevel = -1;
1674         Loadlevel("tutorial");
1675     } else if (which >= 0 && which <= 15) {
1676         char buf[32];
1677         snprintf(buf, 32, "map%d", which + 1); // challenges
1678         Loadlevel(buf);
1679     } else
1680         Loadlevel("mapsave");
1681 }
1682
1683 void Loadlevel(const char *name)
1684 {
1685     int templength;
1686     float lamefloat;
1687     static const char *pfx = ":Data:Maps:";
1688     char *buf;
1689
1690     float headprop, legprop, armprop, bodyprop;
1691
1692     LOGFUNC;
1693
1694     LOG(std::string("Loading level...") + name);
1695
1696     if (!gameon)
1697         visibleloading = 1;
1698     if (stealthloading)
1699         visibleloading = 0;
1700     if (!stillloading)
1701         loadtime = 0;
1702     gamestarted = 1;
1703
1704     numenvsounds = 0;
1705
1706     if (tutoriallevel != -1)
1707         tutoriallevel = 0;
1708     else
1709         tutoriallevel = 1;
1710
1711     if (tutoriallevel == 1)
1712         tutorialstage = 0;
1713     if (tutorialstage == 0) {
1714         tutorialstagetime = 0;
1715         tutorialmaxtime = 1;
1716     }
1717     loadingstuff = 1;
1718     pause_sound(whooshsound);
1719     pause_sound(stream_firesound);
1720
1721     // Change the map filename into something that is os specific
1722     buf = (char*) alloca(strlen(pfx) + strlen(name) + 1);
1723     sprintf(buf, "%s%s", pfx, name);
1724     const char *FixedFN = ConvertFileName(buf);
1725
1726     int mapvers;
1727     FILE *tfile;
1728     //~ char* buff=getcwd(NULL,0);
1729     //~ cout << buff << " " << FixedFN << endl;
1730     //~ free(buff);
1731     tfile = fopen( FixedFN, "rb" );
1732     if (tfile) {
1733         pause_sound(stream_firesound);
1734         scoreadded = 0;
1735         windialogue = false;
1736         hostiletime = 0;
1737         won = 0;
1738
1739         animation[bounceidleanim].Load((char *)"Idle", middleheight, neutral);
1740
1741         numdialogues = 0;
1742
1743         for (int i = 0; i < 20; i++)
1744             dialoguegonethrough[i] = 0;
1745
1746         indialogue = -1;
1747         cameramode = 0;
1748
1749         damagedealt = 0;
1750         damagetaken = 0;
1751
1752         if (accountactive)
1753             difficulty = accountactive->getDifficulty();
1754
1755         numhotspots = 0;
1756         currenthotspot = -1;
1757         bonustime = 1;
1758
1759         skyboxtexture = 1;
1760         skyboxr = 1;
1761         skyboxg = 1;
1762         skyboxb = 1;
1763
1764         freeze = 0;
1765         winfreeze = 0;
1766
1767         for (int i = 0; i < 100; i++)
1768             bonusnum[i] = 0;
1769
1770         numfalls = 0;
1771         numflipfail = 0;
1772         numseen = 0;
1773         numstaffattack = 0;
1774         numswordattack = 0;
1775         numknifeattack = 0;
1776         numunarmedattack = 0;
1777         numescaped = 0;
1778         numflipped = 0;
1779         numwallflipped = 0;
1780         numthrowkill = 0;
1781         numafterkill = 0;
1782         numreversals = 0;
1783         numattacks = 0;
1784         maxalarmed = 0;
1785         numresponded = 0;
1786
1787         bonustotal = startbonustotal;
1788         bonus = 0;
1789         gameon = 1;
1790         changedelay = 0;
1791         if (console) {
1792             emit_sound_np(consolesuccesssound);
1793             freeze = 0;
1794             console = false;
1795         }
1796
1797         if (!stealthloading) {
1798             terrain.numdecals = 0;
1799             Sprite::deleteSprites();
1800             for (int i = 0; i < objects.numobjects; i++)
1801                 objects.model[i].numdecals = 0;
1802
1803             int j = objects.numobjects;
1804             for (int i = 0; i < j; i++) {
1805                 objects.DeleteObject(0);
1806                 if (visibleloading)
1807                     LoadingScreen();
1808             }
1809
1810             for (int i = 0; i < subdivision; i++)
1811                 for (int j = 0; j < subdivision; j++)
1812                     terrain.patchobjectnum[i][j] = 0;
1813             if (visibleloading)
1814                 LoadingScreen();
1815         }
1816
1817         weapons.clear();
1818
1819         funpackf(tfile, "Bi", &mapvers);
1820         if (mapvers >= 15)
1821             funpackf(tfile, "Bi", &indemo);
1822         else
1823             indemo = 0;
1824         if (mapvers >= 5)
1825             funpackf(tfile, "Bi", &maptype);
1826         else
1827             maptype = mapkilleveryone;
1828         if (mapvers >= 6)
1829             funpackf(tfile, "Bi", &hostile);
1830         else
1831             hostile = 1;
1832         if (mapvers >= 4)
1833             funpackf(tfile, "Bf Bf", &viewdistance, &fadestart);
1834         else {
1835             viewdistance = 100;
1836             fadestart = .6;
1837         }
1838         if (mapvers >= 2)
1839             funpackf(tfile, "Bb Bf Bf Bf", &skyboxtexture, &skyboxr, &skyboxg, &skyboxb);
1840         else {
1841             skyboxtexture = 1;
1842             skyboxr = 1;
1843             skyboxg = 1;
1844             skyboxb = 1;
1845         }
1846         if (mapvers >= 10)
1847             funpackf(tfile, "Bf Bf Bf", &skyboxlightr, &skyboxlightg, &skyboxlightb);
1848         else {
1849             skyboxlightr = skyboxr;
1850             skyboxlightg = skyboxg;
1851             skyboxlightb = skyboxb;
1852         }
1853         if (!stealthloading)
1854             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);
1855         if (stealthloading)
1856             funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &lamefloat, &lamefloat, &lamefloat, &lamefloat, &lamefloat, &Person::players[0]->num_weapons);
1857         Person::players[0]->originalcoords = Person::players[0]->coords;
1858         if (Person::players[0]->num_weapons > 0 && Person::players[0]->num_weapons < 5)
1859             for (int j = 0; j < Person::players[0]->num_weapons; j++) {
1860                 Person::players[0]->weaponids[j] = weapons.size();
1861                 int type;
1862                 funpackf(tfile, "Bi", &type);
1863                 weapons.push_back(Weapon(type, 0));
1864             }
1865
1866         if (visibleloading)
1867             LoadingScreen();
1868
1869         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->armorhead, &Person::players[0]->armorhigh, &Person::players[0]->armorlow);
1870         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->protectionhead, &Person::players[0]->protectionhigh, &Person::players[0]->protectionlow);
1871         funpackf(tfile, "Bf Bf Bf", &Person::players[0]->metalhead, &Person::players[0]->metalhigh, &Person::players[0]->metallow);
1872         funpackf(tfile, "Bf Bf", &Person::players[0]->power, &Person::players[0]->speedmult);
1873
1874         funpackf(tfile, "Bi", &Person::players[0]->numclothes);
1875
1876         if (mapvers >= 9)
1877             funpackf(tfile, "Bi Bi", &Person::players[0]->whichskin, &Person::players[0]->creature);
1878         else {
1879             Person::players[0]->whichskin = 0;
1880             Person::players[0]->creature = rabbittype;
1881         }
1882
1883         Person::players[0]->lastattack = -1;
1884         Person::players[0]->lastattack2 = -1;
1885         Person::players[0]->lastattack3 = -1;
1886
1887         //dialogues
1888         if (mapvers >= 8) {
1889             funpackf(tfile, "Bi", &numdialogues);
1890             for (int k = 0; k < numdialogues; k++) {
1891                 funpackf(tfile, "Bi", &numdialogueboxes[k]);
1892                 funpackf(tfile, "Bi", &dialoguetype[k]);
1893                 for (int l = 0; l < 10; l++) {
1894                     funpackf(tfile, "Bf Bf Bf", &participantlocation[k][l].x, &participantlocation[k][l].y, &participantlocation[k][l].z);
1895                     funpackf(tfile, "Bf", &participantyaw[k][l]);
1896                 }
1897                 for (int l = 0; l < numdialogueboxes[k]; l++) {
1898                     funpackf(tfile, "Bi", &dialogueboxlocation[k][l]);
1899                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][0]);
1900                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][1]);
1901                     funpackf(tfile, "Bf", &dialogueboxcolor[k][l][2]);
1902                     funpackf(tfile, "Bi", &dialogueboxsound[k][l]);
1903
1904                     funpackf(tfile, "Bi", &templength);
1905                     if (templength > 128 || templength <= 0)
1906                         templength = 128;
1907                     int m;
1908                     for (m = 0; m < templength; m++) {
1909                         funpackf(tfile, "Bb", &dialoguetext[k][l][m]);
1910                         if (dialoguetext[k][l][m] == '\0')
1911                             break;
1912                     }
1913                     dialoguetext[k][l][m] = 0;
1914
1915                     funpackf(tfile, "Bi", &templength);
1916                     if (templength > 64 || templength <= 0)
1917                         templength = 64;
1918                     for (m = 0; m < templength; m++) {
1919                         funpackf(tfile, "Bb", &dialoguename[k][l][m]);
1920                         if (dialoguename[k][l][m] == '\0')
1921                             break;
1922                     }
1923                     dialoguename[k][l][m] = 0;
1924                     funpackf(tfile, "Bf Bf Bf", &dialoguecamera[k][l].x, &dialoguecamera[k][l].y, &dialoguecamera[k][l].z);
1925                     funpackf(tfile, "Bi", &participantfocus[k][l]);
1926                     funpackf(tfile, "Bi", &participantaction[k][l]);
1927
1928                     for (m = 0; m < 10; m++)
1929                         funpackf(tfile, "Bf Bf Bf", &participantfacing[k][l][m].x, &participantfacing[k][l][m].y, &participantfacing[k][l][m].z);
1930
1931                     funpackf(tfile, "Bf Bf", &dialoguecamerayaw[k][l], &dialoguecamerapitch[k][l]);
1932                 }
1933             }
1934         } else
1935             numdialogues = 0;
1936
1937         for (int k = 0; k < Person::players[0]->numclothes; k++) {
1938             funpackf(tfile, "Bi", &templength);
1939             for (int l = 0; l < templength; l++)
1940                 funpackf(tfile, "Bb", &Person::players[0]->clothes[k][l]);
1941             Person::players[0]->clothes[k][templength] = '\0';
1942             funpackf(tfile, "Bf Bf Bf", &Person::players[0]->clothestintr[k], &Person::players[0]->clothestintg[k], &Person::players[0]->clothestintb[k]);
1943         }
1944
1945         funpackf(tfile, "Bi", &environment);
1946
1947         funpackf(tfile, "Bi", &objects.numobjects);
1948         for (int i = 0; i < objects.numobjects; i++) {
1949             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]);
1950             if (objects.type[i] == treeleavestype)
1951                 objects.scale[i] = objects.scale[i - 1];
1952         }
1953
1954         if (mapvers >= 7) {
1955             funpackf(tfile, "Bi", &numhotspots);
1956             for (int i = 0; i < numhotspots; i++) {
1957                 funpackf(tfile, "Bi Bf Bf Bf Bf", &hotspottype[i], &hotspotsize[i], &hotspot[i].x, &hotspot[i].y, &hotspot[i].z);
1958                 funpackf(tfile, "Bi", &templength);
1959                 if (templength)
1960                     for (int l = 0; l < templength; l++)
1961                         funpackf(tfile, "Bb", &hotspottext[i][l]);
1962                 hotspottext[i][templength] = '\0';
1963                 if (hotspottype[i] == -111)
1964                     indemo = 1;
1965             }
1966         } else
1967             numhotspots = 0;
1968
1969         if (visibleloading)
1970             LoadingScreen();
1971
1972         if (!stealthloading) {
1973             objects.center = 0;
1974             for (int i = 0; i < objects.numobjects; i++)
1975                 objects.center += objects.position[i];
1976             objects.center /= objects.numobjects;
1977
1978
1979             if (visibleloading)
1980                 LoadingScreen();
1981
1982             float maxdistance = 0;
1983             float tempdist;
1984             //~ int whichclosest;
1985             for (int i = 0; i < objects.numobjects; i++) {
1986                 tempdist = distsq(&objects.center, &objects.position[i]);
1987                 if (tempdist > maxdistance) {
1988                     //~ whichclosest=i;
1989                     maxdistance = tempdist;
1990                 }
1991             }
1992             objects.radius = fast_sqrt(maxdistance);
1993         }
1994
1995         if (visibleloading)
1996             LoadingScreen();
1997
1998         int numplayers;
1999         funpackf(tfile, "Bi", &numplayers);
2000         int howmanyremoved = 0;
2001         bool removeanother = 0;
2002         if (numplayers > maxplayers) {
2003             cout << "Warning: this level contains more players than allowed" << endl;
2004         }
2005         if (numplayers > 1) {
2006             for (int i = 1; i < numplayers; i++) {
2007                 Person::players.push_back(shared_ptr<Person>(new Person()));
2008                 if (visibleloading)
2009                     LoadingScreen();
2010                 removeanother = 0;
2011
2012                 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);
2013                 if (mapvers >= 5)
2014                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->howactive);
2015                 else
2016                     Person::players[i - howmanyremoved]->howactive = typeactive;
2017                 if (mapvers >= 3)
2018                     funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->scale);
2019                 else
2020                     Person::players[i - howmanyremoved]->scale = -1;
2021                 if (mapvers >= 11)
2022                     funpackf(tfile, "Bb", &Person::players[i - howmanyremoved]->immobile);
2023                 else
2024                     Person::players[i - howmanyremoved]->immobile = 0;
2025                 if (mapvers >= 12)
2026                     funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->yaw);
2027                 else
2028                     Person::players[i - howmanyremoved]->yaw = 0;
2029                 Person::players[i - howmanyremoved]->targetyaw = Person::players[i - howmanyremoved]->yaw;
2030                 if (Person::players[i - howmanyremoved]->num_weapons < 0 || Person::players[i - howmanyremoved]->num_weapons > 5) {
2031                     removeanother = 1;
2032                     howmanyremoved++;
2033                 }
2034                 if (!removeanother) {
2035                     if (Person::players[i - howmanyremoved]->num_weapons > 0 && Person::players[i - howmanyremoved]->num_weapons < 5) {
2036                         for (int j = 0; j < Person::players[i - howmanyremoved]->num_weapons; j++) {
2037                             Person::players[i - howmanyremoved]->weaponids[j] = weapons.size();
2038                             int type;
2039                             funpackf(tfile, "Bi", &type);
2040                             weapons.push_back(Weapon(type, i));
2041                         }
2042                     }
2043                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->numwaypoints);
2044                     //Person::players[i-howmanyremoved]->numwaypoints=10;
2045                     for (int j = 0; j < Person::players[i - howmanyremoved]->numwaypoints; j++) {
2046                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].x);
2047                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].y);
2048                         funpackf(tfile, "Bf", &Person::players[i - howmanyremoved]->waypoints[j].z);
2049                         if (mapvers >= 5)
2050                             funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->waypointtype[j]);
2051                         else
2052                             Person::players[i - howmanyremoved]->waypointtype[j] = wpkeepwalking;
2053                     }
2054
2055                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->waypoint);
2056                     if (Person::players[i - howmanyremoved]->waypoint > Person::players[i - howmanyremoved]->numwaypoints - 1)
2057                         Person::players[i - howmanyremoved]->waypoint = 0;
2058
2059                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->armorhead, &Person::players[i - howmanyremoved]->armorhigh, &Person::players[i - howmanyremoved]->armorlow);
2060                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->protectionhead, &Person::players[i - howmanyremoved]->protectionhigh, &Person::players[i - howmanyremoved]->protectionlow);
2061                     funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->metalhead, &Person::players[i - howmanyremoved]->metalhigh, &Person::players[i - howmanyremoved]->metallow);
2062                     funpackf(tfile, "Bf Bf", &Person::players[i - howmanyremoved]->power, &Person::players[i - howmanyremoved]->speedmult);
2063
2064                     if (mapvers >= 4)
2065                         funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
2066                     else {
2067                         headprop = 1;
2068                         bodyprop = 1;
2069                         armprop = 1;
2070                         legprop = 1;
2071                     }
2072                     if (Person::players[i - howmanyremoved]->creature == wolftype) {
2073                         Person::players[i - howmanyremoved]->proportionhead = 1.1 * headprop;
2074                         Person::players[i - howmanyremoved]->proportionbody = 1.1 * bodyprop;
2075                         Person::players[i - howmanyremoved]->proportionarms = 1.1 * armprop;
2076                         Person::players[i - howmanyremoved]->proportionlegs = 1.1 * legprop;
2077                     }
2078
2079                     if (Person::players[i - howmanyremoved]->creature == rabbittype) {
2080                         Person::players[i - howmanyremoved]->proportionhead = 1.2 * headprop;
2081                         Person::players[i - howmanyremoved]->proportionbody = 1.05 * bodyprop;
2082                         Person::players[i - howmanyremoved]->proportionarms = 1.00 * armprop;
2083                         Person::players[i - howmanyremoved]->proportionlegs = 1.1 * legprop;
2084                         Person::players[i - howmanyremoved]->proportionlegs.y = 1.05 * legprop;
2085                     }
2086
2087                     funpackf(tfile, "Bi", &Person::players[i - howmanyremoved]->numclothes);
2088                     if (Person::players[i - howmanyremoved]->numclothes) {
2089                         for (int k = 0; k < Person::players[i - howmanyremoved]->numclothes; k++) {
2090                             int templength;
2091                             funpackf(tfile, "Bi", &templength);
2092                             for (int l = 0; l < templength; l++)
2093                                 funpackf(tfile, "Bb", &Person::players[i - howmanyremoved]->clothes[k][l]);
2094                             Person::players[i - howmanyremoved]->clothes[k][templength] = '\0';
2095                             funpackf(tfile, "Bf Bf Bf", &Person::players[i - howmanyremoved]->clothestintr[k], &Person::players[i - howmanyremoved]->clothestintg[k], &Person::players[i - howmanyremoved]->clothestintb[k]);
2096                         }
2097                     }
2098                 }
2099             }
2100         }
2101         if (visibleloading)
2102             LoadingScreen();
2103
2104         numplayers -= howmanyremoved;
2105         Person::players.resize(numplayers);
2106
2107         funpackf(tfile, "Bi", &numpathpoints);
2108         if (numpathpoints > 30 || numpathpoints < 0)
2109             numpathpoints = 0;
2110         for (int j = 0; j < numpathpoints; j++) {
2111             funpackf(tfile, "Bf Bf Bf Bi", &pathpoint[j].x, &pathpoint[j].y, &pathpoint[j].z, &numpathpointconnect[j]);
2112             for (int k = 0; k < numpathpointconnect[j]; k++) {
2113                 funpackf(tfile, "Bi", &pathpointconnect[j][k]);
2114             }
2115         }
2116         if (visibleloading)
2117             LoadingScreen();
2118
2119         funpackf(tfile, "Bf Bf Bf Bf", &mapcenter.x, &mapcenter.y, &mapcenter.z, &mapradius);
2120
2121         SetUpLighting();
2122         if (environment != oldenvironment)
2123             Setenvironment(environment);
2124         oldenvironment = environment;
2125
2126         if (!stealthloading) {
2127             int j = objects.numobjects;
2128             objects.numobjects = 0;
2129             for (int i = 0; i < j; i++) {
2130                 objects.MakeObject(objects.type[i], objects.position[i], objects.yaw[i], objects.pitch[i], objects.scale[i]);
2131                 if (visibleloading)
2132                     LoadingScreen();
2133             }
2134
2135             terrain.DoShadows();
2136             if (visibleloading)
2137                 LoadingScreen();
2138             objects.DoShadows();
2139             if (visibleloading)
2140                 LoadingScreen();
2141         }
2142
2143         fclose(tfile);
2144
2145         for (int i = 0; i < Person::players.size(); i++) {
2146             if (visibleloading)
2147                 LoadingScreen();
2148             Person::players[i]->burnt = 0;
2149             Person::players[i]->bled = 0;
2150             Person::players[i]->onfire = 0;
2151             if (i == 0 || Person::players[i]->scale < 0)
2152                 Person::players[i]->scale = .2;
2153             Person::players[i]->skeleton.free = 0;
2154             Person::players[i]->skeleton.id = i;
2155             if (i == 0 && mapvers < 9)
2156                 Person::players[i]->creature = rabbittype;
2157             if (Person::players[i]->creature != wolftype) {
2158                 Person::players[i]->skeleton.Load(
2159                     (char *)":Data:Skeleton:Basic Figure",
2160                     (char *)":Data:Skeleton:Basic Figurelow",
2161                     (char *)":Data:Skeleton:Rabbitbelt",
2162                     (char *)":Data:Models:Body.solid",
2163                     (char *)":Data:Models:Body2.solid",
2164                     (char *)":Data:Models:Body3.solid",
2165                     (char *)":Data:Models:Body4.solid",
2166                     (char *)":Data:Models:Body5.solid",
2167                     (char *)":Data:Models:Body6.solid",
2168                     (char *)":Data:Models:Body7.solid",
2169                     (char *)":Data:Models:Bodylow.solid",
2170                     (char *)":Data:Models:Belt.solid", 0);
2171             } else {
2172                 if (Person::players[i]->creature != wolftype) {
2173                     Person::players[i]->skeleton.Load(
2174                         (char *)":Data:Skeleton:Basic Figure",
2175                         (char *)":Data:Skeleton:Basic Figurelow",
2176                         (char *)":Data:Skeleton:Rabbitbelt",
2177                         (char *)":Data:Models:Body.solid",
2178                         (char *)":Data:Models:Body2.solid",
2179                         (char *)":Data:Models:Body3.solid",
2180                         (char *)":Data:Models:Body4.solid",
2181                         (char *)":Data:Models:Body5.solid",
2182                         (char *)":Data:Models:Body6.solid",
2183                         (char *)":Data:Models:Body7.solid",
2184                         (char *)":Data:Models:Bodylow.solid",
2185                         (char *)":Data:Models:Belt.solid", 1);
2186                     Person::players[i]->skeleton.drawmodelclothes.textureptr.load(":Data:Textures:Belt.png", 1, 1);
2187                 }
2188                 if (Person::players[i]->creature == wolftype) {
2189                     Person::players[i]->skeleton.Load(
2190                         (char *)":Data:Skeleton:Basic Figure Wolf",
2191                         (char *)":Data:Skeleton:Basic Figure Wolf Low",
2192                         (char *)":Data:Skeleton:Rabbitbelt",
2193                         (char *)":Data:Models:Wolf.solid",
2194                         (char *)":Data:Models:Wolf2.solid",
2195                         (char *)":Data:Models:Wolf3.solid",
2196                         (char *)":Data:Models:Wolf4.solid",
2197                         (char *)":Data:Models:Wolf5.solid",
2198                         (char *)":Data:Models:Wolf6.solid",
2199                         (char *)":Data:Models:Wolf7.solid",
2200                         (char *)":Data:Models:Wolflow.solid",
2201                         (char *)":Data:Models:Belt.solid", 0);
2202                 }
2203             }
2204
2205             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);
2206
2207             if (Person::players[i]->numclothes) {
2208                 for (int j = 0; j < Person::players[i]->numclothes; j++) {
2209                     tintr = Person::players[i]->clothestintr[j];
2210                     tintg = Person::players[i]->clothestintg[j];
2211                     tintb = Person::players[i]->clothestintb[j];
2212                     AddClothes((char *)Person::players[i]->clothes[j], &Person::players[i]->skeleton.skinText[0]);
2213                 }
2214                 Person::players[i]->DoMipmaps();
2215             }
2216
2217             Person::players[i]->animCurrent = bounceidleanim;
2218             Person::players[i]->animTarget = bounceidleanim;
2219             Person::players[i]->frameCurrent = 0;
2220             Person::players[i]->frameTarget = 1;
2221             Person::players[i]->target = 0;
2222             Person::players[i]->speed = 1 + (float)(Random() % 100) / 1000;
2223             if (difficulty == 0)
2224                 Person::players[i]->speed -= .2;
2225             if (difficulty == 1)
2226                 Person::players[i]->speed -= .1;
2227
2228             Person::players[i]->velocity = 0;
2229             Person::players[i]->oldcoords = Person::players[i]->coords;
2230             Person::players[i]->realoldcoords = Person::players[i]->coords;
2231
2232             Person::players[i]->id = i;
2233             Person::players[i]->skeleton.id = i;
2234             Person::players[i]->updatedelay = 0;
2235             Person::players[i]->normalsupdatedelay = 0;
2236
2237             Person::players[i]->aitype = passivetype;
2238             Person::players[i]->madskills = 0;
2239
2240             if (i == 0) {
2241                 Person::players[i]->proportionhead = 1.2;
2242                 Person::players[i]->proportionbody = 1.05;
2243                 Person::players[i]->proportionarms = 1.00;
2244                 Person::players[i]->proportionlegs = 1.1;
2245                 Person::players[i]->proportionlegs.y = 1.05;
2246             }
2247             Person::players[i]->headless = 0;
2248             Person::players[i]->currentoffset = 0;
2249             Person::players[i]->targetoffset = 0;
2250
2251             Person::players[i]->damagetolerance = 200;
2252
2253             if (Person::players[i]->creature == wolftype) {
2254                 if (i == 0 || Person::players[i]->scale < 0)
2255                     Person::players[i]->scale = .23;
2256                 Person::players[i]->damagetolerance = 300;
2257             }
2258
2259             if (visibleloading)
2260                 LoadingScreen();
2261             if (cellophane) {
2262                 Person::players[i]->proportionhead.z = 0;
2263                 Person::players[i]->proportionbody.z = 0;
2264                 Person::players[i]->proportionarms.z = 0;
2265                 Person::players[i]->proportionlegs.z = 0;
2266             }
2267
2268             Person::players[i]->tempanimation.Load((char *)"Tempanim", 0, 0);
2269
2270             Person::players[i]->headmorphness = 0;
2271             Person::players[i]->targetheadmorphness = 1;
2272             Person::players[i]->headmorphstart = 0;
2273             Person::players[i]->headmorphend = 0;
2274
2275             Person::players[i]->pausetime = 0;
2276
2277             Person::players[i]->dead = 0;
2278             Person::players[i]->jumppower = 5;
2279             Person::players[i]->damage = 0;
2280             Person::players[i]->permanentdamage = 0;
2281             Person::players[i]->superpermanentdamage = 0;
2282
2283             Person::players[i]->forwardkeydown = 0;
2284             Person::players[i]->leftkeydown = 0;
2285             Person::players[i]->backkeydown = 0;
2286             Person::players[i]->rightkeydown = 0;
2287             Person::players[i]->jumpkeydown = 0;
2288             Person::players[i]->crouchkeydown = 0;
2289             Person::players[i]->throwkeydown = 0;
2290
2291             Person::players[i]->collided = -10;
2292             Person::players[i]->loaded = 1;
2293             Person::players[i]->bloodloss = 0;
2294             Person::players[i]->weaponactive = -1;
2295             Person::players[i]->weaponstuck = -1;
2296             Person::players[i]->bleeding = 0;
2297             Person::players[i]->deathbleeding = 0;
2298             Person::players[i]->stunned = 0;
2299             Person::players[i]->hasvictim = 0;
2300             Person::players[i]->wentforweapon = 0;
2301         }
2302
2303         Person::players[0]->aitype = playercontrolled;
2304         Person::players[0]->weaponactive = -1;
2305
2306         if (difficulty == 1) {
2307             Person::players[0]->power = 1 / .9;
2308             Person::players[0]->damagetolerance = 250;
2309         } else if (difficulty == 0) {
2310             Person::players[0]->power = 1 / .8;
2311             Person::players[0]->damagetolerance = 300;
2312             Person::players[0]->armorhead *= 1.5;
2313             Person::players[0]->armorhigh *= 1.5;
2314             Person::players[0]->armorlow *= 1.5;
2315         }
2316
2317         cameraloc = Person::players[0]->coords;
2318         cameraloc.y += 5;
2319         yaw = Person::players[0]->yaw;
2320
2321         hawkcoords = Person::players[0]->coords;
2322         hawkcoords.y += 30;
2323
2324         if (visibleloading)
2325             LoadingScreen();
2326
2327         LOG("Starting background music...");
2328
2329         OPENAL_StopSound(OPENAL_ALL);
2330         if (ambientsound) {
2331             if (environment == snowyenvironment) {
2332                 emit_stream_np(stream_wind);
2333             } else if (environment == desertenvironment) {
2334                 emit_stream_np(stream_desertambient);
2335             } else if (environment == grassyenvironment) {
2336                 emit_stream_np(stream_wind, 100.);
2337             }
2338         }
2339         oldmusicvolume[0] = 0;
2340         oldmusicvolume[1] = 0;
2341         oldmusicvolume[2] = 0;
2342         oldmusicvolume[3] = 0;
2343
2344         if (!firstload)
2345             firstload = 1;
2346     } else {
2347         perror("Problem");
2348     }
2349     leveltime = 0;
2350     loadingstuff = 0;
2351     visibleloading = 0;
2352 }
2353
2354 void doTutorial()
2355 {
2356     if (tutorialstagetime > tutorialmaxtime) {
2357         tutorialstage++;
2358         tutorialsuccess = 0;
2359         if (tutorialstage <= 1) {
2360             canattack = 0;
2361             cananger = 0;
2362             reversaltrain = 0;
2363         }
2364         switch (tutorialstage) {
2365         case 1:
2366             tutorialmaxtime = 5;
2367             break;
2368         case 2:
2369             tutorialmaxtime = 2;
2370             break;
2371         case 3:
2372             tutorialmaxtime = 600;
2373             break;
2374         case 4:
2375             tutorialmaxtime = 1000;
2376             break;
2377         case 5:
2378             tutorialmaxtime = 600;
2379             break;
2380         case 6:
2381             tutorialmaxtime = 600;
2382             break;
2383         case 7:
2384             tutorialmaxtime = 600;
2385             break;
2386         case 8:
2387             tutorialmaxtime = 600;
2388             break;
2389         case 9:
2390             tutorialmaxtime = 600;
2391             break;
2392         case 10:
2393             tutorialmaxtime = 2;
2394             break;
2395         case 11:
2396             tutorialmaxtime = 1000;
2397             break;
2398         case 12:
2399             tutorialmaxtime = 1000;
2400             break;
2401         case 13:
2402             tutorialmaxtime = 2;
2403             break;
2404         case 14: {
2405             tutorialmaxtime = 3;
2406
2407             XYZ temp, temp2;
2408
2409             temp.x = 1011;
2410             temp.y = 84;
2411             temp.z = 491;
2412             temp2.x = 1025;
2413             temp2.y = 75;
2414             temp2.z = 447;
2415
2416             Person::players[1]->coords = (temp + temp2) / 2;
2417
2418             emit_sound_at(fireendsound, Person::players[1]->coords);
2419
2420             for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
2421                 if (Random() % 2 == 0) {
2422                     if (!Person::players[1]->skeleton.free)
2423                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
2424                     if (Person::players[1]->skeleton.free)
2425                         temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
2426                     if (!Person::players[1]->skeleton.free)
2427                         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;
2428                     if (Person::players[1]->skeleton.free)
2429                         temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
2430                     Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
2431                 }
2432             }
2433         }
2434         break;
2435         case 15:
2436             tutorialmaxtime = 500;
2437             break;
2438         case 16:
2439             tutorialmaxtime = 500;
2440             break;
2441         case 17:
2442             tutorialmaxtime = 500;
2443             break;
2444         case 18:
2445             tutorialmaxtime = 500;
2446             break;
2447         case 19:
2448             tutorialstage = 20;
2449             //tutorialmaxtime=500;
2450             break;
2451         case 20:
2452             tutorialmaxtime = 500;
2453             break;
2454         case 21:
2455             tutorialmaxtime = 500;
2456             if (bonus == cannon) {
2457                 bonus = Slicebonus;
2458                 againbonus = 1;
2459             } else
2460                 againbonus = 0;
2461             break;
2462         case 22:
2463             tutorialmaxtime = 500;
2464             break;
2465         case 23:
2466             tutorialmaxtime = 500;
2467             break;
2468         case 24:
2469             tutorialmaxtime = 500;
2470             break;
2471         case 25:
2472             tutorialmaxtime = 500;
2473             break;
2474         case 26:
2475             tutorialmaxtime = 2;
2476             break;
2477         case 27:
2478             tutorialmaxtime = 4;
2479             reversaltrain = 1;
2480             cananger = 1;
2481             Person::players[1]->aitype = attacktypecutoff;
2482             break;
2483         case 28:
2484             tutorialmaxtime = 400;
2485             break;
2486         case 29:
2487             tutorialmaxtime = 400;
2488             Person::players[0]->escapednum = 0;
2489             break;
2490         case 30:
2491             tutorialmaxtime = 4;
2492             reversaltrain = 0;
2493             cananger = 0;
2494             Person::players[1]->aitype = passivetype;
2495             break;
2496         case 31:
2497             tutorialmaxtime = 13;
2498             break;
2499         case 32:
2500             tutorialmaxtime = 8;
2501             break;
2502         case 33:
2503             tutorialmaxtime = 400;
2504             cananger = 1;
2505             canattack = 1;
2506             Person::players[1]->aitype = attacktypecutoff;
2507             break;
2508         case 34:
2509             tutorialmaxtime = 400;
2510             break;
2511         case 35:
2512             tutorialmaxtime = 400;
2513             break;
2514         case 36:
2515             tutorialmaxtime = 2;
2516             reversaltrain = 0;
2517             cananger = 0;
2518             Person::players[1]->aitype = passivetype;
2519             break;
2520         case 37:
2521             damagedealt = 0;
2522             damagetaken = 0;
2523             tutorialmaxtime = 50;
2524             cananger = 1;
2525             canattack = 1;
2526             Person::players[1]->aitype = attacktypecutoff;
2527             break;
2528         case 38:
2529             tutorialmaxtime = 4;
2530             canattack = 0;
2531             cananger = 0;
2532             Person::players[1]->aitype = passivetype;
2533             break;
2534         case 39: {
2535             XYZ temp, temp2;
2536
2537             temp.x = 1011;
2538             temp.y = 84;
2539             temp.z = 491;
2540             temp2.x = 1025;
2541             temp2.y = 75;
2542             temp2.z = 447;
2543
2544             Weapon w(knife, -1);
2545             w.position = (temp + temp2) / 2;
2546             w.tippoint = (temp + temp2) / 2;
2547
2548             w.velocity = 0.1;
2549             w.tipvelocity = 0.1;
2550             w.missed = 1;
2551             w.hitsomething = 0;
2552             w.freetime = 0;
2553             w.firstfree = 1;
2554             w.physics = 1;
2555
2556             weapons.push_back(w);
2557         }
2558         break;
2559         case 40:
2560             tutorialmaxtime = 300;
2561             break;
2562         case 41:
2563             tutorialmaxtime = 300;
2564             break;
2565         case 42:
2566             tutorialmaxtime = 8;
2567             break;
2568         case 43:
2569             tutorialmaxtime = 300;
2570             break;
2571         case 44:
2572             weapons[0].owner = 1;
2573             Person::players[0]->weaponactive = -1;
2574             Person::players[0]->num_weapons = 0;
2575             Person::players[1]->weaponactive = 0;
2576             Person::players[1]->num_weapons = 1;
2577             Person::players[1]->weaponids[0] = 0;
2578
2579             cananger = 1;
2580             canattack = 1;
2581             Person::players[1]->aitype = attacktypecutoff;
2582
2583             tutorialmaxtime = 300;
2584             break;
2585         case 45:
2586             weapons[0].owner = 1;
2587             Person::players[0]->weaponactive = -1;
2588             Person::players[0]->num_weapons = 0;
2589             Person::players[1]->weaponactive = 0;
2590             Person::players[1]->num_weapons = 1;
2591             Person::players[1]->weaponids[0] = 0;
2592
2593             tutorialmaxtime = 300;
2594             break;
2595         case 46:
2596             weapons[0].owner = 1;
2597             Person::players[0]->weaponactive = -1;
2598             Person::players[0]->num_weapons = 0;
2599             Person::players[1]->weaponactive = 0;
2600             Person::players[1]->num_weapons = 1;
2601             Person::players[1]->weaponids[0] = 0;
2602
2603             weapons[0].setType(sword);
2604
2605             tutorialmaxtime = 300;
2606             break;
2607         case 47: {
2608             tutorialmaxtime = 10;
2609
2610             XYZ temp, temp2;
2611
2612             temp.x = 1011;
2613             temp.y = 84;
2614             temp.z = 491;
2615             temp2.x = 1025;
2616             temp2.y = 75;
2617             temp2.z = 447;
2618
2619             Weapon w(sword, -1);
2620             w.position = (temp + temp2) / 2;
2621             w.tippoint = (temp + temp2) / 2;
2622
2623             w.velocity = 0.1;
2624             w.tipvelocity = 0.1;
2625             w.missed = 1;
2626             w.hitsomething = 0;
2627             w.freetime = 0;
2628             w.firstfree = 1;
2629             w.physics = 1;
2630
2631             weapons.push_back(w);
2632
2633             weapons[0].owner = 1;
2634             weapons[1].owner = 0;
2635             Person::players[0]->weaponactive = 0;
2636             Person::players[0]->num_weapons = 1;
2637             Person::players[0]->weaponids[0] = 1;
2638             Person::players[1]->weaponactive = 0;
2639             Person::players[1]->num_weapons = 1;
2640             Person::players[1]->weaponids[0] = 0;
2641
2642         }
2643         break;
2644         case 48:
2645             canattack = 0;
2646             cananger = 0;
2647             Person::players[1]->aitype = passivetype;
2648
2649             tutorialmaxtime = 15;
2650
2651             weapons[0].owner = 1;
2652             weapons[1].owner = 0;
2653             Person::players[0]->weaponactive = 0;
2654             Person::players[0]->num_weapons = 1;
2655             Person::players[0]->weaponids[0] = 1;
2656             Person::players[1]->weaponactive = 0;
2657             Person::players[1]->num_weapons = 1;
2658             Person::players[1]->weaponids[0] = 0;
2659
2660             if (Person::players[0]->weaponactive != -1)
2661                 weapons[Person::players[0]->weaponids[Person::players[0]->weaponactive]].setType(staff);
2662             else
2663                 weapons[0].setType(staff);
2664             break;
2665         case 49:
2666             canattack = 0;
2667             cananger = 0;
2668             Person::players[1]->aitype = passivetype;
2669
2670             tutorialmaxtime = 200;
2671
2672             weapons[1].position = 1000;
2673             weapons[1].tippoint = 1000;
2674
2675             weapons[0].setType(knife);
2676
2677             weapons[0].owner = 0;
2678             Person::players[1]->weaponactive = -1;
2679             Person::players[1]->num_weapons = 0;
2680             Person::players[0]->weaponactive = 0;
2681             Person::players[0]->num_weapons = 1;
2682             Person::players[0]->weaponids[0] = 0;
2683
2684             break;
2685         case 50: {
2686             tutorialmaxtime = 8;
2687
2688             XYZ temp, temp2;
2689             emit_sound_at(fireendsound, Person::players[1]->coords);
2690
2691             for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
2692                 if (Random() % 2 == 0) {
2693                     if (!Person::players[1]->skeleton.free)
2694                         temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
2695                     if (Person::players[1]->skeleton.free)
2696                         temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
2697                     if (!Person::players[1]->skeleton.free)
2698                         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;
2699                     if (Person::players[1]->skeleton.free)
2700                         temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
2701                     Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
2702                 }
2703             }
2704
2705             Person::players[1]->num_weapons = 0;
2706             Person::players[1]->weaponstuck = -1;
2707             Person::players[1]->weaponactive = -1;
2708
2709             weapons.clear();
2710         }
2711         break;
2712         case 51:
2713             tutorialmaxtime = 80000;
2714             break;
2715         default:
2716             break;
2717         }
2718         if (tutorialstage <= 51)
2719             tutorialstagetime = 0;
2720     }
2721
2722     //Tutorial success
2723     if (tutorialstagetime < tutorialmaxtime - 3) {
2724         switch (tutorialstage) {
2725         case 3:
2726             if (deltah || deltav)
2727                 tutorialsuccess += multiplier;
2728             break;
2729         case 4:
2730             if (Person::players[0]->forwardkeydown || Person::players[0]->backkeydown || Person::players[0]->leftkeydown || Person::players[0]->rightkeydown)
2731                 tutorialsuccess += multiplier;
2732             break;
2733         case 5:
2734             if (Person::players[0]->jumpkeydown)
2735                 tutorialsuccess = 1;
2736             break;
2737         case 6:
2738             if (Person::players[0]->isCrouch())
2739                 tutorialsuccess = 1;
2740             break;
2741         case 7:
2742             if (Person::players[0]->animTarget == rollanim)
2743                 tutorialsuccess = 1;
2744             break;
2745         case 8:
2746             if (Person::players[0]->animTarget == sneakanim)
2747                 tutorialsuccess += multiplier;
2748             break;
2749         case 9:
2750             if (Person::players[0]->animTarget == rabbitrunninganim || Person::players[0]->animTarget == wolfrunninganim)
2751                 tutorialsuccess += multiplier;
2752             break;
2753         case 11:
2754             if (Person::players[0]->isWallJump())
2755                 tutorialsuccess = 1;
2756             break;
2757         case 12:
2758             if (Person::players[0]->animTarget == flipanim)
2759                 tutorialsuccess = 1;
2760             break;
2761         case 15:
2762             if (Person::players[0]->animTarget == upunchanim || Person::players[0]->animTarget == winduppunchanim)
2763                 tutorialsuccess = 1;
2764             break;
2765         case 16:
2766             if (Person::players[0]->animTarget == winduppunchanim)
2767                 tutorialsuccess = 1;
2768             break;
2769         case 17:
2770             if (Person::players[0]->animTarget == spinkickanim)
2771                 tutorialsuccess = 1;
2772             break;
2773         case 18:
2774             if (Person::players[0]->animTarget == sweepanim)
2775                 tutorialsuccess = 1;
2776             break;
2777         case 19:
2778             if (Person::players[0]->animTarget == dropkickanim)
2779                 tutorialsuccess = 1;
2780             break;
2781         case 20:
2782             if (Person::players[0]->animTarget == rabbitkickanim)
2783                 tutorialsuccess = 1;
2784             break;
2785         case 21:
2786             if (bonus == cannon)
2787                 tutorialsuccess = 1;
2788             break;
2789         case 22:
2790             if (bonus == spinecrusher)
2791                 tutorialsuccess = 1;
2792             break;
2793         case 23:
2794             if (Person::players[0]->animTarget == walljumprightkickanim || Person::players[0]->animTarget == walljumpleftkickanim)
2795                 tutorialsuccess = 1;
2796             break;
2797         case 24:
2798             if (Person::players[0]->animTarget == rabbittacklinganim)
2799                 tutorialsuccess = 1;
2800             break;
2801         case 25:
2802             if (Person::players[0]->animTarget == backhandspringanim)
2803                 tutorialsuccess = 1;
2804             break;
2805         case 28:
2806             if (animation[Person::players[0]->animTarget].attack == reversed && Person::players[0]->feint)
2807                 tutorialsuccess = 1;
2808             break;
2809         case 29:
2810             if (Person::players[0]->escapednum == 2) {
2811                 tutorialsuccess = 1;
2812                 reversaltrain = 0;
2813                 cananger = 0;
2814                 Person::players[1]->aitype = passivetype;
2815             }
2816             break;
2817         case 33:
2818             if (animation[Person::players[0]->animTarget].attack == reversal)
2819                 tutorialsuccess = 1;
2820             break;
2821         case 34:
2822             if (animation[Person::players[0]->animTarget].attack == reversal)
2823                 tutorialsuccess = 1;
2824             break;
2825         case 35:
2826             if (animation[Person::players[0]->animTarget].attack == reversal) {
2827                 tutorialsuccess = 1;
2828                 reversaltrain = 0;
2829                 cananger = 0;
2830                 Person::players[1]->aitype = passivetype;
2831             }
2832             break;
2833         case 40:
2834             if (Person::players[0]->num_weapons > 0)
2835                 tutorialsuccess = 1;
2836             break;
2837         case 41:
2838             if (Person::players[0]->weaponactive == -1 && Person::players[0]->num_weapons > 0)
2839                 tutorialsuccess = 1;
2840             break;
2841         case 43:
2842             if (Person::players[0]->animTarget == knifeslashstartanim)
2843                 tutorialsuccess = 1;
2844             break;
2845         case 44:
2846             if (animation[Person::players[0]->animTarget].attack == reversal)
2847                 tutorialsuccess = 1;
2848             break;
2849         case 45:
2850             if (animation[Person::players[0]->animTarget].attack == reversal)
2851                 tutorialsuccess = 1;
2852             break;
2853         case 46:
2854             if (animation[Person::players[0]->animTarget].attack == reversal)
2855                 tutorialsuccess = 1;
2856             break;
2857         case 49:
2858             if (Person::players[1]->weaponstuck != -1)
2859                 tutorialsuccess = 1;
2860             break;
2861         default:
2862             break;
2863         }
2864         if (tutorialsuccess >= 1)
2865             tutorialstagetime = tutorialmaxtime - 3;
2866
2867
2868         if (tutorialstagetime == tutorialmaxtime - 3) {
2869             emit_sound_np(consolesuccesssound);
2870         }
2871
2872         if (tutorialsuccess >= 1) {
2873             if (tutorialstage == 34 || tutorialstage == 35)
2874                 tutorialstagetime = tutorialmaxtime - 1;
2875         }
2876     }
2877
2878     if (tutorialstage < 14 || tutorialstage >= 50) {
2879         Person::players[1]->coords.y = 300;
2880         Person::players[1]->velocity = 0;
2881     }
2882 }
2883
2884 void doDebugKeys()
2885 {
2886     float headprop, bodyprop, armprop, legprop;
2887     if (debugmode) {
2888         if (Input::isKeyPressed(SDLK_h)) {
2889             Person::players[0]->damagetolerance = 200000;
2890             Person::players[0]->damage = 0;
2891             Person::players[0]->burnt = 0;
2892             Person::players[0]->permanentdamage = 0;
2893             Person::players[0]->superpermanentdamage = 0;
2894         }
2895
2896         if (Input::isKeyPressed(SDLK_j)) {
2897             environment++;
2898             if (environment > 2)
2899                 environment = 0;
2900             Setenvironment(environment);
2901         }
2902
2903         if (Input::isKeyPressed(SDLK_c)) {
2904             cameramode = 1 - cameramode;
2905         }
2906
2907         if (Input::isKeyPressed(SDLK_x) && !Input::isKeyDown(SDLK_LSHIFT)) {
2908             if (Person::players[0]->num_weapons > 0) {
2909                 if (weapons[Person::players[0]->weaponids[0]].getType() == sword)
2910                     weapons[Person::players[0]->weaponids[0]].setType(staff);
2911                 else if (weapons[Person::players[0]->weaponids[0]].getType() == staff)
2912                     weapons[Person::players[0]->weaponids[0]].setType(knife);
2913                 else
2914                     weapons[Person::players[0]->weaponids[0]].setType(sword);
2915             }
2916         }
2917
2918         if (Input::isKeyPressed(SDLK_x) && Input::isKeyDown(SDLK_LSHIFT)) {
2919             int closest = findClosestPlayer();
2920             if (closest >= 0) {
2921                 if (Person::players[closest]->num_weapons) {
2922                     if (weapons[Person::players[closest]->weaponids[0]].getType() == sword)
2923                         weapons[Person::players[closest]->weaponids[0]].setType(staff);
2924                     else if (weapons[Person::players[closest]->weaponids[0]].getType() == staff)
2925                         weapons[Person::players[closest]->weaponids[0]].setType(knife);
2926                     else
2927                         weapons[Person::players[closest]->weaponids[0]].setType(sword);
2928                 }
2929                 if (!Person::players[closest]->num_weapons) {
2930                     Person::players[closest]->weaponids[0] = weapons.size();
2931
2932                     weapons.push_back(Weapon(knife, closest));
2933
2934                     Person::players[closest]->num_weapons = 1;
2935                 }
2936             }
2937         }
2938
2939         if (Input::isKeyDown(SDLK_u)) {
2940             int closest = findClosestPlayer();
2941             if (closest >= 0) {
2942                 Person::players[closest]->yaw += multiplier * 50;
2943                 Person::players[closest]->targetyaw = Person::players[closest]->yaw;
2944             }
2945         }
2946
2947
2948         if (Input::isKeyPressed(SDLK_o) && !Input::isKeyDown(SDLK_LSHIFT)) {
2949             int closest = findClosestPlayer();
2950             if (Input::isKeyDown(SDLK_LCTRL))
2951                 closest = 0;
2952
2953             if (closest >= 0) {
2954                 Person::players[closest]->whichskin++;
2955                 if (Person::players[closest]->whichskin > 9)
2956                     Person::players[closest]->whichskin = 0;
2957                 if (Person::players[closest]->whichskin > 2 && Person::players[closest]->creature == wolftype)
2958                     Person::players[closest]->whichskin = 0;
2959
2960                 Person::players[closest]->skeleton.drawmodel.textureptr.load(creatureskin[Person::players[closest]->creature][Person::players[closest]->whichskin], 1,
2961                         &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
2962             }
2963
2964             if (Person::players[closest]->numclothes) {
2965                 for (int i = 0; i < Person::players[closest]->numclothes; i++) {
2966                     tintr = Person::players[closest]->clothestintr[i];
2967                     tintg = Person::players[closest]->clothestintg[i];
2968                     tintb = Person::players[closest]->clothestintb[i];
2969                     AddClothes((char *)Person::players[closest]->clothes[i], &Person::players[closest]->skeleton.skinText[0]);
2970                 }
2971                 Person::players[closest]->DoMipmaps();
2972             }
2973         }
2974
2975         if (Input::isKeyPressed(SDLK_o) && Input::isKeyDown(SDLK_LSHIFT)) {
2976             int closest = findClosestPlayer();
2977             if (closest >= 0) {
2978                 if (Person::players[closest]->creature == wolftype) {
2979                     headprop = Person::players[closest]->proportionhead.x / 1.1;
2980                     bodyprop = Person::players[closest]->proportionbody.x / 1.1;
2981                     armprop = Person::players[closest]->proportionarms.x / 1.1;
2982                     legprop = Person::players[closest]->proportionlegs.x / 1.1;
2983                 }
2984
2985                 if (Person::players[closest]->creature == rabbittype) {
2986                     headprop = Person::players[closest]->proportionhead.x / 1.2;
2987                     bodyprop = Person::players[closest]->proportionbody.x / 1.05;
2988                     armprop = Person::players[closest]->proportionarms.x / 1.00;
2989                     legprop = Person::players[closest]->proportionlegs.x / 1.1;
2990                 }
2991
2992
2993                 if (Person::players[closest]->creature == rabbittype) {
2994                     Person::players[closest]->skeleton.id = closest;
2995                     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);
2996                     Person::players[closest]->skeleton.drawmodel.textureptr.load(":Data:Textures:Wolf.jpg", 1, &Person::players[closest]->skeleton.skinText[closest], &Person::players[closest]->skeleton.skinsize);
2997                     Person::players[closest]->whichskin = 0;
2998                     Person::players[closest]->creature = wolftype;
2999
3000                     Person::players[closest]->proportionhead = 1.1;
3001                     Person::players[closest]->proportionbody = 1.1;
3002                     Person::players[closest]->proportionarms = 1.1;
3003                     Person::players[closest]->proportionlegs = 1.1;
3004                     Person::players[closest]->proportionlegs.y = 1.1;
3005                     Person::players[closest]->scale = .23 * 5 * Person::players[0]->scale;
3006
3007                     Person::players[closest]->damagetolerance = 300;
3008                 } else {
3009                     Person::players[closest]->skeleton.id = closest;
3010                     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);
3011                     Person::players[closest]->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur3.jpg", 1, &Person::players[closest]->skeleton.skinText[0], &Person::players[closest]->skeleton.skinsize);
3012                     Person::players[closest]->whichskin = 0;
3013                     Person::players[closest]->creature = rabbittype;
3014
3015                     Person::players[closest]->proportionhead = 1.2;
3016                     Person::players[closest]->proportionbody = 1.05;
3017                     Person::players[closest]->proportionarms = 1.00;
3018                     Person::players[closest]->proportionlegs = 1.1;
3019                     Person::players[closest]->proportionlegs.y = 1.05;
3020                     Person::players[closest]->scale = .2 * 5 * Person::players[0]->scale;
3021
3022                     Person::players[closest]->damagetolerance = 200;
3023                 }
3024
3025                 if (Person::players[closest]->creature == wolftype) {
3026                     Person::players[closest]->proportionhead = 1.1 * headprop;
3027                     Person::players[closest]->proportionbody = 1.1 * bodyprop;
3028                     Person::players[closest]->proportionarms = 1.1 * armprop;
3029                     Person::players[closest]->proportionlegs = 1.1 * legprop;
3030                 }
3031
3032                 if (Person::players[closest]->creature == rabbittype) {
3033                     Person::players[closest]->proportionhead = 1.2 * headprop;
3034                     Person::players[closest]->proportionbody = 1.05 * bodyprop;
3035                     Person::players[closest]->proportionarms = 1.00 * armprop;
3036                     Person::players[closest]->proportionlegs = 1.1 * legprop;
3037                     Person::players[closest]->proportionlegs.y = 1.05 * legprop;
3038                 }
3039
3040             }
3041         }
3042
3043         if (Input::isKeyPressed(SDLK_b) && !Input::isKeyDown(SDLK_LSHIFT)) {
3044             slomo = 1 - slomo;
3045             slomodelay = 1000;
3046         }
3047
3048
3049         if (((Input::isKeyPressed(SDLK_i) && !Input::isKeyDown(SDLK_LSHIFT)))) {
3050             int closest = -1;
3051             float closestdist = std::numeric_limits<float>::max();
3052
3053             for (int i = 1; i < Person::players.size(); i++) {
3054                 float distance = distsq(&Person::players[i]->coords, &Person::players[0]->coords);
3055                 if (!Person::players[i]->headless)
3056                     if (distance < closestdist) {
3057                         closestdist = distance;
3058                         closest = i;
3059                     }
3060             }
3061
3062             XYZ flatfacing2, flatvelocity2;
3063             XYZ blah;
3064             if (closest != -1 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
3065                 blah = Person::players[closest]->coords;
3066                 XYZ headspurtdirection;
3067                 //int i = Person::players[closest]->skeleton.jointlabels[head];
3068                 Joint& headjoint = Person::players[closest]->joint(head);
3069                 for (int k = 0; k < Person::players[closest]->skeleton.num_joints; k++) {
3070                     if (!Person::players[closest]->skeleton.free)
3071                         flatvelocity2 = Person::players[closest]->velocity;
3072                     if (Person::players[closest]->skeleton.free)
3073                         flatvelocity2 = headjoint.velocity;
3074                     if (!Person::players[closest]->skeleton.free)
3075                         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;
3076                     if (Person::players[closest]->skeleton.free)
3077                         flatfacing2 = headjoint.position * Person::players[closest]->scale + Person::players[closest]->coords;
3078                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
3079                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
3080                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
3081                     headspurtdirection = headjoint.position - Person::players[closest]->jointPos(neck);
3082                     Normalise(&headspurtdirection);
3083                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, .6, 1);
3084                     flatvelocity2 += headspurtdirection * 8;
3085                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 / 2, 1, 1, 1, .16, 1);
3086                 }
3087                 Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
3088
3089                 emit_sound_at(splattersound, blah);
3090                 emit_sound_at(breaksound2, blah, 100.);
3091
3092                 if (Person::players[closest]->skeleton.free == 2)
3093                     Person::players[closest]->skeleton.free = 0;
3094                 Person::players[closest]->RagDoll(0);
3095                 Person::players[closest]->dead = 2;
3096                 Person::players[closest]->headless = 1;
3097                 Person::players[closest]->DoBloodBig(3, 165);
3098
3099                 camerashake += .3;
3100             }
3101         }
3102
3103         if (((Input::isKeyPressed(SDLK_i) && Input::isKeyDown(SDLK_LSHIFT)))) {
3104             int closest = findClosestPlayer();
3105             XYZ flatfacing2, flatvelocity2;
3106             XYZ blah;
3107             if (closest >= 0 && distsq(&Person::players[closest]->coords, &Person::players[0]->coords) < 144) {
3108                 blah = Person::players[closest]->coords;
3109                 emit_sound_at(splattersound, blah);
3110                 emit_sound_at(breaksound2, blah);
3111
3112                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
3113                     if (!Person::players[closest]->skeleton.free)
3114                         flatvelocity2 = Person::players[closest]->velocity;
3115                     if (Person::players[closest]->skeleton.free)
3116                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
3117                     if (!Person::players[closest]->skeleton.free)
3118                         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;
3119                     if (Person::players[closest]->skeleton.free)
3120                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
3121                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
3122                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
3123                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
3124                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
3125                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .3, 1);
3126                     Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
3127                 }
3128
3129                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
3130                     if (!Person::players[closest]->skeleton.free)
3131                         flatvelocity2 = Person::players[closest]->velocity;
3132                     if (Person::players[closest]->skeleton.free)
3133                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
3134                     if (!Person::players[closest]->skeleton.free)
3135                         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;
3136                     if (Person::players[closest]->skeleton.free)
3137                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
3138                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
3139                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
3140                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
3141                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
3142                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
3143                 }
3144
3145                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
3146                     if (!Person::players[closest]->skeleton.free)
3147                         flatvelocity2 = Person::players[closest]->velocity;
3148                     if (Person::players[closest]->skeleton.free)
3149                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
3150                     if (!Person::players[closest]->skeleton.free)
3151                         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;
3152                     if (Person::players[closest]->skeleton.free)
3153                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
3154                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
3155                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
3156                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
3157                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, 3, 1);
3158                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
3159                 }
3160
3161                 for (int i = 0; i < Person::players[closest]->skeleton.num_joints; i++) {
3162                     if (!Person::players[closest]->skeleton.free)
3163                         flatvelocity2 = Person::players[closest]->velocity;
3164                     if (Person::players[closest]->skeleton.free)
3165                         flatvelocity2 = Person::players[closest]->skeleton.joints[i].velocity;
3166                     if (!Person::players[closest]->skeleton.free)
3167                         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;
3168                     if (Person::players[closest]->skeleton.free)
3169                         flatfacing2 = Person::players[closest]->skeleton.joints[i].position * Person::players[closest]->scale + Person::players[closest]->coords;
3170                     flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
3171                     flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
3172                     flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
3173                     Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, 3, 1);
3174                     Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2 * 2, 1, 1, 1, .4, 1);
3175                 }
3176
3177                 XYZ temppos;
3178                 for (int j = 0; j < Person::players.size(); j++) {
3179                     if (j != closest) {
3180                         if (distsq(&Person::players[j]->coords, &Person::players[closest]->coords) < 25) {
3181                             Person::players[j]->DoDamage((25 - distsq(&Person::players[j]->coords, &Person::players[closest]->coords)) * 60);
3182                             if (Person::players[j]->skeleton.free == 2)
3183                                 Person::players[j]->skeleton.free = 1;
3184                             Person::players[j]->skeleton.longdead = 0;
3185                             Person::players[j]->RagDoll(0);
3186                             for (int i = 0; i < Person::players[j]->skeleton.num_joints; i++) {
3187                                 temppos = Person::players[j]->skeleton.joints[i].position + Person::players[j]->coords;
3188                                 if (distsq(&temppos, &Person::players[closest]->coords) < 25) {
3189                                     flatvelocity2 = temppos - Person::players[closest]->coords;
3190                                     Normalise(&flatvelocity2);
3191                                     Person::players[j]->skeleton.joints[i].velocity += flatvelocity2 * ((20 - distsq(&temppos, &Person::players[closest]->coords)) * 20);
3192                                 }
3193                             }
3194                         }
3195                     }
3196                 }
3197
3198                 Person::players[closest]->DoDamage(10000);
3199                 Person::players[closest]->RagDoll(0);
3200                 Person::players[closest]->dead = 2;
3201                 Person::players[closest]->coords = 20;
3202                 Person::players[closest]->skeleton.free = 2;
3203
3204                 camerashake += .6;
3205
3206             }
3207         }
3208
3209         if (Input::isKeyPressed(SDLK_f)) {
3210             Person::players[0]->onfire = 1 - Person::players[0]->onfire;
3211             if (Person::players[0]->onfire) {
3212                 Person::players[0]->CatchFire();
3213             }
3214             if (!Person::players[0]->onfire) {
3215                 emit_sound_at(fireendsound, Person::players[0]->coords);
3216                 pause_sound(stream_firesound);
3217             }
3218         }
3219
3220         if (Input::isKeyPressed(SDLK_n) && !Input::isKeyDown(SDLK_LCTRL)) {
3221             //if(!Person::players[0]->skeleton.free)Person::players[0]->damage+=500;
3222             Person::players[0]->RagDoll(0);
3223             //Person::players[0]->spurt=1;
3224             //Person::players[0]->DoDamage(1000);
3225
3226             emit_sound_at(whooshsound, Person::players[0]->coords, 128.);
3227         }
3228
3229         if (Input::isKeyPressed(SDLK_n) && Input::isKeyDown(SDLK_LCTRL)) {
3230             for (int i = 0; i < objects.numobjects; i++) {
3231                 if (objects.type[i] == treeleavestype) {
3232                     objects.scale[i] *= .9;
3233                 }
3234             }
3235         }
3236
3237         if (Input::isKeyPressed(SDLK_m) && Input::isKeyDown(SDLK_LSHIFT)) {
3238             editorenabled = 1 - editorenabled;
3239             if (editorenabled) {
3240                 Person::players[0]->damagetolerance = 100000;
3241             } else {
3242                 Person::players[0]->damagetolerance = 200;
3243             }
3244             Person::players[0]->damage = 0; // these lines were in both if and else, but I think they would better fit in the if
3245             Person::players[0]->permanentdamage = 0;
3246             Person::players[0]->superpermanentdamage = 0;
3247             Person::players[0]->bloodloss = 0;
3248             Person::players[0]->deathbleeding = 0;
3249         }
3250
3251         //skip level
3252         if (whichlevel != -2 && Input::isKeyPressed(SDLK_k) && Input::isKeyDown(SDLK_LSHIFT) && !editorenabled) {
3253             targetlevel++;
3254             if (targetlevel > numchallengelevels - 1)
3255                 targetlevel = 0;
3256             loading = 1;
3257             leveltime = 5;
3258         }
3259
3260         if (editorenabled) {
3261             if (Input::isKeyPressed(SDLK_DELETE) && Input::isKeyDown(SDLK_LSHIFT)) {
3262                 int closest = findClosestPlayer();
3263                 if (closest >= 0) {
3264                     Person::players.erase(Person::players.begin()+closest);
3265                 }
3266             }
3267
3268             if (Input::isKeyPressed(SDLK_DELETE) && Input::isKeyDown(SDLK_LCTRL)) {
3269                 int closest = findClosestObject();
3270                 if (closest >= 0)
3271                     objects.position[closest].y -= 500;
3272             }
3273
3274             if (Input::isKeyPressed(SDLK_m) && Input::isKeyDown(SDLK_LSHIFT)) {
3275                 //drawmode++;
3276                 //if(drawmode>2)drawmode=0;
3277                 if (objects.numobjects < max_objects - 1) {
3278                     XYZ boxcoords;
3279                     boxcoords.x = Person::players[0]->coords.x;
3280                     boxcoords.z = Person::players[0]->coords.z;
3281                     boxcoords.y = Person::players[0]->coords.y - 3;
3282                     if (editortype == bushtype)
3283                         boxcoords.y = Person::players[0]->coords.y - .5;
3284                     if (editortype == firetype)
3285                         boxcoords.y = Person::players[0]->coords.y - .5;
3286                     //objects.MakeObject(abs(Random()%3),boxcoords,Random()%360);
3287                     float temprotat, temprotat2;
3288                     temprotat = editoryaw;
3289                     temprotat2 = editorpitch;
3290                     if (temprotat < 0 || editortype == bushtype)
3291                         temprotat = Random() % 360;
3292                     if (temprotat2 < 0)
3293                         temprotat2 = Random() % 360;
3294
3295                     objects.MakeObject(editortype, boxcoords, (int)temprotat - ((int)temprotat) % 30, (int)temprotat2, editorsize);
3296                     if (editortype == treetrunktype)
3297                         objects.MakeObject(treeleavestype, boxcoords, Random() % 360 * (temprotat2 < 2) + (int)editoryaw - ((int)editoryaw) % 30, editorpitch, editorsize);
3298                 }
3299             }
3300
3301             if (Input::isKeyPressed(SDLK_p) && Input::isKeyDown(SDLK_LSHIFT) && !Input::isKeyDown(SDLK_LCTRL)) {
3302                 Person::players.push_back(shared_ptr<Person>(new Person()));
3303
3304                 Person::players.back()->scale = .2 * 5 * Person::players[0]->scale;
3305                 Person::players.back()->creature = rabbittype;
3306                 Person::players.back()->howactive = editoractive;
3307                 Person::players.back()->skeleton.id = Person::players.size()-1;
3308                 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);
3309
3310                 int k = abs(Random() % 2) + 1;
3311                 if (k == 0) {
3312                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur3.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
3313                     Person::players.back()->whichskin = 0;
3314                 } else if (k == 1) {
3315                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
3316                     Person::players.back()->whichskin = 1;
3317                 } else {
3318                     Person::players.back()->skeleton.drawmodel.textureptr.load(":Data:Textures:Fur2.jpg", 1, &Person::players.back()->skeleton.skinText[0], &Person::players.back()->skeleton.skinsize);
3319                     Person::players.back()->whichskin = 2;
3320                 }
3321
3322                 Person::players.back()->skeleton.drawmodelclothes.textureptr.load(":Data:Textures:Belt.png", 1, 1);
3323                 Person::players.back()->power = 1;
3324                 Person::players.back()->speedmult = 1;
3325                 Person::players.back()->animCurrent = bounceidleanim;
3326                 Person::players.back()->animTarget = bounceidleanim;
3327                 Person::players.back()->frameCurrent = 0;
3328                 Person::players.back()->frameTarget = 1;
3329                 Person::players.back()->target = 0;
3330                 Person::players.back()->bled = 0;
3331                 Person::players.back()->speed = 1 + (float)(Random() % 100) / 1000;
3332
3333                 Person::players.back()->targetyaw = Person::players[0]->targetyaw;
3334                 Person::players.back()->yaw = Person::players[0]->yaw;
3335
3336                 Person::players.back()->velocity = 0;
3337                 Person::players.back()->coords = Person::players[0]->coords;
3338                 Person::players.back()->oldcoords = Person::players.back()->coords;
3339                 Person::players.back()->realoldcoords = Person::players.back()->coords;
3340
3341                 Person::players.back()->id = Person::players.size()-1;
3342                 Person::players.back()->updatedelay = 0;
3343                 Person::players.back()->normalsupdatedelay = 0;
3344
3345                 Person::players.back()->aitype = passivetype;
3346
3347                 if (Person::players[0]->creature == wolftype) {
3348                     headprop = Person::players[0]->proportionhead.x / 1.1;
3349                     bodyprop = Person::players[0]->proportionbody.x / 1.1;
3350                     armprop = Person::players[0]->proportionarms.x / 1.1;
3351                     legprop = Person::players[0]->proportionlegs.x / 1.1;
3352                 }
3353
3354                 if (Person::players[0]->creature == rabbittype) {
3355                     headprop = Person::players[0]->proportionhead.x / 1.2;
3356                     bodyprop = Person::players[0]->proportionbody.x / 1.05;
3357                     armprop = Person::players[0]->proportionarms.x / 1.00;
3358                     legprop = Person::players[0]->proportionlegs.x / 1.1;
3359                 }
3360
3361                 if (Person::players.back()->creature == wolftype) {
3362                     Person::players.back()->proportionhead = 1.1 * headprop;
3363                     Person::players.back()->proportionbody = 1.1 * bodyprop;
3364                     Person::players.back()->proportionarms = 1.1 * armprop;
3365                     Person::players.back()->proportionlegs = 1.1 * legprop;
3366                 }
3367
3368                 if (Person::players.back()->creature == rabbittype) {
3369                     Person::players.back()->proportionhead = 1.2 * headprop;
3370                     Person::players.back()->proportionbody = 1.05 * bodyprop;
3371                     Person::players.back()->proportionarms = 1.00 * armprop;
3372                     Person::players.back()->proportionlegs = 1.1 * legprop;
3373                     Person::players.back()->proportionlegs.y = 1.05 * legprop;
3374                 }
3375
3376                 Person::players.back()->headless = 0;
3377                 Person::players.back()->onfire = 0;
3378
3379                 if (cellophane) {
3380                     Person::players.back()->proportionhead.z = 0;
3381                     Person::players.back()->proportionbody.z = 0;
3382                     Person::players.back()->proportionarms.z = 0;
3383                     Person::players.back()->proportionlegs.z = 0;
3384                 }
3385
3386                 Person::players.back()->tempanimation.Load((char *)"Tempanim", 0, 0);
3387
3388                 Person::players.back()->damagetolerance = 200;
3389
3390                 Person::players.back()->protectionhead = Person::players[0]->protectionhead;
3391                 Person::players.back()->protectionhigh = Person::players[0]->protectionhigh;
3392                 Person::players.back()->protectionlow = Person::players[0]->protectionlow;
3393                 Person::players.back()->armorhead = Person::players[0]->armorhead;
3394                 Person::players.back()->armorhigh = Person::players[0]->armorhigh;
3395                 Person::players.back()->armorlow = Person::players[0]->armorlow;
3396                 Person::players.back()->metalhead = Person::players[0]->metalhead;
3397                 Person::players.back()->metalhigh = Person::players[0]->metalhigh;
3398                 Person::players.back()->metallow = Person::players[0]->metallow;
3399
3400                 Person::players.back()->immobile = Person::players[0]->immobile;
3401
3402                 Person::players.back()->numclothes = Person::players[0]->numclothes;
3403                 if (Person::players.back()->numclothes)
3404                     for (int i = 0; i < Person::players.back()->numclothes; i++) {
3405                         strcpy(Person::players.back()->clothes[i], Person::players[0]->clothes[i]);
3406                         Person::players.back()->clothestintr[i] = Person::players[0]->clothestintr[i];
3407                         Person::players.back()->clothestintg[i] = Person::players[0]->clothestintg[i];
3408                         Person::players.back()->clothestintb[i] = Person::players[0]->clothestintb[i];
3409                         tintr = Person::players.back()->clothestintr[i];
3410                         tintg = Person::players.back()->clothestintg[i];
3411                         tintb = Person::players.back()->clothestintb[i];
3412                         AddClothes((char *)Person::players.back()->clothes[i], &Person::players.back()->skeleton.skinText[0]);
3413                     }
3414                 if (Person::players.back()->numclothes) {
3415                     Person::players.back()->DoMipmaps();
3416                 }
3417
3418                 Person::players.back()->power = Person::players[0]->power;
3419                 Person::players.back()->speedmult = Person::players[0]->speedmult;
3420
3421                 Person::players.back()->damage = 0;
3422                 Person::players.back()->permanentdamage = 0;
3423                 Person::players.back()->superpermanentdamage = 0;
3424                 Person::players.back()->deathbleeding = 0;
3425                 Person::players.back()->bleeding = 0;
3426                 Person::players.back()->numwaypoints = 0;
3427                 Person::players.back()->waypoint = 0;
3428                 Person::players.back()->jumppath = 0;
3429                 Person::players.back()->weaponstuck = -1;
3430                 Person::players.back()->weaponactive = -1;
3431                 Person::players.back()->num_weapons = 0;
3432                 Person::players.back()->bloodloss = 0;
3433                 Person::players.back()->dead = 0;
3434
3435                 Person::players.back()->loaded = 1;
3436             }
3437
3438             if (Input::isKeyPressed(SDLK_p) && Input::isKeyDown(SDLK_LSHIFT)) {
3439                 if (Person::players.back()->numwaypoints < 90) {
3440                     Person::players.back()->waypoints[Person::players.back()->numwaypoints] = Person::players[0]->coords;
3441                     Person::players.back()->waypointtype[Person::players.back()->numwaypoints] = editorpathtype;
3442                     Person::players.back()->numwaypoints++;
3443                 }
3444             }
3445
3446             if (Input::isKeyPressed(SDLK_p) && Input::isKeyDown(SDLK_LCTRL)) {
3447                 if (numpathpoints < 30) {
3448                     bool connected, alreadyconnected;
3449                     connected = 0;
3450                     if (numpathpoints > 1)
3451                         for (int i = 0; i < numpathpoints; i++) {
3452                             if (distsq(&pathpoint[i], &Person::players[0]->coords) < .5 && i != pathpointselected && !connected) {
3453                                 alreadyconnected = 0;
3454                                 for (int j = 0; j < numpathpointconnect[pathpointselected]; j++) {
3455                                     if (pathpointconnect[pathpointselected][j] == i)
3456                                         alreadyconnected = 1;
3457                                 }
3458                                 if (!alreadyconnected) {
3459                                     numpathpointconnect[pathpointselected]++;
3460                                     connected = 1;
3461                                     pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected] - 1] = i;
3462                                 }
3463                             }
3464                         }
3465                     if (!connected) {
3466                         numpathpoints++;
3467                         pathpoint[numpathpoints - 1] = Person::players[0]->coords;
3468                         numpathpointconnect[numpathpoints - 1] = 0;
3469                         if (numpathpoints > 1 && pathpointselected != -1) {
3470                             numpathpointconnect[pathpointselected]++;
3471                             pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected] - 1] = numpathpoints - 1;
3472                         }
3473                         pathpointselected = numpathpoints - 1;
3474                     }
3475                 }
3476             }
3477
3478             if (Input::isKeyPressed(SDLK_PERIOD)) {
3479                 pathpointselected++;
3480                 if (pathpointselected >= numpathpoints)
3481                     pathpointselected = -1;
3482             }
3483             if (Input::isKeyPressed(SDLK_COMMA) && !Input::isKeyDown(SDLK_LSHIFT)) {
3484                 pathpointselected--;
3485                 if (pathpointselected <= -2)
3486                     pathpointselected = numpathpoints - 1;
3487             }
3488             if (Input::isKeyPressed(SDLK_COMMA) && Input::isKeyDown(SDLK_LSHIFT)) {
3489                 if (pathpointselected != -1) {
3490                     numpathpoints--;
3491                     pathpoint[pathpointselected] = pathpoint[numpathpoints];
3492                     numpathpointconnect[pathpointselected] = numpathpointconnect[numpathpoints];
3493                     for (int i = 0; i < numpathpointconnect[pathpointselected]; i++) {
3494                         pathpointconnect[pathpointselected][i] = pathpointconnect[numpathpoints][i];
3495                     }
3496                     for (int i = 0; i < numpathpoints; i++) {
3497                         for (int j = 0; j < numpathpointconnect[i]; j++) {
3498                             if (pathpointconnect[i][j] == pathpointselected) {
3499                                 pathpointconnect[i][j] = pathpointconnect[i][numpathpointconnect[i] - 1];
3500                                 numpathpointconnect[i]--;
3501                             }
3502                             if (pathpointconnect[i][j] == numpathpoints) {
3503                                 pathpointconnect[i][j] = pathpointselected;
3504                             }
3505                         }
3506                     }
3507                     pathpointselected = numpathpoints - 1;
3508                 }
3509             }
3510
3511             if (Input::isKeyPressed(SDLK_LEFT) && Input::isKeyDown(SDLK_LSHIFT) && !Input::isKeyDown(SDLK_LCTRL)) {
3512                 editortype--;
3513                 if (editortype == treeleavestype || editortype == 10)
3514                     editortype--;
3515                 if (editortype < 0)
3516                     editortype = firetype;
3517             }
3518
3519             if (Input::isKeyPressed(SDLK_RIGHT) && Input::isKeyDown(SDLK_LSHIFT) && !Input::isKeyDown(SDLK_LCTRL)) {
3520                 editortype++;
3521                 if (editortype == treeleavestype || editortype == 10)
3522                     editortype++;
3523                 if (editortype > firetype)
3524                     editortype = 0;
3525             }
3526
3527             if (Input::isKeyDown(SDLK_LEFT) && !Input::isKeyDown(SDLK_LSHIFT) && !Input::isKeyDown(SDLK_LCTRL)) {
3528                 editoryaw -= multiplier * 100;
3529                 if (editoryaw < -.01)
3530                     editoryaw = -.01;
3531             }
3532
3533             if (Input::isKeyDown(SDLK_RIGHT) && !Input::isKeyDown(SDLK_LSHIFT) && !Input::isKeyDown(SDLK_LCTRL)) {
3534                 editoryaw += multiplier * 100;
3535             }
3536
3537             if (Input::isKeyDown(SDLK_UP) && !Input::isKeyDown(SDLK_LCTRL)) {
3538                 editorsize += multiplier;
3539             }
3540
3541             if (Input::isKeyDown(SDLK_DOWN) && !Input::isKeyDown(SDLK_LCTRL)) {
3542                 editorsize -= multiplier;
3543                 if (editorsize < .1)
3544                     editorsize = .1;
3545             }
3546
3547
3548             if (Input::isKeyPressed(SDLK_LEFT) && Input::isKeyDown(SDLK_LSHIFT) && Input::isKeyDown(SDLK_LCTRL)) {
3549                 mapradius -= multiplier * 10;
3550             }
3551
3552             if (Input::isKeyPressed(SDLK_RIGHT) && Input::isKeyDown(SDLK_LSHIFT) && Input::isKeyDown(SDLK_LCTRL)) {
3553                 mapradius += multiplier * 10;
3554             }
3555             if (Input::isKeyDown(SDLK_UP) && Input::isKeyDown(SDLK_LCTRL)) {
3556                 editorpitch += multiplier * 100;
3557             }
3558
3559             if (Input::isKeyDown(SDLK_DOWN) && Input::isKeyDown(SDLK_LCTRL)) {
3560                 editorpitch -= multiplier * 100;
3561                 if (editorpitch < -.01)
3562                     editorpitch = -.01;
3563             }
3564             if (Input::isKeyPressed(SDLK_DELETE) && objects.numobjects && Input::isKeyDown(SDLK_LSHIFT)) {
3565                 int closest = findClosestObject();
3566                 if (closest >= 0)
3567                     objects.DeleteObject(closest);
3568             }
3569         }
3570     }
3571 }
3572
3573 void doJumpReversals()
3574 {
3575     for (int k = 0; k < Person::players.size(); k++)
3576         for (int i = k; i < Person::players.size(); i++) {
3577             if (i == k)
3578                 continue;
3579             if (     Person::players[k]->skeleton.free == 0 &&
3580                      Person::players[i]->skeleton.oldfree == 0 &&
3581                      (Person::players[i]->animTarget == jumpupanim ||
3582                       Person::players[k]->animTarget == jumpupanim) &&
3583                      (Person::players[i]->aitype == playercontrolled ||
3584                       Person::players[k]->aitype == playercontrolled) &&
3585                      (Person::players[i]->aitype == attacktypecutoff && Person::players[i]->stunned <= 0 ||
3586                       Person::players[k]->aitype == attacktypecutoff && Person::players[k]->stunned <= 0)) {
3587                 if (     distsq(&Person::players[i]->coords, &Person::players[k]->coords) < 10 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5) &&
3588                          distsqflat(&Person::players[i]->coords, &Person::players[k]->coords) < 2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
3589                     //TODO: refactor two huge similar ifs
3590                     if (Person::players[i]->animTarget == jumpupanim &&
3591                             Person::players[k]->animTarget != getupfrombackanim &&
3592                             Person::players[k]->animTarget != getupfromfrontanim &&
3593                             animation[Person::players[k]->animTarget].height == middleheight &&
3594                             normaldotproduct(Person::players[i]->velocity, Person::players[k]->coords - Person::players[i]->coords) < 0 &&
3595                             (Person::players[k]->aitype == playercontrolled && Person::players[k]->attackkeydown ||
3596                              Person::players[k]->aitype != playercontrolled)) {
3597                         Person::players[i]->victim = Person::players[k];
3598                         Person::players[i]->velocity = 0;
3599                         Person::players[i]->animCurrent = jumpreversedanim;
3600                         Person::players[i]->animTarget = jumpreversedanim;
3601                         Person::players[i]->frameCurrent = 0;
3602                         Person::players[i]->frameTarget = 1;
3603                         Person::players[i]->targettilt2 = 0;
3604                         Person::players[k]->victim = Person::players[i];
3605                         Person::players[k]->velocity = 0;
3606                         Person::players[k]->animCurrent = jumpreversalanim;
3607                         Person::players[k]->animTarget = jumpreversalanim;
3608                         Person::players[k]->frameCurrent = 0;
3609                         Person::players[k]->frameTarget = 1;
3610                         Person::players[k]->targettilt2 = 0;
3611                         if (Person::players[i]->coords.y < Person::players[k]->coords.y + 1) {
3612                             Person::players[i]->animCurrent = rabbitkickreversedanim;
3613                             Person::players[i]->animTarget = rabbitkickreversedanim;
3614                             Person::players[i]->frameCurrent = 1;
3615                             Person::players[i]->frameTarget = 2;
3616                             Person::players[k]->animCurrent = rabbitkickreversalanim;
3617                             Person::players[k]->animTarget = rabbitkickreversalanim;
3618                             Person::players[k]->frameCurrent = 1;
3619                             Person::players[k]->frameTarget = 2;
3620                         }
3621                         Person::players[i]->target = 0;
3622                         Person::players[k]->oldcoords = Person::players[k]->coords;
3623                         Person::players[i]->coords = Person::players[k]->coords;
3624                         Person::players[k]->targetyaw = Person::players[i]->targetyaw;
3625                         Person::players[k]->yaw = Person::players[i]->targetyaw;
3626                         if (Person::players[k]->aitype == attacktypecutoff)
3627                             Person::players[k]->stunned = .5;
3628                     }
3629                     if (Person::players[k]->animTarget == jumpupanim &&
3630                             Person::players[i]->animTarget != getupfrombackanim &&
3631                             Person::players[i]->animTarget != getupfromfrontanim &&
3632                             animation[Person::players[i]->animTarget].height == middleheight &&
3633                             normaldotproduct(Person::players[k]->velocity, Person::players[i]->coords - Person::players[k]->coords) < 0 &&
3634                             ((Person::players[i]->aitype == playercontrolled && Person::players[i]->attackkeydown) ||
3635                              Person::players[i]->aitype != playercontrolled)) {
3636                         Person::players[k]->victim = Person::players[i];
3637                         Person::players[k]->velocity = 0;
3638                         Person::players[k]->animCurrent = jumpreversedanim;
3639                         Person::players[k]->animTarget = jumpreversedanim;
3640                         Person::players[k]->frameCurrent = 0;
3641                         Person::players[k]->frameTarget = 1;
3642                         Person::players[k]->targettilt2 = 0;
3643                         Person::players[i]->victim = Person::players[k];
3644                         Person::players[i]->velocity = 0;
3645                         Person::players[i]->animCurrent = jumpreversalanim;
3646                         Person::players[i]->animTarget = jumpreversalanim;
3647                         Person::players[i]->frameCurrent = 0;
3648                         Person::players[i]->frameTarget = 1;
3649                         Person::players[i]->targettilt2 = 0;
3650                         if (Person::players[k]->coords.y < Person::players[i]->coords.y + 1) {
3651                             Person::players[k]->animTarget = rabbitkickreversedanim;
3652                             Person::players[k]->animCurrent = rabbitkickreversedanim;
3653                             Person::players[i]->animCurrent = rabbitkickreversalanim;
3654                             Person::players[i]->animTarget = rabbitkickreversalanim;
3655                             Person::players[k]->frameCurrent = 1;
3656                             Person::players[k]->frameTarget = 2;
3657                             Person::players[i]->frameCurrent = 1;
3658                             Person::players[i]->frameTarget = 2;
3659                         }
3660                         Person::players[k]->target = 0;
3661                         Person::players[i]->oldcoords = Person::players[i]->coords;
3662                         Person::players[k]->coords = Person::players[i]->coords;
3663                         Person::players[i]->targetyaw = Person::players[k]->targetyaw;
3664                         Person::players[i]->yaw = Person::players[k]->targetyaw;
3665                         if (Person::players[i]->aitype == attacktypecutoff)
3666                             Person::players[i]->stunned = .5;
3667                     }
3668                 }
3669             }
3670         }
3671 }
3672
3673 void doAerialAcrobatics()
3674 {
3675     static XYZ facing, flatfacing;
3676     for (int k = 0; k < Person::players.size(); k++) {
3677         Person::players[k]->turnspeed = 500;
3678
3679         if ((Person::players[k]->isRun() &&
3680                 ((Person::players[k]->targetyaw != rabbitrunninganim &&
3681                   Person::players[k]->targetyaw != wolfrunninganim) ||
3682                  Person::players[k]->frameTarget == 4)) ||
3683                 Person::players[k]->animTarget == removeknifeanim ||
3684                 Person::players[k]->animTarget == crouchremoveknifeanim ||
3685                 Person::players[k]->animTarget == flipanim ||
3686                 Person::players[k]->animTarget == fightsidestep ||
3687                 Person::players[k]->animTarget == walkanim) {
3688             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed);
3689         }
3690
3691
3692         if (Person::players[k]->isStop() ||
3693                 Person::players[k]->isLanding() ||
3694                 Person::players[k]->animTarget == staggerbackhighanim ||
3695                 (Person::players[k]->animTarget == sneakanim && Person::players[k]->animCurrent == sneakanim) ||
3696                 Person::players[k]->animTarget == staggerbackhardanim ||
3697                 Person::players[k]->animTarget == backhandspringanim ||
3698                 Person::players[k]->animTarget == dodgebackanim ||
3699                 Person::players[k]->animTarget == rollanim ||
3700                 (animation[Person::players[k]->animTarget].attack &&
3701                  Person::players[k]->animTarget != rabbitkickanim &&
3702                  (Person::players[k]->animTarget != crouchstabanim || Person::players[k]->hasvictim) &&
3703                  (Person::players[k]->animTarget != swordgroundstabanim || Person::players[k]->hasvictim))) {
3704             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed * 2);
3705         }
3706
3707         if (Person::players[k]->animTarget == sneakanim && Person::players[k]->animCurrent != sneakanim) {
3708             Person::players[k]->yaw = stepTowardf(Person::players[k]->yaw, Person::players[k]->targetyaw, multiplier * Person::players[k]->turnspeed * 4);
3709         }
3710
3711         /*if(Person::players[k]->aitype!=passivetype||(distsq(&Person::players[k]->coords,&viewer)<viewdistance*viewdistance))*/
3712         Person::players[k]->DoStuff();
3713         if (Person::players[k]->immobile && k != 0)
3714             Person::players[k]->coords = Person::players[k]->realoldcoords;
3715
3716         //if player's position has changed (?)
3717         if (distsq(&Person::players[k]->coords, &Person::players[k]->realoldcoords) > 0 &&
3718                 !Person::players[k]->skeleton.free &&
3719                 Person::players[k]->animTarget != climbanim &&
3720                 Person::players[k]->animTarget != hanganim) {
3721             XYZ lowpoint, lowpointtarget, lowpoint2, lowpointtarget2, lowpoint3, lowpointtarget3, lowpoint4, lowpointtarget4, lowpoint5, lowpointtarget5, lowpoint6, lowpointtarget6, lowpoint7, lowpointtarget7, colpoint, colpoint2;
3722             int whichhit;
3723             bool tempcollide = 0;
3724
3725             if (Person::players[k]->collide < -.3)
3726                 Person::players[k]->collide = -.3;
3727             if (Person::players[k]->collide > 1)
3728                 Person::players[k]->collide = 1;
3729             Person::players[k]->collide -= multiplier * 30;
3730
3731             //clip to terrain
3732             Person::players[k]->coords.y = max(Person::players[k]->coords.y, terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z));
3733
3734             for (int l = 0; l < terrain.patchobjectnum[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz]; l++) {
3735                 int i = terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz][l];
3736                 if (objects.type[i] != rocktype ||
3737                         objects.scale[i] > .5 && Person::players[k]->aitype == playercontrolled ||
3738                         objects.position[i].y > Person::players[k]->coords.y) {
3739                     lowpoint = Person::players[k]->coords;
3740                     if (Person::players[k]->animTarget != jumpupanim &&
3741                             Person::players[k]->animTarget != jumpdownanim &&
3742                             !Person::players[k]->isFlip())
3743                         lowpoint.y += 1.25;
3744                     else
3745                         lowpoint.y += 1.3;
3746                     if (     Person::players[k]->coords.y < terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z) &&
3747                              Person::players[k]->coords.y > terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z) - .1)
3748                         Person::players[k]->coords.y = terrain.getHeight(Person::players[k]->coords.x, Person::players[k]->coords.z);
3749                     if (Person::players[k]->SphereCheck(&lowpoint, 1.3, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
3750                         flatfacing = lowpoint - Person::players[k]->coords;
3751                         Person::players[k]->coords = lowpoint;
3752                         Person::players[k]->coords.y -= 1.3;
3753                         Person::players[k]->collide = 1;
3754                         tempcollide = 1;
3755                         //wall jumps
3756                         //TODO: refactor four similar blocks
3757                         if (Person::players[k]->aitype == playercontrolled &&
3758                                 (Person::players[k]->animTarget == jumpupanim ||
3759                                  Person::players[k]->animTarget == jumpdownanim ||
3760                                  Person::players[k]->isFlip()) &&
3761                                 !Person::players[k]->jumptogglekeydown &&
3762                                 Person::players[k]->jumpkeydown) {
3763                             lowpointtarget = lowpoint + DoRotation(Person::players[k]->facing, 0, -90, 0) * 1.5;
3764                             XYZ tempcoords1 = lowpoint;
3765                             whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3766                             if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
3767                                 Person::players[k]->setAnimation(walljumpleftanim);
3768                                 emit_sound_at(movewhooshsound, Person::players[k]->coords);
3769                                 if (k == 0)
3770                                     pause_sound(whooshsound);
3771
3772                                 lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3773                                 Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3774                                 if (lowpointtarget.z < 0)
3775                                     Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3776                                 Person::players[k]->targetyaw = Person::players[k]->yaw;
3777                                 Person::players[k]->lowyaw = Person::players[k]->yaw;
3778                                 if (k == 0)
3779                                     numwallflipped++;
3780                             } else {
3781                                 lowpoint = tempcoords1;
3782                                 lowpointtarget = lowpoint + DoRotation(Person::players[k]->facing, 0, 90, 0) * 1.5;
3783                                 whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3784                                 if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
3785                                     Person::players[k]->setAnimation(walljumprightanim);
3786                                     emit_sound_at(movewhooshsound, Person::players[k]->coords);
3787                                     if (k == 0)
3788                                         pause_sound(whooshsound);
3789
3790                                     lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3791                                     Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3792                                     if (lowpointtarget.z < 0)
3793                                         Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3794                                     Person::players[k]->targetyaw = Person::players[k]->yaw;
3795                                     Person::players[k]->lowyaw = Person::players[k]->yaw;
3796                                     if (k == 0)
3797                                         numwallflipped++;
3798                                 } else {
3799                                     lowpoint = tempcoords1;
3800                                     lowpointtarget = lowpoint + Person::players[k]->facing * 2;
3801                                     whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3802                                     if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
3803                                         Person::players[k]->setAnimation(walljumpbackanim);
3804                                         emit_sound_at(movewhooshsound, Person::players[k]->coords);
3805                                         if (k == 0)
3806                                             pause_sound(whooshsound);
3807
3808                                         lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3809                                         Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3810                                         if (lowpointtarget.z < 0)
3811                                             Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3812                                         Person::players[k]->targetyaw = Person::players[k]->yaw;
3813                                         Person::players[k]->lowyaw = Person::players[k]->yaw;
3814                                         if (k == 0)
3815                                             numwallflipped++;
3816                                     } else {
3817                                         lowpoint = tempcoords1;
3818                                         lowpointtarget = lowpoint - Person::players[k]->facing * 2;
3819                                         whichhit = objects.model[i].LineCheck(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3820                                         if (whichhit != -1 && fabs(objects.model[i].facenormals[whichhit].y) < .3) {
3821                                             Person::players[k]->setAnimation(walljumpfrontanim);
3822                                             emit_sound_at(movewhooshsound, Person::players[k]->coords);
3823                                             if (k == 0)
3824                                                 pause_sound(whooshsound);
3825
3826                                             lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3827                                             Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3828                                             if (lowpointtarget.z < 0)
3829                                                 Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3830                                             Person::players[k]->yaw += 180;
3831                                             Person::players[k]->targetyaw = Person::players[k]->yaw;
3832                                             Person::players[k]->lowyaw = Person::players[k]->yaw;
3833                                             if (k == 0)
3834                                                 numwallflipped++;
3835                                         }
3836                                     }
3837                                 }
3838                             }
3839                         }
3840                     }
3841                 } else if (objects.type[i] == rocktype) {
3842                     lowpoint2 = Person::players[k]->coords;
3843                     lowpoint = Person::players[k]->coords;
3844                     lowpoint.y += 2;
3845                     if (objects.model[i].LineCheck(&lowpoint, &lowpoint2, &colpoint, &objects.position[i], &objects.yaw[i]) != -1) {
3846                         Person::players[k]->coords = colpoint;
3847                         Person::players[k]->collide = 1;
3848                         tempcollide = 1;
3849
3850                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) {
3851                             //flipped into a rock
3852                             if (Person::players[k]->isFlip() && animation[Person::players[k]->animTarget].label[Person::players[k]->frameTarget] == 7)
3853                                 Person::players[k]->RagDoll(0);
3854
3855                             if (Person::players[k]->animTarget == jumpupanim) {
3856                                 Person::players[k]->jumppower = -4;
3857                                 Person::players[k]->animTarget = Person::players[k]->getIdle();
3858                             }
3859                             Person::players[k]->target = 0;
3860                             Person::players[k]->frameTarget = 0;
3861                             Person::players[k]->onterrain = 1;
3862
3863                             if (Person::players[k]->id == 0) {
3864                                 pause_sound(whooshsound);
3865                                 OPENAL_SetVolume(channels[whooshsound], 0);
3866                             }
3867
3868                             //landing
3869                             if ((Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) && !Person::players[k]->wasLanding()) {
3870                                 if (Person::players[k]->isFlip())
3871                                     Person::players[k]->jumppower = -4;
3872                                 Person::players[k]->animTarget = Person::players[k]->getLanding();
3873                                 emit_sound_at(landsound, Person::players[k]->coords, 128.);
3874                                 if (k == 0) {
3875                                     envsound[numenvsounds] = Person::players[k]->coords;
3876                                     envsoundvol[numenvsounds] = 16;
3877                                     envsoundlife[numenvsounds] = .4;
3878                                     numenvsounds++;
3879                                 }
3880
3881                             }
3882                         }
3883                     }
3884                 }
3885             }
3886
3887             if (tempcollide && (/*Person::players[k]->jumptogglekeydown*/1 == 1 || Person::players[k]->aitype != playercontrolled))
3888                 for (int l = 0; l < terrain.patchobjectnum[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz]; l++) {
3889                     int i = terrain.patchobjects[Person::players[k]->whichpatchx][Person::players[k]->whichpatchz][l];
3890                     lowpoint = Person::players[k]->coords;
3891                     lowpoint.y += 1.35;
3892                     if (objects.type[i] != rocktype)
3893                         if (Person::players[k]->SphereCheck(&lowpoint, 1.33, &colpoint, &objects.position[i], &objects.yaw[i], &objects.model[i]) != -1) {
3894                             if (Person::players[k]->animTarget != jumpupanim &&
3895                                     Person::players[k]->animTarget != jumpdownanim &&
3896                                     Person::players[k]->onterrain)
3897                                 Person::players[k]->avoidcollided = 1;
3898                             Person::players[k]->coords = lowpoint;
3899                             Person::players[k]->coords.y -= 1.35;
3900                             Person::players[k]->collide = 1;
3901
3902                             if ((Person::players[k]->grabdelay <= 0 || Person::players[k]->aitype != playercontrolled) &&
3903                                     (Person::players[k]->animCurrent != climbanim &&
3904                                      Person::players[k]->animCurrent != hanganim &&
3905                                      !Person::players[k]->isWallJump() ||
3906                                      Person::players[k]->animTarget == jumpupanim ||
3907                                      Person::players[k]->animTarget == jumpdownanim)) {
3908                                 lowpoint = Person::players[k]->coords;
3909                                 objects.model[i].SphereCheckPossible(&lowpoint, 1.5, &objects.position[i], &objects.yaw[i]);
3910                                 lowpoint = Person::players[k]->coords;
3911                                 lowpoint.y += .05;
3912                                 facing = 0;
3913                                 facing.z = -1;
3914                                 facing = DoRotation(facing, 0, Person::players[k]->targetyaw + 180, 0);
3915                                 lowpointtarget = lowpoint + facing * 1.4;
3916                                 whichhit = objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3917                                 if (whichhit != -1) {
3918                                     lowpoint = Person::players[k]->coords;
3919                                     lowpoint.y += .1;
3920                                     lowpointtarget = lowpoint + facing * 1.4;
3921                                     lowpoint2 = lowpoint;
3922                                     lowpointtarget2 = lowpointtarget;
3923                                     lowpoint3 = lowpoint;
3924                                     lowpointtarget3 = lowpointtarget;
3925                                     lowpoint4 = lowpoint;
3926                                     lowpointtarget4 = lowpointtarget;
3927                                     lowpoint5 = lowpoint;
3928                                     lowpointtarget5 = lowpointtarget;
3929                                     lowpoint6 = lowpoint;
3930                                     lowpointtarget6 = lowpointtarget;
3931                                     lowpoint7 = lowpoint;
3932                                     lowpointtarget7 = lowpoint;
3933                                     lowpoint2.x += .1;
3934                                     lowpointtarget2.x += .1;
3935                                     lowpoint3.z += .1;
3936                                     lowpointtarget3.z += .1;
3937                                     lowpoint4.x -= .1;
3938                                     lowpointtarget4.x -= .1;
3939                                     lowpoint5.z -= .1;
3940                                     lowpointtarget5.z -= .1;
3941                                     lowpoint6.y += 45 / 13;
3942                                     lowpointtarget6.y += 45 / 13;
3943                                     lowpointtarget6 += facing * .6;
3944                                     lowpointtarget7.y += 90 / 13;
3945                                     whichhit = objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget, &colpoint, &objects.position[i], &objects.yaw[i]);
3946                                     if (objects.friction[i] > .5)
3947                                         if (whichhit != -1) {
3948                                             if (whichhit != -1 && Person::players[k]->animTarget != jumpupanim && Person::players[k]->animTarget != jumpdownanim)
3949                                                 Person::players[k]->collided = 1;
3950                                             if (checkcollide(lowpoint7, lowpointtarget7) == -1)
3951                                                 if (checkcollide(lowpoint6, lowpointtarget6) == -1)
3952                                                     if (     objects.model[i].LineCheckPossible(&lowpoint2, &lowpointtarget2,
3953                                                              &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3954                                                              objects.model[i].LineCheckPossible(&lowpoint3, &lowpointtarget3,
3955                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3956                                                              objects.model[i].LineCheckPossible(&lowpoint4, &lowpointtarget4,
3957                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1 &&
3958                                                              objects.model[i].LineCheckPossible(&lowpoint5, &lowpointtarget5,
3959                                                                      &colpoint, &objects.position[i], &objects.yaw[i]) != -1)
3960                                                         for (int j = 0; j < 45; j++) {
3961                                                             lowpoint = Person::players[k]->coords;
3962                                                             lowpoint.y += (float)j / 13;
3963                                                             lowpointtarget = lowpoint + facing * 1.4;
3964                                                             if (objects.model[i].LineCheckPossible(&lowpoint, &lowpointtarget,
3965                                                                                                    &colpoint2, &objects.position[i], &objects.yaw[i]) == -1) {
3966                                                                 if (j <= 6 || j <= 25 && Person::players[k]->animTarget == jumpdownanim)
3967                                                                     break;
3968                                                                 if (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim) {
3969                                                                     lowpoint = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[k], 0);
3970                                                                     lowpoint = Person::players[k]->coords;
3971                                                                     lowpoint.y += (float)j / 13;
3972                                                                     lowpointtarget = lowpoint + facing * 1.3;
3973                                                                     flatfacing = Person::players[k]->coords;
3974                                                                     Person::players[k]->coords = colpoint - DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[k], 0) * .01;
3975                                                                     Person::players[k]->coords.y = lowpointtarget.y - .07;
3976                                                                     Person::players[k]->currentoffset = (flatfacing - Person::players[k]->coords) / Person::players[k]->scale;
3977
3978                                                                     if (j > 10 || !Person::players[k]->isRun()) {
3979                                                                         if (Person::players[k]->animTarget == jumpdownanim || Person::players[k]->animTarget == jumpupanim) {
3980                                                                             if (k == 0)
3981                                                                                 pause_sound(whooshsound);
3982                                                                         }
3983                                                                         emit_sound_at(jumpsound, Person::players[k]->coords, 128.);
3984
3985                                                                         lowpointtarget = DoRotation(objects.model[i].facenormals[whichhit], 0, objects.yaw[i], 0);
3986                                                                         Person::players[k]->yaw = -asin(0 - lowpointtarget.x) * 180 / M_PI;
3987                                                                         if (lowpointtarget.z < 0)
3988                                                                             Person::players[k]->yaw = 180 - Person::players[k]->yaw;
3989                                                                         Person::players[k]->targetyaw = Person::players[k]->yaw;
3990                                                                         Person::players[k]->lowyaw = Person::players[k]->yaw;
3991
3992                                                                         //Person::players[k]->velocity=lowpointtarget*.03;
3993                                                                         Person::players[k]->velocity = 0;
3994
3995                                                                         //climb ledge (?)
3996                                                                         if (Person::players[k]->animTarget == jumpupanim) {
3997                                                                             Person::players[k]->animTarget = climbanim;
3998                                                                             Person::players[k]->jumppower = 0;
3999                                                                             Person::players[k]->jumpclimb = 1;
4000                                                                         }
4001                                                                         Person::players[k]->transspeed = 6;
4002                                                                         Person::players[k]->target = 0;
4003                                                                         Person::players[k]->frameTarget = 1;
4004                                                                         //hang ledge (?)
4005                                                                         if (j > 25) {
4006                                                                             Person::players[k]->setAnimation(hanganim);
4007                                                                             Person::players[k]->jumppower = 0;
4008                                                                         }
4009                                                                     }
4010                                                                     break;
4011                                                                 }
4012                                                             }
4013                                                         }
4014                                         }
4015                                 }
4016                             }
4017                         }
4018                 }
4019             if (Person::players[k]->collide <= 0) {
4020                 //in the air
4021                 if (!Person::players[k]->onterrain &&
4022                         Person::players[k]->animTarget != jumpupanim &&
4023                         Person::players[k]->animTarget != jumpdownanim &&
4024                         Person::players[k]->animTarget != climbanim &&
4025                         Person::players[k]->animTarget != hanganim &&
4026                         !Person::players[k]->isWallJump() &&
4027                         !Person::players[k]->isFlip()) {
4028                     if (Person::players[k]->animCurrent != climbanim &&
4029                             Person::players[k]->animCurrent != tempanim &&
4030                             Person::players[k]->animTarget != backhandspringanim &&
4031                             (Person::players[k]->animTarget != rollanim ||
4032                              Person::players[k]->frameTarget < 2 ||
4033                              Person::players[k]->frameTarget > 6)) {
4034                         //stagger off ledge (?)
4035                         if (Person::players[k]->animTarget == staggerbackhighanim || Person::players[k]->animTarget == staggerbackhardanim)
4036                             Person::players[k]->RagDoll(0);
4037                         Person::players[k]->setAnimation(jumpdownanim);
4038
4039                         if (!k)
4040                             emit_sound_at(whooshsound, Person::players[k]->coords, 128.);
4041                     }
4042                     //gravity
4043                     Person::players[k]->velocity.y += gravity;
4044                 }
4045             }
4046         }
4047         Person::players[k]->realoldcoords = Person::players[k]->coords;
4048     }
4049 }
4050
4051 void doAttacks()
4052 {
4053     static XYZ relative;
4054     static int randattack;
4055     static bool playerrealattackkeydown = 0;
4056
4057     if (!Input::isKeyDown(attackkey))
4058         oldattackkey = 0;
4059     if (oldattackkey)
4060         Person::players[0]->attackkeydown = 0;
4061     if (oldattackkey)
4062         playerrealattackkeydown = 0;
4063     if (!oldattackkey)
4064         playerrealattackkeydown = Input::isKeyDown(attackkey);
4065     if ((Person::players[0]->parriedrecently <= 0 ||
4066             Person::players[0]->weaponactive == -1) &&
4067             (!oldattackkey ||
4068              (realthreat &&
4069               Person::players[0]->lastattack != swordslashanim &&
4070               Person::players[0]->lastattack != knifeslashstartanim &&
4071               Person::players[0]->lastattack != staffhitanim &&
4072               Person::players[0]->lastattack != staffspinhitanim)))
4073         Person::players[0]->attackkeydown = Input::isKeyDown(attackkey);
4074     if (Input::isKeyDown(attackkey) &&
4075             !oldattackkey &&
4076             !Person::players[0]->backkeydown) {
4077         for (int k = 0; k < Person::players.size(); k++) {
4078             if ((Person::players[k]->animTarget == swordslashanim ||
4079                     Person::players[k]->animTarget == staffhitanim ||
4080                     Person::players[k]->animTarget == staffspinhitanim) &&
4081                     Person::players[0]->animCurrent != dodgebackanim &&
4082                     !Person::players[k]->skeleton.free)
4083                 Person::players[k]->Reverse();
4084         }
4085     }
4086
4087     if (!hostile || indialogue != -1)
4088         Person::players[0]->attackkeydown = 0;
4089
4090     for (int k = 0; k < Person::players.size(); k++) {
4091         if (indialogue != -1)
4092             Person::players[k]->attackkeydown = 0;
4093         if (Person::players[k]->animTarget != rabbitrunninganim && Person::players[k]->animTarget != wolfrunninganim) {
4094             if (Person::players[k]->aitype != playercontrolled)
4095                 Person::players[k]->victim = Person::players[0];
4096             //attack key pressed
4097             if (Person::players[k]->attackkeydown) {
4098                 //dodge backward
4099                 if (Person::players[k]->backkeydown &&
4100                         Person::players[k]->animTarget != backhandspringanim &&
4101                         (Person::players[k]->isIdle() ||
4102                          Person::players[k]->isStop() ||
4103                          Person::players[k]->isRun() ||
4104                          Person::players[k]->animTarget == walkanim)) {
4105                     if (Person::players[k]->jumppower <= 1) {
4106                         Person::players[k]->jumppower -= 2;
4107                     } else {
4108                         for (int i = 0; i < Person::players.size(); i++) {
4109                             if (i == k)
4110                                 continue;
4111                             if (Person::players[i]->animTarget == swordslashanim ||
4112                                     Person::players[i]->animTarget == knifeslashstartanim ||
4113                                     Person::players[i]->animTarget == staffhitanim ||
4114                                     Person::players[i]->animTarget == staffspinhitanim)
4115                                 if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < 6.5 && !Person::players[i]->skeleton.free) {
4116                                     Person::players[k]->setAnimation(dodgebackanim);
4117                                     Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
4118                                     Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
4119                                 }
4120                         }
4121                         if (Person::players[k]->animTarget != dodgebackanim) {
4122                             if (k == 0)
4123                                 numflipped++;
4124                             Person::players[k]->setAnimation(backhandspringanim);
4125                             Person::players[k]->targetyaw = -yaw + 180;
4126                             if (Person::players[k]->leftkeydown)
4127                                 Person::players[k]->targetyaw -= 45;
4128                             if (Person::players[k]->rightkeydown)
4129                                 Person::players[k]->targetyaw += 45;
4130                             Person::players[k]->yaw = Person::players[k]->targetyaw;
4131                             Person::players[k]->jumppower -= 2;
4132                         }
4133                     }
4134                 }
4135                 //attack
4136                 if (!animation[Person::players[k]->animTarget].attack &&
4137                         !Person::players[k]->backkeydown &&
4138                         (Person::players[k]->isIdle() ||
4139                          Person::players[k]->isRun() ||
4140                          Person::players[k]->animTarget == walkanim ||
4141                          Person::players[k]->animTarget == sneakanim ||
4142                          Person::players[k]->isCrouch())) {
4143                     const int attackweapon = Person::players[k]->weaponactive == -1 ? 0 : weapons[Person::players[k]->weaponids[Person::players[k]->weaponactive]].getType();
4144                     //normal attacks (?)
4145                     Person::players[k]->hasvictim = 0;
4146                     if (Person::players.size() > 1)
4147                         for (int i = 0; i < Person::players.size(); i++) {
4148                             if (i == k || !(k == 0 || i == 0))
4149                                 continue;
4150                             if (!Person::players[k]->hasvictim)
4151                                 if (animation[Person::players[k]->animTarget].attack != reversal) {
4152                                     //choose an attack
4153                                     const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
4154                                     if (distance < 4.5 &&
4155                                             !Person::players[i]->skeleton.free &&
4156                                             Person::players[i]->howactive < typedead1 &&
4157                                             Person::players[i]->animTarget != jumpreversedanim &&
4158                                             Person::players[i]->animTarget != rabbitkickreversedanim &&
4159                                             Person::players[i]->animTarget != rabbitkickanim &&
4160                                             Person::players[k]->animTarget != rabbitkickanim &&
4161                                             Person::players[i]->animTarget != getupfrombackanim &&
4162                                             (Person::players[i]->animTarget != staggerbackhighanim &&
4163                                              (Person::players[i]->animTarget != staggerbackhardanim ||
4164                                               animation[staggerbackhardanim].label[Person::players[i]->frameTarget] == 6)) &&
4165                                             Person::players[i]->animTarget != jumpdownanim &&
4166                                             Person::players[i]->animTarget != jumpupanim &&
4167                                             Person::players[i]->animTarget != getupfromfrontanim) {
4168                                         Person::players[k]->victim = Person::players[i];
4169                                         Person::players[k]->hasvictim = 1;
4170                                         if (Person::players[k]->aitype == playercontrolled) { //human player
4171                                             //sweep
4172                                             if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4173                                                     Person::players[k]->crouchkeydown &&
4174                                                     animation[Person::players[i]->animTarget].height != lowheight)
4175                                                 Person::players[k]->animTarget = sweepanim;
4176                                             //winduppunch
4177                                             else if (distance < 1.5 * sq(Person::players[k]->scale * 5) &&
4178                                                      animation[Person::players[i]->animTarget].height != lowheight &&
4179                                                      !Person::players[k]->forwardkeydown &&
4180                                                      !Person::players[k]->leftkeydown &&
4181                                                      !Person::players[k]->rightkeydown &&
4182                                                      !Person::players[k]->crouchkeydown &&
4183                                                      !attackweapon &&
4184                                                      !reversaltrain)
4185                                                 Person::players[k]->animTarget = winduppunchanim;
4186                                             //upunch
4187                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4188                                                      animation[Person::players[i]->animTarget].height != lowheight &&
4189                                                      !Person::players[k]->forwardkeydown &&
4190                                                      !Person::players[k]->leftkeydown &&
4191                                                      !Person::players[k]->rightkeydown &&
4192                                                      !Person::players[k]->crouchkeydown &&
4193                                                      !attackweapon)
4194                                                 Person::players[k]->animTarget = upunchanim;
4195                                             //knifefollow
4196                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4197                                                      Person::players[i]->staggerdelay > 0 &&
4198                                                      attackweapon == knife &&
4199                                                      Person::players[i]->bloodloss > Person::players[i]->damagetolerance / 2)
4200                                                 Person::players[k]->animTarget = knifefollowanim;
4201                                             //knifeslashstart
4202                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4203                                                      animation[Person::players[i]->animTarget].height != lowheight &&
4204                                                      !Person::players[k]->forwardkeydown &&
4205                                                      !Person::players[k]->leftkeydown &&
4206                                                      !Person::players[k]->rightkeydown &&
4207                                                      !Person::players[k]->crouchkeydown &&
4208                                                      attackweapon == knife &&
4209                                                      Person::players[k]->weaponmissdelay <= 0)
4210                                                 Person::players[k]->animTarget = knifeslashstartanim;
4211                                             //swordslash
4212                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
4213                                                      animation[Person::players[i]->animTarget].height != lowheight &&
4214                                                      !Person::players[k]->crouchkeydown &&
4215                                                      attackweapon == sword &&
4216                                                      Person::players[k]->weaponmissdelay <= 0)
4217                                                 Person::players[k]->animTarget = swordslashanim;
4218                                             //staffhit
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 == staff &&
4223                                                      Person::players[k]->weaponmissdelay <= 0 &&
4224                                                      !Person::players[k]->leftkeydown &&
4225                                                      !Person::players[k]->rightkeydown &&
4226                                                      !Person::players[k]->forwardkeydown)
4227                                                 Person::players[k]->animTarget = staffhitanim;
4228                                             //staffspinhit
4229                                             else if (distance < 4.5 * sq(Person::players[k]->scale * 5) &&
4230                                                      animation[Person::players[i]->animTarget].height != lowheight &&
4231                                                      !Person::players[k]->crouchkeydown &&
4232                                                      attackweapon == staff &&
4233                                                      Person::players[k]->weaponmissdelay <= 0)
4234                                                 Person::players[k]->animTarget = staffspinhitanim;
4235                                             //spinkick
4236                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4237                                                      animation[Person::players[i]->animTarget].height != lowheight)
4238                                                 Person::players[k]->animTarget = spinkickanim;
4239                                             //lowkick
4240                                             else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4241                                                      animation[Person::players[i]->animTarget].height == lowheight &&
4242                                                      animation[Person::players[k]->animTarget].attack != normalattack)
4243                                                 Person::players[k]->animTarget = lowkickanim;
4244                                         } else { //AI player
4245                                             if (distance < 4.5 * sq(Person::players[k]->scale * 5)) {
4246                                                 randattack = abs(Random() % 5);
4247                                                 if (!attackweapon && distance < 2.5 * sq(Person::players[k]->scale * 5)) {
4248                                                     //sweep
4249                                                     if (randattack == 0 && animation[Person::players[i]->animTarget].height != lowheight)
4250                                                         Person::players[k]->animTarget = sweepanim;
4251                                                     //upunch
4252                                                     else if (randattack == 1 && animation[Person::players[i]->animTarget].height != lowheight &&
4253                                                              !attackweapon)
4254                                                         Person::players[k]->animTarget = upunchanim;
4255                                                     //spinkick
4256                                                     else if (randattack == 2 && animation[Person::players[i]->animTarget].height != lowheight)
4257                                                         Person::players[k]->animTarget = spinkickanim;
4258                                                     //lowkick
4259                                                     else if (animation[Person::players[i]->animTarget].height == lowheight)
4260                                                         Person::players[k]->animTarget = lowkickanim;
4261                                                 }
4262                                                 if (attackweapon) {
4263                                                     //sweep
4264                                                     if ((tutoriallevel != 1 || !attackweapon) &&
4265                                                             distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4266                                                             randattack == 0 &&
4267                                                             animation[Person::players[i]->animTarget].height != lowheight)
4268                                                         Person::players[k]->animTarget = sweepanim;
4269                                                     //knifeslashstart
4270                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4271                                                              attackweapon == knife &&
4272                                                              Person::players[k]->weaponmissdelay <= 0)
4273                                                         Person::players[k]->animTarget = knifeslashstartanim;
4274                                                     //swordslash
4275                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
4276                                                                Person::players[0]->hasvictim &&
4277                                                                Person::players[0]->animTarget == swordslashanim) &&
4278                                                              attackweapon == sword &&
4279                                                              Person::players[k]->weaponmissdelay <= 0)
4280                                                         Person::players[k]->animTarget = swordslashanim;
4281                                                     //staffhit
4282                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
4283                                                                Person::players[0]->hasvictim &&
4284                                                                Person::players[0]->animTarget == swordslashanim) &&
4285                                                              attackweapon == staff &&
4286                                                              Person::players[k]->weaponmissdelay <= 0 &&
4287                                                              randattack < 3)
4288                                                         Person::players[k]->animTarget = staffhitanim;
4289                                                     //staffspinhit
4290                                                     else if (!(Person::players[0]->victim == Person::players[i] &&
4291                                                                Person::players[0]->hasvictim &&
4292                                                                Person::players[0]->animTarget == swordslashanim) &&
4293                                                              attackweapon == staff &&
4294                                                              Person::players[k]->weaponmissdelay <= 0 &&
4295                                                              randattack >= 3)
4296                                                         Person::players[k]->animTarget = staffspinhitanim;
4297                                                     //spinkick
4298                                                     else if ((tutoriallevel != 1 || !attackweapon) &&
4299                                                              distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4300                                                              randattack == 1 &&
4301                                                              animation[Person::players[i]->animTarget].height != lowheight)
4302                                                         Person::players[k]->animTarget = spinkickanim;
4303                                                     //lowkick
4304                                                     else if (distance < 2.5 * sq(Person::players[k]->scale * 5) &&
4305                                                              animation[Person::players[i]->animTarget].height == lowheight &&
4306                                                              animation[Person::players[k]->animTarget].attack != normalattack)
4307                                                         Person::players[k]->animTarget = lowkickanim;
4308                                                 }
4309                                             }
4310                                         }
4311                                         //upunch becomes wolfslap
4312                                         if (Person::players[k]->animTarget == upunchanim && Person::players[k]->creature == wolftype)
4313                                             Person::players[k]->animTarget = wolfslapanim;
4314                                     }
4315                                     //sneak attacks
4316                                     if ((k == 0) && (tutoriallevel != 1 || tutorialstage == 22) &&
4317                                             Person::players[i]->howactive < typedead1 &&
4318                                             distance < 1.5 * sq(Person::players[k]->scale * 5) &&
4319                                             !Person::players[i]->skeleton.free &&
4320                                             Person::players[i]->animTarget != getupfrombackanim &&
4321                                             Person::players[i]->animTarget != getupfromfrontanim &&
4322                                             (Person::players[i]->stunned > 0 && Person::players[k]->madskills ||
4323                                              Person::players[i]->surprised > 0 ||
4324                                              Person::players[i]->aitype == passivetype ||
4325                                              attackweapon && Person::players[i]->stunned > 0) &&
4326                                             normaldotproduct(Person::players[i]->facing, Person::players[i]->coords - Person::players[k]->coords) > 0) {
4327                                         //sneakattack
4328                                         if (!attackweapon) {
4329                                             Person::players[k]->animCurrent = sneakattackanim;
4330                                             Person::players[k]->animTarget = sneakattackanim;
4331                                             Person::players[i]->animCurrent = sneakattackedanim;
4332                                             Person::players[i]->animTarget = sneakattackedanim;
4333                                             Person::players[k]->oldcoords = Person::players[k]->coords;
4334                                             Person::players[k]->coords = Person::players[i]->coords;
4335                                         }
4336                                         //knifesneakattack
4337                                         if (attackweapon == knife) {
4338                                             Person::players[k]->animCurrent = knifesneakattackanim;
4339                                             Person::players[k]->animTarget = knifesneakattackanim;
4340                                             Person::players[i]->animCurrent = knifesneakattackedanim;
4341                                             Person::players[i]->animTarget = knifesneakattackedanim;
4342                                             Person::players[i]->oldcoords = Person::players[i]->coords;
4343                                             Person::players[i]->coords = Person::players[k]->coords;
4344                                         }
4345                                         //swordsneakattack
4346                                         if (attackweapon == sword) {
4347                                             Person::players[k]->animCurrent = swordsneakattackanim;
4348                                             Person::players[k]->animTarget = swordsneakattackanim;
4349                                             Person::players[i]->animCurrent = swordsneakattackedanim;
4350                                             Person::players[i]->animTarget = swordsneakattackedanim;
4351                                             Person::players[i]->oldcoords = Person::players[i]->coords;
4352                                             Person::players[i]->coords = Person::players[k]->coords;
4353                                         }
4354                                         if (attackweapon != staff) {
4355                                             Person::players[k]->victim = Person::players[i];
4356                                             Person::players[k]->hasvictim = 1;
4357                                             Person::players[i]->targettilt2 = 0;
4358                                             Person::players[i]->frameTarget = 1;
4359                                             Person::players[i]->frameCurrent = 0;
4360                                             Person::players[i]->target = 0;
4361                                             Person::players[i]->velocity = 0;
4362                                             Person::players[k]->targettilt2 = Person::players[i]->targettilt2;
4363                                             Person::players[k]->frameCurrent = Person::players[i]->frameCurrent;
4364                                             Person::players[k]->frameTarget = Person::players[i]->frameTarget;
4365                                             Person::players[k]->target = Person::players[i]->target;
4366                                             Person::players[k]->velocity = 0;
4367                                             Person::players[k]->targetyaw = Person::players[i]->yaw;
4368                                             Person::players[k]->yaw = Person::players[i]->yaw;
4369                                             Person::players[i]->targetyaw = Person::players[i]->yaw;
4370                                         }
4371                                     }
4372                                     if (animation[Person::players[k]->animTarget].attack == normalattack &&
4373                                             Person::players[k]->victim == Person::players[i] &&
4374                                             (!Person::players[i]->skeleton.free)) {
4375                                         oldattackkey = 1;
4376                                         Person::players[k]->frameTarget = 0;
4377                                         Person::players[k]->target = 0;
4378
4379                                         Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
4380                                         Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
4381                                         Person::players[k]->lastattack3 = Person::players[k]->lastattack2;
4382                                         Person::players[k]->lastattack2 = Person::players[k]->lastattack;
4383                                         Person::players[k]->lastattack = Person::players[k]->animTarget;
4384                                     }
4385                                     if (Person::players[k]->animTarget == knifefollowanim &&
4386                                             Person::players[k]->victim == Person::players[i]) {
4387                                         oldattackkey = 1;
4388                                         Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, Person::players[i]->coords);
4389                                         Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, Person::players[i]->coords);
4390                                         Person::players[k]->victim = Person::players[i];
4391                                         Person::players[k]->hasvictim = 1;
4392                                         Person::players[i]->animTarget = knifefollowedanim;
4393                                         Person::players[i]->animCurrent = knifefollowedanim;
4394                                         Person::players[i]->targettilt2 = 0;
4395                                         Person::players[i]->targettilt2 = Person::players[k]->targettilt2;
4396                                         Person::players[i]->frameTarget = 1;
4397                                         Person::players[i]->frameCurrent = 0;
4398                                         Person::players[i]->target = 0;
4399                                         Person::players[i]->velocity = 0;
4400                                         Person::players[k]->animCurrent = knifefollowanim;
4401                                         Person::players[k]->animTarget = knifefollowanim;
4402                                         Person::players[k]->targettilt2 = Person::players[i]->targettilt2;
4403                                         Person::players[k]->frameCurrent = Person::players[i]->frameCurrent;
4404                                         Person::players[k]->frameTarget = Person::players[i]->frameTarget;
4405                                         Person::players[k]->target = Person::players[i]->target;
4406                                         Person::players[k]->velocity = 0;
4407                                         Person::players[k]->oldcoords = Person::players[k]->coords;
4408                                         Person::players[i]->coords = Person::players[k]->coords;
4409                                         Person::players[i]->targetyaw = Person::players[k]->targetyaw;
4410                                         Person::players[i]->yaw = Person::players[k]->targetyaw;
4411                                         Person::players[k]->yaw = Person::players[k]->targetyaw;
4412                                         Person::players[i]->yaw = Person::players[k]->targetyaw;
4413                                     }
4414                                 }
4415                         }
4416                     const bool hasstaff = attackweapon == staff;
4417                     if (k == 0 && Person::players.size() > 1)
4418                         for (int i = 0; i < Person::players.size(); i++) {
4419                             if (i == k)
4420                                 continue;
4421                             if ((playerrealattackkeydown || Person::players[i]->dead || !hasstaff) &&
4422                                     animation[Person::players[k]->animTarget].attack == neutral) {
4423                                 const float distance = distsq(&Person::players[k]->coords, &Person::players[i]->coords);
4424                                 if (!Person::players[i]->dead || !realthreat || (!attackweapon && Person::players[k]->crouchkeydown))
4425                                     if (Person::players[i]->skeleton.free)
4426                                         if (distance < 3.5 * sq(Person::players[k]->scale * 5) &&
4427                                                 (Person::players[i]->dead ||
4428                                                  Person::players[i]->skeleton.longdead > 1000 ||
4429                                                  Person::players[k]->isRun() ||
4430                                                  hasstaff ||
4431                                                  (attackweapon &&
4432                                                   (Person::players[i]->skeleton.longdead > 2000 ||
4433                                                    Person::players[i]->damage > Person::players[i]->damagetolerance / 8 ||
4434                                                    Person::players[i]->bloodloss > Person::players[i]->damagetolerance / 2) &&
4435                                                   distance < 1.5 * sq(Person::players[k]->scale * 5)))) {
4436                                             Person::players[k]->victim = Person::players[i];
4437                                             Person::players[k]->hasvictim = 1;
4438                                             if (attackweapon && tutoriallevel != 1) {
4439                                                 //crouchstab
4440                                                 if (Person::players[k]->crouchkeydown && attackweapon == knife && distance < 1.5 * sq(Person::players[k]->scale * 5))
4441                                                     Person::players[k]->animTarget = crouchstabanim;
4442                                                 //swordgroundstab
4443                                                 if (Person::players[k]->crouchkeydown && distance < 1.5 * sq(Person::players[k]->scale * 5) && attackweapon == sword)
4444                                                     Person::players[k]->animTarget = swordgroundstabanim;
4445                                                 //staffgroundsmash
4446                                                 if (distance < 3.5 * sq(Person::players[k]->scale * 5) && attackweapon == staff)
4447                                                     Person::players[k]->animTarget = staffgroundsmashanim;
4448                                             }
4449                                             if (distance < 2.5 &&
4450                                                     Person::players[k]->crouchkeydown &&
4451                                                     Person::players[k]->animTarget != crouchstabanim &&
4452                                                     !attackweapon &&
4453                                                     Person::players[i]->dead &&
4454                                                     Person::players[i]->skeleton.free &&
4455                                                     Person::players[i]->skeleton.longdead > 1000) {
4456                                                 Person::players[k]->animTarget = killanim;
4457                                                 //TODO: refactor this out, what does it do?
4458                                                 for (int j = 0; j < terrain.numdecals; j++) {
4459                                                     if ((terrain.decaltype[j] == blooddecal || terrain.decaltype[j] == blooddecalslow) &&
4460                                                             terrain.decalalivetime[j] < 2)
4461                                                         terrain.DeleteDecal(j);
4462                                                 }
4463                                                 for (int l = 0; l < objects.numobjects; l++) {
4464                                                     if (objects.model[l].type == decalstype)
4465                                                         for (int j = 0; j < objects.model[l].numdecals; j++) {
4466                                                             if ((objects.model[l].decaltype[j] == blooddecal ||
4467                                                                     objects.model[l].decaltype[j] == blooddecalslow) &&
4468                                                                     objects.model[l].decalalivetime[j] < 2)
4469                                                                 objects.model[l].DeleteDecal(j);
4470                                                         }
4471                                                 }
4472                                             }
4473                                             if (!Person::players[i]->dead || musictype != 2)
4474                                                 if (distance < 3.5 &&
4475                                                         (Person::players[k]->isRun() || Person::players[k]->isIdle() && Person::players[k]->attackkeydown) &&
4476                                                         Person::players[k]->staggerdelay <= 0 &&
4477                                                         (Person::players[i]->dead ||
4478                                                          Person::players[i]->skeleton.longdead < 300 &&
4479                                                          Person::players[k]->lastattack != spinkickanim &&
4480                                                          Person::players[i]->skeleton.free) &&
4481                                                         (!Person::players[i]->dead || musictype != stream_fighttheme)) {
4482                                                     Person::players[k]->animTarget = dropkickanim;
4483                                                     for (int j = 0; j < terrain.numdecals; j++) {
4484                                                         if ((terrain.decaltype[j] == blooddecal || terrain.decaltype[j] == blooddecalslow) &&
4485                                                                 terrain.decalalivetime[j] < 2) {
4486                                                             terrain.DeleteDecal(j);
4487                                                         }
4488                                                     }
4489                                                     for (int l = 0; l < objects.numobjects; l++) {
4490                                                         if (objects.model[l].type == decalstype)
4491                                                             for (int j = 0; j < objects.model[l].numdecals; j++) {
4492                                                                 if ((objects.model[l].decaltype[j] == blooddecal ||
4493                                                                         objects.model[l].decaltype[j] == blooddecalslow) &&
4494                                                                         objects.model[l].decalalivetime[j] < 2) {
4495                                                                     objects.model[l].DeleteDecal(j);
4496                                                                 }
4497                                                             }
4498                                                     }
4499                                                 }
4500                                         }
4501                                 if (animation[Person::players[k]->animTarget].attack == normalattack &&
4502                                         Person::players[k]->victim == Person::players[i] &&
4503                                         (!Person::players[i]->skeleton.free ||
4504                                          Person::players[k]->animTarget == killanim ||
4505                                          Person::players[k]->animTarget == crouchstabanim ||
4506                                          Person::players[k]->animTarget == swordgroundstabanim ||
4507                                          Person::players[k]->animTarget == staffgroundsmashanim ||
4508                                          Person::players[k]->animTarget == dropkickanim)) {
4509                                     oldattackkey = 1;
4510                                     Person::players[k]->frameTarget = 0;
4511                                     Person::players[k]->target = 0;
4512
4513                                     XYZ targetpoint = Person::players[i]->coords;
4514                                     if (Person::players[k]->animTarget == crouchstabanim ||
4515                                             Person::players[k]->animTarget == swordgroundstabanim ||
4516                                             Person::players[k]->animTarget == staffgroundsmashanim) {
4517                                         targetpoint += (Person::players[i]->jointPos(abdomen) +
4518                                                         Person::players[i]->jointPos(neck)) / 2 *
4519                                                        Person::players[i]->scale;
4520                                     }
4521                                     Person::players[k]->targetyaw = roughDirectionTo(Person::players[k]->coords, targetpoint);
4522                                     Person::players[k]->targettilt2 = pitchTo(Person::players[k]->coords, targetpoint);
4523
4524                                     if (Person::players[k]->animTarget == crouchstabanim || Person::players[k]->animTarget == swordgroundstabanim) {
4525                                         Person::players[k]->targetyaw += (float)(abs(Random() % 100) - 50) / 4;
4526                                     }
4527
4528                                     if (Person::players[k]->animTarget == staffgroundsmashanim)
4529                                         Person::players[k]->targettilt2 += 10;
4530
4531                                     Person::players[k]->lastattack3 = Person::players[k]->lastattack2;
4532                                     Person::players[k]->lastattack2 = Person::players[k]->lastattack;
4533                                     Person::players[k]->lastattack = Person::players[k]->animTarget;
4534
4535                                     if (Person::players[k]->animTarget == swordgroundstabanim) {
4536                                         Person::players[k]->targetyaw += 30;
4537                                     }
4538                                 }
4539                             }
4540                         }
4541                     if (!Person::players[k]->hasvictim) {
4542                         //find victim
4543                         for (int i = 0; i < Person::players.size(); i++) {
4544                             if (i == k || !(i == 0 || k == 0))
4545                                 continue;
4546                             if (!Person::players[i]->skeleton.free) {
4547                                 if (Person::players[k]->hasvictim) {
4548                                     if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) <
4549                                             distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords))
4550                                         Person::players[k]->victim = Person::players[i];
4551                                 } else {
4552                                     Person::players[k]->victim = Person::players[i];
4553                                     Person::players[k]->hasvictim = 1;
4554                                 }
4555                             }
4556                         }
4557                     }
4558                     if (Person::players[k]->aitype == playercontrolled)
4559                         //rabbit kick
4560                         if (Person::players[k]->attackkeydown &&
4561                                 Person::players[k]->isRun() &&
4562                                 Person::players[k]->wasRun() &&
4563                                 ((Person::players[k]->hasvictim &&
4564                                   distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords) < 12 * sq(Person::players[k]->scale * 5) &&
4565                                   distsq(&Person::players[k]->coords, &Person::players[k]->victim->coords) > 7 * sq(Person::players[k]->scale * 5) &&
4566                                   !Person::players[k]->victim->skeleton.free &&
4567                                   Person::players[k]->victim->animTarget != getupfrombackanim &&
4568                                   Person::players[k]->victim->animTarget != getupfromfrontanim &&
4569                                   animation[Person::players[k]->victim->animTarget].height != lowheight &&
4570                                   Person::players[k]->aitype != playercontrolled && //wat???
4571                                   normaldotproduct(Person::players[k]->facing, Person::players[k]->victim->coords - Person::players[k]->coords) > 0 &&
4572                                   Person::players[k]->rabbitkickenabled) ||
4573                                  Person::players[k]->jumpkeydown)) {
4574                             oldattackkey = 1;
4575                             Person::players[k]->setAnimation(rabbitkickanim);
4576                         }
4577                     //update counts
4578                     if (animation[Person::players[k]->animTarget].attack && k == 0) {
4579                         numattacks++;
4580                         switch (attackweapon) {
4581                         case 0:
4582                             numunarmedattack++;
4583                             break;
4584                         case knife:
4585                             numknifeattack++;
4586                             break;
4587                         case sword:
4588                             numswordattack++;
4589                             break;
4590                         case staff:
4591                             numstaffattack++;
4592                             break;
4593                         }
4594                     }
4595                 }
4596             }
4597         }
4598     }
4599 }
4600
4601 void doPlayerCollisions()
4602 {
4603     static XYZ rotatetarget;
4604     static float collisionradius;
4605     if (Person::players.size() > 1)
4606         for (int k = 0; k < Person::players.size(); k++)
4607             for (int i = k + 1; i < Person::players.size(); i++) {
4608                 //neither player is part of a reversal
4609                 if ((animation[Person::players[i]->animTarget].attack != reversed &&
4610                         animation[Person::players[i]->animTarget].attack != reversal &&
4611                         animation[Person::players[k]->animTarget].attack != reversed &&
4612                         animation[Person::players[k]->animTarget].attack != reversal) || (i != 0 && k != 0))
4613                     if ((animation[Person::players[i]->animCurrent].attack != reversed &&
4614                             animation[Person::players[i]->animCurrent].attack != reversal &&
4615                             animation[Person::players[k]->animCurrent].attack != reversed &&
4616                             animation[Person::players[k]->animCurrent].attack != reversal) || (i != 0 && k != 0))
4617                         //neither is sleeping
4618                         if (Person::players[i]->howactive <= typesleeping && Person::players[k]->howactive <= typesleeping)
4619                             if (Person::players[i]->howactive != typesittingwall && Person::players[k]->howactive != typesittingwall)
4620                                 //in same patch, neither is climbing
4621                                 if (Person::players[i]->whichpatchx == Person::players[k]->whichpatchx &&
4622                                         Person::players[i]->whichpatchz == Person::players[k]->whichpatchz &&
4623                                         Person::players[k]->skeleton.oldfree == Person::players[k]->skeleton.free &&
4624                                         Person::players[i]->skeleton.oldfree == Person::players[i]->skeleton.free &&
4625                                         Person::players[i]->animTarget != climbanim &&
4626                                         Person::players[i]->animTarget != hanganim &&
4627                                         Person::players[k]->animTarget != climbanim &&
4628                                         Person::players[k]->animTarget != hanganim)
4629                                     //players are close (bounding box test)
4630                                     if (Person::players[i]->coords.y > Person::players[k]->coords.y - 3)
4631                                         if (Person::players[i]->coords.y < Person::players[k]->coords.y + 3)
4632                                             if (Person::players[i]->coords.x > Person::players[k]->coords.x - 3)
4633                                                 if (Person::players[i]->coords.x < Person::players[k]->coords.x + 3)
4634                                                     if (Person::players[i]->coords.z > Person::players[k]->coords.z - 3)
4635                                                         if (Person::players[i]->coords.z < Person::players[k]->coords.z + 3) {
4636                                                             //spread fire from player to player
4637                                                             if (distsq(&Person::players[i]->coords, &Person::players[k]->coords)
4638                                                                     < 3 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
4639                                                                 if (Person::players[i]->onfire || Person::players[k]->onfire) {
4640                                                                     if (!Person::players[i]->onfire)
4641                                                                         Person::players[i]->CatchFire();
4642                                                                     if (!Person::players[k]->onfire)
4643                                                                         Person::players[k]->CatchFire();
4644                                                                 }
4645                                                             }
4646
4647                                                             XYZ tempcoords1 = Person::players[i]->coords;
4648                                                             XYZ tempcoords2 = Person::players[k]->coords;
4649                                                             if (!Person::players[i]->skeleton.oldfree)
4650                                                                 tempcoords1.y += Person::players[i]->jointPos(abdomen).y * Person::players[i]->scale;
4651                                                             if (!Person::players[k]->skeleton.oldfree)
4652                                                                 tempcoords2.y += Person::players[k]->jointPos(abdomen).y * Person::players[k]->scale;
4653                                                             collisionradius = 1.2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
4654                                                             if (Person::players[0]->hasvictim)
4655                                                                 if (Person::players[0]->animTarget == rabbitkickanim && (k == 0 || i == 0) && !Person::players[0]->victim->skeleton.free)
4656                                                                     collisionradius = 3;
4657                                                             if ((!Person::players[i]->skeleton.oldfree || !Person::players[k]->skeleton.oldfree) &&
4658                                                                     (distsq(&tempcoords1, &tempcoords2) < collisionradius ||
4659                                                                      distsq(&Person::players[i]->coords, &Person::players[k]->coords) < collisionradius)) {
4660                                                                 //jump down on a dead body
4661                                                                 if (k == 0 || i == 0) {
4662                                                                     int l = i ? i : k;
4663                                                                     if (Person::players[0]->animTarget == jumpdownanim &&
4664                                                                             !Person::players[0]->skeleton.oldfree &&
4665                                                                             !Person::players[0]->skeleton.free &&
4666                                                                             Person::players[l]->skeleton.oldfree &&
4667                                                                             Person::players[l]->skeleton.free &&
4668                                                                             Person::players[l]->dead &&
4669                                                                             Person::players[0]->lastcollide <= 0 &&
4670                                                                             fabs(Person::players[l]->coords.y - Person::players[0]->coords.y) < .2 &&
4671                                                                             distsq(&Person::players[0]->coords, &Person::players[l]->coords) < .7 * sq((Person::players[l]->scale + Person::players[0]->scale) * 2.5)) {
4672                                                                         Person::players[0]->coords.y = Person::players[l]->coords.y;
4673                                                                         Person::players[l]->velocity = Person::players[0]->velocity;
4674                                                                         Person::players[l]->skeleton.free = 0;
4675                                                                         Person::players[l]->yaw = 0;
4676                                                                         Person::players[l]->RagDoll(0);
4677                                                                         Person::players[l]->DoDamage(20);
4678                                                                         camerashake += .3;
4679                                                                         Person::players[l]->skeleton.longdead = 0;
4680                                                                         Person::players[0]->lastcollide = 1;
4681                                                                     }
4682                                                                 }
4683
4684                                                                 if (     (Person::players[i]->skeleton.oldfree == 1 && findLengthfast(&Person::players[i]->velocity) > 1) ||
4685                                                                          (Person::players[k]->skeleton.oldfree == 1 && findLengthfast(&Person::players[k]->velocity) > 1) ||
4686                                                                          (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0)) {
4687                                                                     rotatetarget = Person::players[k]->velocity - Person::players[i]->velocity;
4688                                                                     if ((Person::players[i]->animTarget != getupfrombackanim && Person::players[i]->animTarget != getupfromfrontanim ||
4689                                                                             Person::players[i]->skeleton.free) &&
4690                                                                             (Person::players[k]->animTarget != getupfrombackanim && Person::players[k]->animTarget != getupfromfrontanim ||
4691                                                                              Person::players[k]->skeleton.free))
4692                                                                         if ((((k != 0 && findLengthfast(&rotatetarget) > 150 ||
4693                                                                                 k == 0 && findLengthfast(&rotatetarget) > 50 && Person::players[0]->rabbitkickragdoll) &&
4694                                                                                 normaldotproduct(rotatetarget, Person::players[k]->coords - Person::players[i]->coords) > 0) &&
4695                                                                                 (k == 0 ||
4696                                                                                  k != 0 && Person::players[i]->skeleton.oldfree == 1 && animation[Person::players[k]->animCurrent].attack == neutral ||
4697                                                                                  /*i!=0&&*/Person::players[k]->skeleton.oldfree == 1 && animation[Person::players[i]->animCurrent].attack == neutral)) ||
4698                                                                                 (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) &&
4699                                                                                 (Person::players[k]->animTarget == jumpupanim || Person::players[k]->animTarget == jumpdownanim || Person::players[k]->isFlip()) &&
4700                                                                                 k == 0 && !Person::players[i]->skeleton.oldfree && !Person::players[k]->skeleton.oldfree) {
4701                                                                             //If hit by body
4702                                                                             if (     (i != 0 || Person::players[i]->skeleton.free) &&
4703                                                                                      (k != 0 || Person::players[k]->skeleton.free) ||
4704                                                                                      (animation[Person::players[i]->animTarget].height == highheight &&
4705                                                                                       animation[Person::players[k]->animTarget].height == highheight)) {
4706                                                                                 if (tutoriallevel != 1) {
4707                                                                                     emit_sound_at(heavyimpactsound, Person::players[i]->coords);
4708                                                                                 }
4709
4710                                                                                 Person::players[i]->RagDoll(0);
4711                                                                                 if (Person::players[i]->damage > Person::players[i]->damagetolerance - findLengthfast(&rotatetarget) / 4 && !Person::players[i]->dead) {
4712                                                                                     award_bonus(0, aimbonus);
4713                                                                                 }
4714                                                                                 Person::players[i]->DoDamage(findLengthfast(&rotatetarget) / 4);
4715                                                                                 Person::players[k]->RagDoll(0);
4716                                                                                 if (Person::players[k]->damage > Person::players[k]->damagetolerance - findLengthfast(&rotatetarget) / 4 && !Person::players[k]->dead) {
4717                                                                                     award_bonus(0, aimbonus); // Huh, again?
4718                                                                                 }
4719                                                                                 Person::players[k]->DoDamage(findLengthfast(&rotatetarget) / 4);
4720
4721                                                                                 for (int j = 0; j < Person::players[i]->skeleton.num_joints; j++) {
4722                                                                                     Person::players[i]->skeleton.joints[j].velocity = Person::players[i]->skeleton.joints[j].velocity / 5 + Person::players[k]->velocity;
4723                                                                                 }
4724                                                                                 for (int j = 0; j < Person::players[k]->skeleton.num_joints; j++) {
4725                                                                                     Person::players[k]->skeleton.joints[j].velocity = Person::players[k]->skeleton.joints[j].velocity / 5 + Person::players[i]->velocity;
4726                                                                                 }
4727
4728                                                                             }
4729                                                                         }
4730                                                                     if (     (animation[Person::players[i]->animTarget].attack == neutral ||
4731                                                                               animation[Person::players[i]->animTarget].attack == normalattack) &&
4732                                                                              (animation[Person::players[k]->animTarget].attack == neutral ||
4733                                                                               animation[Person::players[k]->animTarget].attack == normalattack)) {
4734                                                                         //If bumped
4735                                                                         if (Person::players[i]->skeleton.oldfree == 0 && Person::players[k]->skeleton.oldfree == 0) {
4736                                                                             if (distsq(&Person::players[k]->coords, &Person::players[i]->coords) < .5 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5)) {
4737                                                                                 rotatetarget = Person::players[k]->coords - Person::players[i]->coords;
4738                                                                                 Normalise(&rotatetarget);
4739                                                                                 Person::players[k]->coords = (Person::players[k]->coords + Person::players[i]->coords) / 2;
4740                                                                                 Person::players[i]->coords = Person::players[k]->coords - rotatetarget * fast_sqrt(.6) / 2
4741                                                                                                    * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
4742                                                                                 Person::players[k]->coords += rotatetarget * fast_sqrt(.6) / 2 * sq((Person::players[i]->scale + Person::players[k]->scale) * 2.5);
4743                                                                                 if (Person::players[k]->howactive == typeactive || hostile)
4744                                                                                     if (Person::players[k]->isIdle()) {
4745                                                                                         if (Person::players[k]->howactive < typesleeping)
4746                                                                                             Person::players[k]->setAnimation(Person::players[k]->getStop());
4747                                                                                         else if (Person::players[k]->howactive == typesleeping)
4748                                                                                             Person::players[k]->setAnimation(getupfromfrontanim);
4749                                                                                         if (!editorenabled)
4750                                                                                             Person::players[k]->howactive = typeactive;
4751                                                                                     }
4752                                                                                 if (Person::players[i]->howactive == typeactive || hostile)
4753                                                                                     if (Person::players[i]->isIdle()) {
4754                                                                                         if (Person::players[i]->howactive < typesleeping)
4755                                                                                             Person::players[i]->setAnimation(Person::players[k]->getStop());
4756                                                                                         else
4757                                                                                             Person::players[i]->setAnimation(getupfromfrontanim);
4758                                                                                         if (!editorenabled)
4759                                                                                             Person::players[i]->howactive = typeactive;
4760                                                                                     }
4761                                                                             }
4762                                                                             //jump down on player
4763                                                                             if (hostile) {
4764                                                                                 if (k == 0 && i != 0 && Person::players[k]->animTarget == jumpdownanim &&
4765                                                                                         !Person::players[i]->isCrouch() &&
4766                                                                                         Person::players[i]->animTarget != rollanim &&
4767                                                                                         !Person::players[k]->skeleton.oldfree && !
4768                                                                                         Person::players[k]->skeleton.free &&
4769                                                                                         Person::players[k]->lastcollide <= 0 &&
4770                                                                                         Person::players[k]->velocity.y < -10) {
4771                                                                                     Person::players[i]->velocity = Person::players[k]->velocity;
4772                                                                                     Person::players[k]->velocity = Person::players[k]->velocity * -.5;
4773                                                                                     Person::players[k]->velocity.y = Person::players[i]->velocity.y;
4774                                                                                     Person::players[i]->DoDamage(20);
4775                                                                                     Person::players[i]->RagDoll(0);
4776                                                                                     Person::players[k]->lastcollide = 1;
4777                                                                                     award_bonus(k, AboveBonus);
4778                                                                                 }
4779                                                                                 if (i == 0 && k != 0 && Person::players[i]->animTarget == jumpdownanim &&
4780                                                                                         !Person::players[k]->isCrouch() &&
4781                                                                                         Person::players[k]->animTarget != rollanim &&
4782                                                                                         !Person::players[i]->skeleton.oldfree &&
4783                                                                                         !Person::players[i]->skeleton.free &&
4784                                                                                         Person::players[i]->lastcollide <= 0 &&
4785                                                                                         Person::players[i]->velocity.y < -10) {
4786                                                                                     Person::players[k]->velocity = Person::players[i]->velocity;
4787                                                                                     Person::players[i]->velocity = Person::players[i]->velocity * -.3;
4788                                                                                     Person::players[i]->velocity.y = Person::players[k]->velocity.y;
4789                                                                                     Person::players[k]->DoDamage(20);
4790                                                                                     Person::players[k]->RagDoll(0);
4791                                                                                     Person::players[i]->lastcollide = 1;
4792                                                                                     award_bonus(i, AboveBonus);
4793                                                                                 }
4794                                                                             }
4795                                                                         }
4796                                                                     }
4797                                                                 }
4798                                                                 Person::players[i]->CheckKick();
4799                                                                 Person::players[k]->CheckKick();
4800                                                             }
4801                                                         }
4802             }
4803 }
4804
4805 void doAI(int i)
4806 {
4807     static bool connected;
4808     if (Person::players[i]->aitype != playercontrolled && indialogue == -1) {
4809         Person::players[i]->jumpclimb = 0;
4810         //disable movement in editor
4811         if (editorenabled)
4812             Person::players[i]->stunned = 1;
4813
4814         Person::players[i]->pause = 0;
4815         if (distsqflat(&Person::players[0]->coords, &Person::players[i]->coords) < 30 &&
4816                 Person::players[0]->coords.y > Person::players[i]->coords.y + 2 &&
4817                 !Person::players[0]->onterrain)
4818             Person::players[i]->pause = 1;
4819
4820         //pathfinding
4821         if (Person::players[i]->aitype == pathfindtype) {
4822             if (Person::players[i]->finalpathfindpoint == -1) {
4823                 float closestdistance;
4824                 float tempdist;
4825                 int closest;
4826                 XYZ colpoint;
4827                 closest = -1;
4828                 closestdistance = -1;
4829                 for (int j = 0; j < numpathpoints; j++)
4830                     if (closest == -1 || distsq(&Person::players[i]->finalfinaltarget, &pathpoint[j]) < closestdistance) {
4831                         closestdistance = distsq(&Person::players[i]->finalfinaltarget, &pathpoint[j]);
4832                         closest = j;
4833                         Person::players[i]->finaltarget = pathpoint[j];
4834                     }
4835                 Person::players[i]->finalpathfindpoint = closest;
4836                 for (int j = 0; j < numpathpoints; j++)
4837                     for (int k = 0; k < numpathpointconnect[j]; k++) {
4838                         DistancePointLine(&Person::players[i]->finalfinaltarget, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist, &colpoint );
4839                         if (sq(tempdist) < closestdistance)
4840                             if (findDistance(&colpoint, &pathpoint[j]) + findDistance(&colpoint, &pathpoint[pathpointconnect[j][k]]) <
4841                                     findDistance(&pathpoint[j], &pathpoint[pathpointconnect[j][k]]) + .1) {
4842                                 closestdistance = sq(tempdist);
4843                                 closest = j;
4844                                 Person::players[i]->finaltarget = colpoint;
4845                             }
4846                     }
4847                 Person::players[i]->finalpathfindpoint = closest;
4848
4849             }
4850             if (Person::players[i]->targetpathfindpoint == -1) {
4851                 float closestdistance;
4852                 float tempdist;
4853                 int closest;
4854                 XYZ colpoint;
4855                 closest = -1;
4856                 closestdistance = -1;
4857                 if (Person::players[i]->lastpathfindpoint == -1) {
4858                     for (int j = 0; j < numpathpoints; j++) {
4859                         if (j != Person::players[i]->lastpathfindpoint)
4860                             if (closest == -1 || (distsq(&Person::players[i]->coords, &pathpoint[j]) < closestdistance)) {
4861                                 closestdistance = distsq(&Person::players[i]->coords, &pathpoint[j]);
4862                                 closest = j;
4863                             }
4864                     }
4865                     Person::players[i]->targetpathfindpoint = closest;
4866                     for (int j = 0; j < numpathpoints; j++)
4867                         if (j != Person::players[i]->lastpathfindpoint)
4868                             for (int k = 0; k < numpathpointconnect[j]; k++) {
4869                                 DistancePointLine(&Person::players[i]->coords, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist, &colpoint );
4870                                 if (sq(tempdist) < closestdistance) {
4871                                     if (findDistance(&colpoint, &pathpoint[j]) + findDistance(&colpoint, &pathpoint[pathpointconnect[j][k]]) <
4872                                             findDistance(&pathpoint[j], &pathpoint[pathpointconnect[j][k]]) + .1) {
4873                                         closestdistance = sq(tempdist);
4874                                         closest = j;
4875                                     }
4876                                 }
4877                             }
4878                     Person::players[i]->targetpathfindpoint = closest;
4879                 } else {
4880                     for (int j = 0; j < numpathpoints; j++)
4881                         if (j != Person::players[i]->lastpathfindpoint &&
4882                                 j != Person::players[i]->lastpathfindpoint2 &&
4883                                 j != Person::players[i]->lastpathfindpoint3 &&
4884                                 j != Person::players[i]->lastpathfindpoint4) {
4885                             connected = 0;
4886                             if (numpathpointconnect[j])
4887                                 for (int k = 0; k < numpathpointconnect[j]; k++)
4888                                     if (pathpointconnect[j][k] == Person::players[i]->lastpathfindpoint)
4889                                         connected = 1;
4890                             if (!connected)
4891                                 if (numpathpointconnect[Person::players[i]->lastpathfindpoint])
4892                                     for (int k = 0; k < numpathpointconnect[Person::players[i]->lastpathfindpoint]; k++)
4893                                         if (pathpointconnect[Person::players[i]->lastpathfindpoint][k] == j)
4894                                             connected = 1;
4895                             if (connected) {
4896                                 tempdist = findPathDist(j, Person::players[i]->finalpathfindpoint);
4897                                 if (closest == -1 || tempdist < closestdistance) {
4898                                     closestdistance = tempdist;
4899                                     closest = j;
4900                                 }
4901                             }
4902                         }
4903                     Person::players[i]->targetpathfindpoint = closest;
4904                 }
4905             }
4906             Person::players[i]->losupdatedelay -= multiplier;
4907
4908             Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, pathpoint[Person::players[i]->targetpathfindpoint]);
4909             Person::players[i]->lookyaw = Person::players[i]->targetyaw;
4910
4911             //reached target point
4912             if (distsqflat(&Person::players[i]->coords, &pathpoint[Person::players[i]->targetpathfindpoint]) < .6) {
4913                 Person::players[i]->lastpathfindpoint4 = Person::players[i]->lastpathfindpoint3;
4914                 Person::players[i]->lastpathfindpoint3 = Person::players[i]->lastpathfindpoint2;
4915                 Person::players[i]->lastpathfindpoint2 = Person::players[i]->lastpathfindpoint;
4916                 Person::players[i]->lastpathfindpoint = Person::players[i]->targetpathfindpoint;
4917                 if (Person::players[i]->lastpathfindpoint2 == -1)
4918                     Person::players[i]->lastpathfindpoint2 = Person::players[i]->lastpathfindpoint;
4919                 if (Person::players[i]->lastpathfindpoint3 == -1)
4920                     Person::players[i]->lastpathfindpoint3 = Person::players[i]->lastpathfindpoint2;
4921                 if (Person::players[i]->lastpathfindpoint4 == -1)
4922                     Person::players[i]->lastpathfindpoint4 = Person::players[i]->lastpathfindpoint3;
4923                 Person::players[i]->targetpathfindpoint = -1;
4924             }
4925             if (     distsqflat(&Person::players[i]->coords, &Person::players[i]->finalfinaltarget) <
4926                      distsqflat(&Person::players[i]->coords, &Person::players[i]->finaltarget) ||
4927                      distsqflat(&Person::players[i]->coords, &Person::players[i]->finaltarget) < .6 * sq(Person::players[i]->scale * 5) ||
4928                      Person::players[i]->lastpathfindpoint == Person::players[i]->finalpathfindpoint) {
4929                 Person::players[i]->aitype = passivetype;
4930             }
4931
4932             Person::players[i]->forwardkeydown = 1;
4933             Person::players[i]->leftkeydown = 0;
4934             Person::players[i]->backkeydown = 0;
4935             Person::players[i]->rightkeydown = 0;
4936             Person::players[i]->crouchkeydown = 0;
4937             Person::players[i]->attackkeydown = 0;
4938             Person::players[i]->throwkeydown = 0;
4939
4940             if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8)
4941                 Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
4942
4943             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
4944                 Person::players[i]->jumpkeydown = 0;
4945             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
4946                 Person::players[i]->jumpkeydown = 1;
4947
4948             if ((tutoriallevel != 1 || cananger) &&
4949                     hostile &&
4950                     !Person::players[0]->dead &&
4951                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
4952                     Person::players[i]->occluded < 25) {
4953                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
4954                         animation[Person::players[0]->animTarget].height != lowheight &&
4955                         !editorenabled &&
4956                         (Person::players[0]->coords.y < Person::players[i]->coords.y + 5 || Person::players[0]->onterrain))
4957                     Person::players[i]->aitype = attacktypecutoff;
4958                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
4959                         animation[Person::players[0]->animTarget].height == highheight &&
4960                         !editorenabled)
4961                     Person::players[i]->aitype = attacktypecutoff;
4962
4963                 if (Person::players[i]->losupdatedelay < 0 && !editorenabled && Person::players[i]->occluded < 2) {
4964                     Person::players[i]->losupdatedelay = .2;
4965                     for (int j = 0; j < Person::players.size(); j++)
4966                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype)
4967                             if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
4968                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
4969                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
4970                                         if (Person::players[j]->coords.y < Person::players[i]->coords.y + 5 || Person::players[j]->onterrain)
4971                                             if (!Person::players[j]->isWallJump() && -1 == checkcollide(
4972                                                         DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)
4973                                                         *Person::players[i]->scale + Person::players[i]->coords,
4974                                                         DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0)
4975                                                         *Person::players[j]->scale + Person::players[j]->coords) ||
4976                                                     (Person::players[j]->animTarget == hanganim &&
4977                                                      normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
4978                                                 Person::players[i]->aitype = searchtype;
4979                                                 Person::players[i]->lastchecktime = 12;
4980                                                 Person::players[i]->lastseen = Person::players[j]->coords;
4981                                                 Person::players[i]->lastseentime = 12;
4982                                             }
4983                 }
4984             }
4985             if (Person::players[i]->aitype == attacktypecutoff && musictype != 2)
4986                 if (Person::players[i]->creature != wolftype) {
4987                     Person::players[i]->stunned = .6;
4988                     Person::players[i]->surprised = .6;
4989                 }
4990         }
4991
4992         if (Person::players[i]->aitype != passivetype && leveltime > .5)
4993             Person::players[i]->howactive = typeactive;
4994
4995         if (Person::players[i]->aitype == passivetype) {
4996             Person::players[i]->aiupdatedelay -= multiplier;
4997             Person::players[i]->losupdatedelay -= multiplier;
4998             Person::players[i]->lastseentime += multiplier;
4999             Person::players[i]->pausetime -= multiplier;
5000             if (Person::players[i]->lastseentime > 1)
5001                 Person::players[i]->lastseentime = 1;
5002
5003             if (Person::players[i]->aiupdatedelay < 0) {
5004                 if (Person::players[i]->numwaypoints > 1 && Person::players[i]->howactive == typeactive && Person::players[i]->pausetime <= 0) {
5005                     Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[i]->waypoints[Person::players[i]->waypoint]);
5006                     Person::players[i]->lookyaw = Person::players[i]->targetyaw;
5007                     Person::players[i]->aiupdatedelay = .05;
5008
5009                     if (distsqflat(&Person::players[i]->coords, &Person::players[i]->waypoints[Person::players[i]->waypoint]) < 1) {
5010                         if (Person::players[i]->waypointtype[Person::players[i]->waypoint] == wppause)
5011                             Person::players[i]->pausetime = 4;
5012                         Person::players[i]->waypoint++;
5013                         if (Person::players[i]->waypoint > Person::players[i]->numwaypoints - 1)
5014                             Person::players[i]->waypoint = 0;
5015
5016                     }
5017                 }
5018
5019                 if (Person::players[i]->numwaypoints > 1 && Person::players[i]->howactive == typeactive && Person::players[i]->pausetime <= 0)
5020                     Person::players[i]->forwardkeydown = 1;
5021                 else
5022                     Person::players[i]->forwardkeydown = 0;
5023                 Person::players[i]->leftkeydown = 0;
5024                 Person::players[i]->backkeydown = 0;
5025                 Person::players[i]->rightkeydown = 0;
5026                 Person::players[i]->crouchkeydown = 0;
5027                 Person::players[i]->attackkeydown = 0;
5028                 Person::players[i]->throwkeydown = 0;
5029
5030                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
5031                     if (!Person::players[i]->avoidsomething)
5032                         Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
5033                     else {
5034                         XYZ leftpos, rightpos;
5035                         float leftdist, rightdist;
5036                         leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
5037                         rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
5038                         leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
5039                         rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
5040                         if (leftdist < rightdist)
5041                             Person::players[i]->targetyaw += 90;
5042                         else
5043                             Person::players[i]->targetyaw -= 90;
5044                     }
5045                 }
5046             }
5047             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
5048                 Person::players[i]->jumpkeydown = 0;
5049             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
5050                 Person::players[i]->jumpkeydown = 1;
5051
5052
5053             //hearing sounds
5054             if (!editorenabled) {
5055                 if (Person::players[i]->howactive <= typesleeping)
5056                     if (numenvsounds > 0 && (tutoriallevel != 1 || cananger) && hostile)
5057                         for (int j = 0; j < numenvsounds; j++) {
5058                             float vol = Person::players[i]->howactive == typesleeping ? envsoundvol[j] - 14 : envsoundvol[j];
5059                             if (vol > 0 && distsq(&Person::players[i]->coords, &envsound[j]) <
5060                                     2 * (vol + vol * (Person::players[i]->creature == rabbittype) * 3))
5061                                 Person::players[i]->aitype = attacktypecutoff;
5062                         }
5063
5064                 if (Person::players[i]->aitype != passivetype) {
5065                     if (Person::players[i]->howactive == typesleeping)
5066                         Person::players[i]->setAnimation(getupfromfrontanim);
5067                     Person::players[i]->howactive = typeactive;
5068                 }
5069             }
5070
5071             if (Person::players[i]->howactive < typesleeping &&
5072                     ((tutoriallevel != 1 || cananger) && hostile) &&
5073                     !Person::players[0]->dead &&
5074                     distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400 &&
5075                     Person::players[i]->occluded < 25) {
5076                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 12 &&
5077                         animation[Person::players[0]->animTarget].height != lowheight && !editorenabled)
5078                     Person::players[i]->aitype = attacktypecutoff;
5079                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 30 &&
5080                         animation[Person::players[0]->animTarget].height == highheight && !editorenabled)
5081                     Person::players[i]->aitype = attacktypecutoff;
5082
5083                 //wolf smell
5084                 if (Person::players[i]->creature == wolftype) {
5085                     XYZ windsmell;
5086                     for (int j = 0; j < Person::players.size(); j++) {
5087                         if (j == 0 || (Person::players[j]->dead && Person::players[j]->bloodloss > 0)) {
5088                             float smelldistance = 50;
5089                             if (j == 0 && Person::players[j]->num_weapons > 0) {
5090                                 if (weapons[Person::players[j]->weaponids[0]].bloody)
5091                                     smelldistance = 100;
5092                                 if (Person::players[j]->num_weapons == 2)
5093                                     if (weapons[Person::players[j]->weaponids[1]].bloody)
5094                                         smelldistance = 100;
5095                             }
5096                             if (j != 0)
5097                                 smelldistance = 100;
5098                             windsmell = windvector;
5099                             Normalise(&windsmell);
5100                             windsmell = windsmell * 2 + Person::players[j]->coords;
5101                             if (distsq(&Person::players[i]->coords, &windsmell) < smelldistance && !editorenabled)
5102                                 Person::players[i]->aitype = attacktypecutoff;
5103                         }
5104                     }
5105                 }
5106
5107                 if (Person::players[i]->howactive < typesleeping && Person::players[i]->losupdatedelay < 0 && !editorenabled && Person::players[i]->occluded < 2) {
5108                     Person::players[i]->losupdatedelay = .2;
5109                     for (int j = 0; j < Person::players.size(); j++) {
5110                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
5111                             if (abs(Random() % 2) || animation[Person::players[j]->animTarget].height != lowheight || j != 0)
5112                                 if (distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 400)
5113                                     if (normaldotproduct(Person::players[i]->facing, Person::players[j]->coords - Person::players[i]->coords) > 0)
5114                                         if ((-1 == checkcollide(
5115                                                     DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)*
5116                                                     Person::players[i]->scale + Person::players[i]->coords,
5117                                                     DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0)*
5118                                                     Person::players[j]->scale + Person::players[j]->coords) &&
5119                                                 !Person::players[j]->isWallJump()) ||
5120                                                 (Person::players[j]->animTarget == hanganim &&
5121                                                  normaldotproduct(Person::players[j]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0)) {
5122                                             Person::players[i]->lastseentime -= .2;
5123                                             if (j == 0 && animation[Person::players[j]->animTarget].height == lowheight)
5124                                                 Person::players[i]->lastseentime -= .4;
5125                                             else
5126                                                 Person::players[i]->lastseentime -= .6;
5127                                         }
5128                             if (Person::players[i]->lastseentime <= 0) {
5129                                 Person::players[i]->aitype = searchtype;
5130                                 Person::players[i]->lastchecktime = 12;
5131                                 Person::players[i]->lastseen = Person::players[j]->coords;
5132                                 Person::players[i]->lastseentime = 12;
5133                             }
5134                         }
5135                     }
5136                 }
5137             }
5138             //alerted surprise
5139             if (Person::players[i]->aitype == attacktypecutoff && musictype != 2) {
5140                 if (Person::players[i]->creature != wolftype) {
5141                     Person::players[i]->stunned = .6;
5142                     Person::players[i]->surprised = .6;
5143                 }
5144                 if (Person::players[i]->creature == wolftype) {
5145                     Person::players[i]->stunned = .47;
5146                     Person::players[i]->surprised = .47;
5147                 }
5148                 numseen++;
5149             }
5150         }
5151
5152         //search for player
5153         int j;
5154         if (Person::players[i]->aitype == searchtype) {
5155             Person::players[i]->aiupdatedelay -= multiplier;
5156             Person::players[i]->losupdatedelay -= multiplier;
5157             if (!Person::players[i]->pause)
5158                 Person::players[i]->lastseentime -= multiplier;
5159             Person::players[i]->lastchecktime -= multiplier;
5160
5161             if (Person::players[i]->isRun() && !Person::players[i]->onground) {
5162                 if (Person::players[i]->coords.y > terrain.getHeight(Person::players[i]->coords.x, Person::players[i]->coords.z) + 10) {
5163                     XYZ test2 = Person::players[i]->coords + Person::players[i]->facing;
5164                     test2.y += 5;
5165                     XYZ test = Person::players[i]->coords + Person::players[i]->facing;
5166                     test.y -= 10;
5167                     j = checkcollide(test2, test, Person::players[i]->laststanding);
5168                     if (j == -1)
5169                         j = checkcollide(test2, test);
5170                     if (j == -1) {
5171                         Person::players[i]->velocity = 0;
5172                         Person::players[i]->setAnimation(Person::players[i]->getStop());
5173                         Person::players[i]->targetyaw += 180;
5174                         Person::players[i]->stunned = .5;
5175                         //Person::players[i]->aitype=passivetype;
5176                         Person::players[i]->aitype = pathfindtype;
5177                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
5178                         Person::players[i]->finalpathfindpoint = -1;
5179                         Person::players[i]->targetpathfindpoint = -1;
5180                         Person::players[i]->lastpathfindpoint = -1;
5181                         Person::players[i]->lastpathfindpoint2 = -1;
5182                         Person::players[i]->lastpathfindpoint3 = -1;
5183                         Person::players[i]->lastpathfindpoint4 = -1;
5184                     } else
5185                         Person::players[i]->laststanding = j;
5186                 }
5187             }
5188             //check out last seen location
5189             if (Person::players[i]->aiupdatedelay < 0) {
5190                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[i]->lastseen);
5191                 Person::players[i]->lookyaw = Person::players[i]->targetyaw;
5192                 Person::players[i]->aiupdatedelay = .05;
5193                 Person::players[i]->forwardkeydown = 1;
5194
5195                 if (distsqflat(&Person::players[i]->coords, &Person::players[i]->lastseen) < 1 * sq(Person::players[i]->scale * 5) || Person::players[i]->lastchecktime < 0) {
5196                     Person::players[i]->forwardkeydown = 0;
5197                     Person::players[i]->aiupdatedelay = 1;
5198                     Person::players[i]->lastseen.x += (float(Random() % 100) - 50) / 25;
5199                     Person::players[i]->lastseen.z += (float(Random() % 100) - 50) / 25;
5200                     Person::players[i]->lastchecktime = 3;
5201                 }
5202
5203                 Person::players[i]->leftkeydown = 0;
5204                 Person::players[i]->backkeydown = 0;
5205                 Person::players[i]->rightkeydown = 0;
5206                 Person::players[i]->crouchkeydown = 0;
5207                 Person::players[i]->attackkeydown = 0;
5208                 Person::players[i]->throwkeydown = 0;
5209
5210                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
5211                     if (!Person::players[i]->avoidsomething)
5212                         Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
5213                     else {
5214                         XYZ leftpos, rightpos;
5215                         float leftdist, rightdist;
5216                         leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
5217                         rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
5218                         leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
5219                         rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
5220                         if (leftdist < rightdist)
5221                             Person::players[i]->targetyaw += 90;
5222                         else
5223                             Person::players[i]->targetyaw -= 90;
5224                     }
5225                 }
5226             }
5227             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
5228                 Person::players[i]->jumpkeydown = 0;
5229             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
5230                 Person::players[i]->jumpkeydown = 1;
5231
5232             if (numenvsounds > 0 && ((tutoriallevel != 1 || cananger) && hostile))
5233                 for (int k = 0; k < numenvsounds; k++) {
5234                     if (distsq(&Person::players[i]->coords, &envsound[k]) < 2 * (envsoundvol[k] + envsoundvol[k] * (Person::players[i]->creature == rabbittype) * 3)) {
5235                         Person::players[i]->aitype = attacktypecutoff;
5236                     }
5237                 }
5238
5239             if (!Person::players[0]->dead &&
5240                     Person::players[i]->losupdatedelay < 0 &&
5241                     !editorenabled &&
5242                     Person::players[i]->occluded < 2 &&
5243                     ((tutoriallevel != 1 || cananger) && hostile)) {
5244                 Person::players[i]->losupdatedelay = .2;
5245                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 4 && animation[Person::players[i]->animTarget].height != lowheight) {
5246                     Person::players[i]->aitype = attacktypecutoff;
5247                     Person::players[i]->lastseentime = 1;
5248                 }
5249                 if (abs(Random() % 2) || animation[Person::players[i]->animTarget].height != lowheight)
5250                     //TODO: factor out canSeePlayer()
5251                     if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 400)
5252                         if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
5253                             if ((checkcollide(
5254                                         DoRotation(Person::players[i]->jointPos(head), 0, Person::players[i]->yaw, 0)*
5255                                         Person::players[i]->scale + Person::players[i]->coords,
5256                                         DoRotation(Person::players[0]->jointPos(head), 0, Person::players[0]->yaw, 0)*
5257                                         Person::players[0]->scale + Person::players[0]->coords) == -1) ||
5258                                     (Person::players[0]->animTarget == hanganim && normaldotproduct(
5259                                          Person::players[0]->facing, Person::players[i]->coords - Person::players[0]->coords) < 0)) {
5260                                 /* //TODO: changed j to 0 on a whim, make sure this is correct
5261                                 (Person::players[j]->animTarget==hanganim&&normaldotproduct(
5262                                     Person::players[j]->facing,Person::players[i]->coords-Person::players[j]->coords)<0)
5263                                 */
5264                                 Person::players[i]->aitype = attacktypecutoff;
5265                                 Person::players[i]->lastseentime = 1;
5266                             }
5267             }
5268             //player escaped
5269             if (Person::players[i]->lastseentime < 0) {
5270                 //Person::players[i]->aitype=passivetype;
5271                 numescaped++;
5272                 Person::players[i]->aitype = pathfindtype;
5273                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
5274                 Person::players[i]->finalpathfindpoint = -1;
5275                 Person::players[i]->targetpathfindpoint = -1;
5276                 Person::players[i]->lastpathfindpoint = -1;
5277                 Person::players[i]->lastpathfindpoint2 = -1;
5278                 Person::players[i]->lastpathfindpoint3 = -1;
5279                 Person::players[i]->lastpathfindpoint4 = -1;
5280             }
5281         }
5282
5283         if (Person::players[i]->aitype != gethelptype)
5284             Person::players[i]->runninghowlong = 0;
5285
5286         //get help from buddies
5287         if (Person::players[i]->aitype == gethelptype) {
5288             Person::players[i]->runninghowlong += multiplier;
5289             Person::players[i]->aiupdatedelay -= multiplier;
5290
5291             if (Person::players[i]->aiupdatedelay < 0 || Person::players[i]->ally == 0) {
5292                 Person::players[i]->aiupdatedelay = .2;
5293
5294                 //find closest ally
5295                 //TODO: factor out closest search somehow
5296                 if (!Person::players[i]->ally) {
5297                     int closest = -1;
5298                     float closestdist = -1;
5299                     for (int k = 0; k < Person::players.size(); k++) {
5300                         if (k != i && k != 0 && !Person::players[k]->dead &&
5301                                 Person::players[k]->howactive < typedead1 &&
5302                                 !Person::players[k]->skeleton.free &&
5303                                 Person::players[k]->aitype == passivetype) {
5304                             float distance = distsq(&Person::players[i]->coords, &Person::players[k]->coords);
5305                             if (closestdist == -1 || distance < closestdist) {
5306                                 closestdist = distance;
5307                                 closest = k;
5308                             }
5309                             closest = k;
5310                         }
5311                     }
5312                     if (closest != -1)
5313                         Person::players[i]->ally = closest;
5314                     else
5315                         Person::players[i]->ally = 0;
5316                     Person::players[i]->lastseen = Person::players[0]->coords;
5317                     Person::players[i]->lastseentime = 12;
5318                 }
5319
5320
5321                 Person::players[i]->lastchecktime = 12;
5322
5323                 XYZ facing = Person::players[i]->coords;
5324                 XYZ flatfacing = Person::players[Person::players[i]->ally]->coords;
5325                 facing.y += Person::players[i]->jointPos(head).y * Person::players[i]->scale;
5326                 flatfacing.y += Person::players[Person::players[i]->ally]->jointPos(head).y * Person::players[Person::players[i]->ally]->scale;
5327                 if (-1 != checkcollide(facing, flatfacing))
5328                     Person::players[i]->lastseentime -= .1;
5329
5330                 //no available ally, run back to player
5331                 if (Person::players[i]->ally <= 0 ||
5332                         Person::players[Person::players[i]->ally]->skeleton.free ||
5333                         Person::players[Person::players[i]->ally]->aitype != passivetype ||
5334                         Person::players[i]->lastseentime <= 0) {
5335                     Person::players[i]->aitype = searchtype;
5336                     Person::players[i]->lastseentime = 12;
5337                 }
5338
5339                 //seek out ally
5340                 if (Person::players[i]->ally > 0) {
5341                     Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[Person::players[i]->ally]->coords);
5342                     Person::players[i]->lookyaw = Person::players[i]->targetyaw;
5343                     Person::players[i]->aiupdatedelay = .05;
5344                     Person::players[i]->forwardkeydown = 1;
5345
5346                     if (distsqflat(&Person::players[i]->coords, &Person::players[Person::players[i]->ally]->coords) < 3) {
5347                         Person::players[i]->aitype = searchtype;
5348                         Person::players[i]->lastseentime = 12;
5349                         Person::players[Person::players[i]->ally]->aitype = searchtype;
5350                         if (Person::players[Person::players[i]->ally]->lastseentime < Person::players[i]->lastseentime) {
5351                             Person::players[Person::players[i]->ally]->lastseen = Person::players[i]->lastseen;
5352                             Person::players[Person::players[i]->ally]->lastseentime = Person::players[i]->lastseentime;
5353                             Person::players[Person::players[i]->ally]->lastchecktime = Person::players[i]->lastchecktime;
5354                         }
5355                     }
5356
5357                     if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
5358                         if (!Person::players[i]->avoidsomething)
5359                             Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
5360                         else {
5361                             XYZ leftpos, rightpos;
5362                             float leftdist, rightdist;
5363                             leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
5364                             rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
5365                             leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
5366                             rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
5367                             if (leftdist < rightdist)
5368                                 Person::players[i]->targetyaw += 90;
5369                             else
5370                                 Person::players[i]->targetyaw -= 90;
5371                         }
5372                     }
5373                 }
5374
5375                 Person::players[i]->leftkeydown = 0;
5376                 Person::players[i]->backkeydown = 0;
5377                 Person::players[i]->rightkeydown = 0;
5378                 Person::players[i]->crouchkeydown = 0;
5379                 Person::players[i]->attackkeydown = 0;
5380             }
5381             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
5382                 Person::players[i]->jumpkeydown = 0;
5383             if (Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5)
5384                 Person::players[i]->jumpkeydown = 1;
5385         }
5386
5387         //retreiving a weapon on the ground
5388         if (Person::players[i]->aitype == getweapontype) {
5389             Person::players[i]->aiupdatedelay -= multiplier;
5390             Person::players[i]->lastchecktime -= multiplier;
5391
5392             if (Person::players[i]->aiupdatedelay < 0) {
5393                 Person::players[i]->aiupdatedelay = .2;
5394
5395                 //ALLY IS WEPON
5396                 if (Person::players[i]->ally < 0) {
5397                     int closest = -1;
5398                     float closestdist = -1;
5399                     for (int k = 0; k < weapons.size(); k++)
5400                         if (weapons[k].owner == -1) {
5401                             float distance = distsq(&Person::players[i]->coords, &weapons[k].position);
5402                             if (closestdist == -1 || distance < closestdist) {
5403                                 closestdist = distance;
5404                                 closest = k;
5405                             }
5406                             closest = k;
5407                         }
5408                     if (closest != -1)
5409                         Person::players[i]->ally = closest;
5410                     else
5411                         Person::players[i]->ally = -1;
5412                 }
5413
5414                 Person::players[i]->lastseentime = 12;
5415
5416                 if (!Person::players[0]->dead && ((tutoriallevel != 1 || cananger) && hostile))
5417                     if (Person::players[i]->ally < 0 || Person::players[i]->weaponactive != -1 || Person::players[i]->lastchecktime <= 0) {
5418                         Person::players[i]->aitype = attacktypecutoff;
5419                         Person::players[i]->lastseentime = 1;
5420                     }
5421                 if (!Person::players[0]->dead)
5422                     if (Person::players[i]->ally >= 0) {
5423                         if (weapons[Person::players[i]->ally].owner != -1 ||
5424                                 distsq(&Person::players[i]->coords, &weapons[Person::players[i]->ally].position) > 16) {
5425                             Person::players[i]->aitype = attacktypecutoff;
5426                             Person::players[i]->lastseentime = 1;
5427                         }
5428                         //TODO: factor these out as moveToward()
5429                         Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[Person::players[i]->ally].position);
5430                         Person::players[i]->lookyaw = Person::players[i]->targetyaw;
5431                         Person::players[i]->aiupdatedelay = .05;
5432                         Person::players[i]->forwardkeydown = 1;
5433
5434
5435                         if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8) {
5436                             if (!Person::players[i]->avoidsomething)
5437                                 Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
5438                             else {
5439                                 XYZ leftpos, rightpos;
5440                                 float leftdist, rightdist;
5441                                 leftpos = Person::players[i]->coords + DoRotation(Person::players[i]->facing, 0, 90, 0);
5442                                 rightpos = Person::players[i]->coords - DoRotation(Person::players[i]->facing, 0, 90, 0);
5443                                 leftdist = distsq(&leftpos, &Person::players[i]->avoidwhere);
5444                                 rightdist = distsq(&rightpos, &Person::players[i]->avoidwhere);
5445                                 if (leftdist < rightdist)
5446                                     Person::players[i]->targetyaw += 90;
5447                                 else
5448                                     Person::players[i]->targetyaw -= 90;
5449                             }
5450                         }
5451                     }
5452
5453                 Person::players[i]->leftkeydown = 0;
5454                 Person::players[i]->backkeydown = 0;
5455                 Person::players[i]->rightkeydown = 0;
5456                 Person::players[i]->attackkeydown = 0;
5457                 Person::players[i]->throwkeydown = 1;
5458                 Person::players[i]->crouchkeydown = 0;
5459                 if (Person::players[i]->animTarget != crouchremoveknifeanim &&
5460                         Person::players[i]->animTarget != removeknifeanim)
5461                     Person::players[i]->throwtogglekeydown = 0;
5462                 Person::players[i]->drawkeydown = 0;
5463             }
5464             if (Person::players[i]->collided < 1 || Person::players[i]->animTarget != jumpupanim)
5465                 Person::players[i]->jumpkeydown = 0;
5466             if ((Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5))
5467                 Person::players[i]->jumpkeydown = 1;
5468         }
5469
5470         if (Person::players[i]->aitype == attacktypecutoff) {
5471             Person::players[i]->aiupdatedelay -= multiplier;
5472             //dodge or reverse rabbit kicks, knife throws, flips
5473             if (Person::players[i]->damage < Person::players[i]->damagetolerance * 2 / 3)
5474                 if ((Person::players[0]->animTarget == rabbitkickanim ||
5475                         Person::players[0]->animTarget == knifethrowanim ||
5476                         (Person::players[0]->isFlip() &&
5477                          normaldotproduct(Person::players[0]->facing, Person::players[0]->coords - Person::players[i]->coords) < 0)) &&
5478                         !Person::players[0]->skeleton.free &&
5479                         (Person::players[i]->aiupdatedelay < .1)) {
5480                     Person::players[i]->attackkeydown = 0;
5481                     if (Person::players[i]->isIdle())
5482                         Person::players[i]->crouchkeydown = 1;
5483                     if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->weaponactive != -1) {
5484                         if (weapons[Person::players[0]->weaponids[0]].getType() == knife) {
5485                             if (Person::players[i]->isIdle() || Person::players[i]->isCrouch() || Person::players[i]->isRun() || Person::players[i]->isFlip()) {
5486                                 if (abs(Random() % 2 == 0))
5487                                     Person::players[i]->setAnimation(backhandspringanim);
5488                                 else
5489                                     Person::players[i]->setAnimation(rollanim);
5490                                 Person::players[i]->targetyaw += 90 * (abs(Random() % 2) * 2 - 1);
5491                                 Person::players[i]->wentforweapon = 0;
5492                             }
5493                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim)
5494                                 Person::players[i]->setAnimation(flipanim);
5495                         }
5496                     }
5497                     Person::players[i]->forwardkeydown = 0;
5498                     Person::players[i]->aiupdatedelay = .02;
5499                 }
5500             //get confused by flips
5501             if (Person::players[0]->isFlip() &&
5502                     !Person::players[0]->skeleton.free &&
5503                     Person::players[0]->animTarget != walljumprightkickanim &&
5504                     Person::players[0]->animTarget != walljumpleftkickanim) {
5505                 if (distsq(&Person::players[0]->coords, &Person::players[i]->coords) < 25)
5506                     if ((1 - Person::players[i]->damage / Person::players[i]->damagetolerance) > .5)
5507                         Person::players[i]->stunned = 1;
5508             }
5509             //go for weapon on the ground
5510             if (Person::players[i]->wentforweapon < 3)
5511                 for (int k = 0; k < weapons.size(); k++)
5512                     if (Person::players[i]->creature != wolftype)
5513                         if (Person::players[i]->num_weapons == 0 &&
5514                                 weapons[k].owner == -1 &&
5515                                 weapons[i].velocity.x == 0 &&
5516                                 weapons[i].velocity.z == 0 &&
5517                                 weapons[i].velocity.y == 0) {
5518                             if (distsq(&Person::players[i]->coords, &weapons[k].position) < 16) {
5519                                 Person::players[i]->wentforweapon++;
5520                                 Person::players[i]->lastchecktime = 6;
5521                                 Person::players[i]->aitype = getweapontype;
5522                                 Person::players[i]->ally = -1;
5523                             }
5524                         }
5525             //dodge/reverse walljump kicks
5526             if (Person::players[i]->damage < Person::players[i]->damagetolerance / 2)
5527                 if (animation[Person::players[i]->animTarget].height != highheight)
5528                     if (Person::players[i]->damage < Person::players[i]->damagetolerance * .5 &&
5529                             ((Person::players[0]->animTarget == walljumprightkickanim ||
5530                               Person::players[0]->animTarget == walljumpleftkickanim) &&
5531                              ((Person::players[i]->aiupdatedelay < .15 &&
5532                                difficulty == 2) ||
5533                               (Person::players[i]->aiupdatedelay < .08 &&
5534                                difficulty != 2)))) {
5535                         Person::players[i]->crouchkeydown = 1;
5536                     }
5537             //walked off a ledge (?)
5538             if (Person::players[i]->isRun() && !Person::players[i]->onground)
5539                 if (Person::players[i]->coords.y > terrain.getHeight(Person::players[i]->coords.x, Person::players[i]->coords.z) + 10) {
5540                     XYZ test2 = Person::players[i]->coords + Person::players[i]->facing;
5541                     test2.y += 5;
5542                     XYZ test = Person::players[i]->coords + Person::players[i]->facing;
5543                     test.y -= 10;
5544                     j = checkcollide(test2, test, Person::players[i]->laststanding);
5545                     if (j == -1)
5546                         j = checkcollide(test2, test);
5547                     if (j == -1) {
5548                         Person::players[i]->velocity = 0;
5549                         Person::players[i]->setAnimation(Person::players[i]->getStop());
5550                         Person::players[i]->targetyaw += 180;
5551                         Person::players[i]->stunned = .5;
5552                         Person::players[i]->aitype = pathfindtype;
5553                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
5554                         Person::players[i]->finalpathfindpoint = -1;
5555                         Person::players[i]->targetpathfindpoint = -1;
5556                         Person::players[i]->lastpathfindpoint = -1;
5557                         Person::players[i]->lastpathfindpoint2 = -1;
5558                         Person::players[i]->lastpathfindpoint3 = -1;
5559                         Person::players[i]->lastpathfindpoint4 = -1;
5560                     } else
5561                         Person::players[i]->laststanding = j;
5562                 }
5563             //lose sight of player in the air (?)
5564             if (Person::players[0]->coords.y > Person::players[i]->coords.y + 5 &&
5565                     animation[Person::players[0]->animTarget].height != highheight &&
5566                     !Person::players[0]->onterrain) {
5567                 Person::players[i]->aitype = pathfindtype;
5568                 Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
5569                 Person::players[i]->finalpathfindpoint = -1;
5570                 Person::players[i]->targetpathfindpoint = -1;
5571                 Person::players[i]->lastpathfindpoint = -1;
5572                 Person::players[i]->lastpathfindpoint2 = -1;
5573                 Person::players[i]->lastpathfindpoint3 = -1;
5574                 Person::players[i]->lastpathfindpoint4 = -1;
5575             }
5576             //it's time to think (?)
5577             if (Person::players[i]->aiupdatedelay < 0 &&
5578                     !animation[Person::players[i]->animTarget].attack &&
5579                     Person::players[i]->animTarget != staggerbackhighanim &&
5580                     Person::players[i]->animTarget != staggerbackhardanim &&
5581                     Person::players[i]->animTarget != backhandspringanim &&
5582                     Person::players[i]->animTarget != dodgebackanim) {
5583                 //draw weapon
5584                 if (Person::players[i]->weaponactive == -1 && Person::players[i]->num_weapons > 0)
5585                     Person::players[i]->drawkeydown = Random() % 2;
5586                 else
5587                     Person::players[i]->drawkeydown = 0;
5588                 Person::players[i]->rabbitkickenabled = Random() % 2;
5589                 //chase player
5590                 XYZ rotatetarget = Person::players[0]->coords + Person::players[0]->velocity;
5591                 XYZ targetpoint = Person::players[0]->coords;
5592                 if (distsq(&Person::players[0]->coords, &Person::players[i]->coords) <
5593                         distsq(&rotatetarget, &Person::players[i]->coords))
5594                     targetpoint += Person::players[0]->velocity *
5595                                    findDistance(&Person::players[0]->coords, &Person::players[i]->coords) / findLength(&Person::players[i]->velocity);
5596                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, targetpoint);
5597                 Person::players[i]->lookyaw = Person::players[i]->targetyaw;
5598                 Person::players[i]->aiupdatedelay = .2 + fabs((float)(Random() % 100) / 1000);
5599
5600                 if (distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 5 && (Person::players[0]->weaponactive == -1 || Person::players[i]->weaponactive != -1))
5601                     Person::players[i]->forwardkeydown = 1;
5602                 else if ((distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 16 ||
5603                           distsq(&Person::players[i]->coords, &Person::players[0]->coords) < 9) &&
5604                          Person::players[0]->weaponactive != -1)
5605                     Person::players[i]->forwardkeydown = 1;
5606                 else if (Random() % 6 == 0 || (Person::players[i]->creature == wolftype && Random() % 3 == 0))
5607                     Person::players[i]->forwardkeydown = 1;
5608                 else
5609                     Person::players[i]->forwardkeydown = 0;
5610                 //chill out around the corpse
5611                 if (Person::players[0]->dead) {
5612                     Person::players[i]->forwardkeydown = 0;
5613                     if (Random() % 10 == 0)
5614                         Person::players[i]->forwardkeydown = 1;
5615                     if (Random() % 100 == 0) {
5616                         Person::players[i]->aitype = pathfindtype;
5617                         Person::players[i]->finalfinaltarget = Person::players[i]->waypoints[Person::players[i]->waypoint];
5618                         Person::players[i]->finalpathfindpoint = -1;
5619                         Person::players[i]->targetpathfindpoint = -1;
5620                         Person::players[i]->lastpathfindpoint = -1;
5621                         Person::players[i]->lastpathfindpoint2 = -1;
5622                         Person::players[i]->lastpathfindpoint3 = -1;
5623                         Person::players[i]->lastpathfindpoint4 = -1;
5624                     }
5625                 }
5626                 Person::players[i]->leftkeydown = 0;
5627                 Person::players[i]->backkeydown = 0;
5628                 Person::players[i]->rightkeydown = 0;
5629                 Person::players[i]->crouchkeydown = 0;
5630                 Person::players[i]->throwkeydown = 0;
5631
5632                 if (Person::players[i]->avoidcollided > .8 && !Person::players[i]->jumpkeydown && Person::players[i]->collided < .8)
5633                     Person::players[i]->targetyaw += 90 * (Person::players[i]->whichdirection * 2 - 1);
5634                 //attack!!!
5635                 if (Random() % 2 == 0 || Person::players[i]->weaponactive != -1 || Person::players[i]->creature == wolftype)
5636                     Person::players[i]->attackkeydown = 1;
5637                 else
5638                     Person::players[i]->attackkeydown = 0;
5639                 if (Person::players[i]->isRun() && Random() % 6 && distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 7)
5640                     Person::players[i]->attackkeydown = 0;
5641
5642                 //TODO: wat
5643                 if (Person::players[i]->aitype != playercontrolled &&
5644                         (Person::players[i]->isIdle() ||
5645                          Person::players[i]->isCrouch() ||
5646                          Person::players[i]->isRun())) {
5647                     int target = -2;
5648                     for (int j = 0; j < Person::players.size(); j++)
5649                         if (j != i && !Person::players[j]->skeleton.free &&
5650                                 Person::players[j]->hasvictim &&
5651                                 (tutoriallevel == 1 && reversaltrain ||
5652                                  Random() % 2 == 0 && difficulty == 2 ||
5653                                  Random() % 4 == 0 && difficulty == 1 ||
5654                                  Random() % 8 == 0 && difficulty == 0 ||
5655                                  Person::players[j]->lastattack2 == Person::players[j]->animTarget &&
5656                                  Person::players[j]->lastattack3 == Person::players[j]->animTarget &&
5657                                  (Random() % 2 == 0 || difficulty == 2) ||
5658                                  (Person::players[i]->isIdle() || Person::players[i]->isRun()) &&
5659                                  Person::players[j]->weaponactive != -1 ||
5660                                  Person::players[j]->animTarget == swordslashanim &&
5661                                  Person::players[i]->weaponactive != -1 ||
5662                                  Person::players[j]->animTarget == staffhitanim ||
5663                                  Person::players[j]->animTarget == staffspinhitanim))
5664                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 4 &&
5665                                     Person::players[j]->victim == Person::players[i] &&
5666                                     (Person::players[j]->animTarget == sweepanim ||
5667                                      Person::players[j]->animTarget == spinkickanim ||
5668                                      Person::players[j]->animTarget == staffhitanim ||
5669                                      Person::players[j]->animTarget == staffspinhitanim ||
5670                                      Person::players[j]->animTarget == winduppunchanim ||
5671                                      Person::players[j]->animTarget == upunchanim ||
5672                                      Person::players[j]->animTarget == wolfslapanim ||
5673                                      Person::players[j]->animTarget == knifeslashstartanim ||
5674                                      Person::players[j]->animTarget == swordslashanim &&
5675                                      (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 2 ||
5676                                       Person::players[i]->weaponactive != -1))) {
5677                                 if (target >= 0)
5678                                     target = -1;
5679                                 else
5680                                     target = j;
5681                             }
5682                     if (target >= 0)
5683                         Person::players[target]->Reverse();
5684                 }
5685
5686                 if (Person::players[i]->collided < 1)
5687                     Person::players[i]->jumpkeydown = 0;
5688                 if (Person::players[i]->collided > .8 && Person::players[i]->jumppower >= 5 ||
5689                         distsq(&Person::players[i]->coords, &Person::players[0]->coords) > 400 &&
5690                         Person::players[i]->onterrain &&
5691                         Person::players[i]->creature == rabbittype)
5692                     Person::players[i]->jumpkeydown = 1;
5693                 //TODO: why are we controlling the human?
5694                 if (normaldotproduct(Person::players[i]->facing, Person::players[0]->coords - Person::players[i]->coords) > 0)
5695                     Person::players[0]->jumpkeydown = 0;
5696                 if (Person::players[0]->animTarget == jumpdownanim &&
5697                         distsq(&Person::players[0]->coords, &Person::players[i]->coords) < 40)
5698                     Person::players[i]->crouchkeydown = 1;
5699                 if (Person::players[i]->jumpkeydown)
5700                     Person::players[i]->attackkeydown = 0;
5701
5702                 if (tutoriallevel == 1)
5703                     if (!canattack)
5704                         Person::players[i]->attackkeydown = 0;
5705
5706
5707                 XYZ facing = Person::players[i]->coords;
5708                 XYZ flatfacing = Person::players[0]->coords;
5709                 facing.y += Person::players[i]->jointPos(head).y * Person::players[i]->scale;
5710                 flatfacing.y += Person::players[0]->jointPos(head).y * Person::players[0]->scale;
5711                 if (Person::players[i]->occluded >= 2)
5712                     if (-1 != checkcollide(facing, flatfacing)) {
5713                         if (!Person::players[i]->pause)
5714                             Person::players[i]->lastseentime -= .2;
5715                         if (Person::players[i]->lastseentime <= 0 &&
5716                                 (Person::players[i]->creature != wolftype ||
5717                                  Person::players[i]->weaponstuck == -1)) {
5718                             Person::players[i]->aitype = searchtype;
5719                             Person::players[i]->lastchecktime = 12;
5720                             Person::players[i]->lastseen = Person::players[0]->coords;
5721                             Person::players[i]->lastseentime = 12;
5722                         }
5723                     } else
5724                         Person::players[i]->lastseentime = 1;
5725             }
5726         }
5727         if (animation[Person::players[0]->animTarget].height == highheight &&
5728                 (Person::players[i]->aitype == attacktypecutoff ||
5729                  Person::players[i]->aitype == searchtype))
5730             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
5731                 XYZ test = Person::players[0]->coords;
5732                 test.y -= 40;
5733                 if (-1 == checkcollide(Person::players[0]->coords, test))
5734                     Person::players[i]->stunned = 1;
5735             }
5736         //stunned
5737         if (Person::players[i]->aitype == passivetype && !(Person::players[i]->numwaypoints > 1) ||
5738                 Person::players[i]->stunned > 0 ||
5739                 Person::players[i]->pause && Person::players[i]->damage > Person::players[i]->superpermanentdamage) {
5740             if (Person::players[i]->pause)
5741                 Person::players[i]->lastseentime = 1;
5742             Person::players[i]->targetyaw = Person::players[i]->yaw;
5743             Person::players[i]->forwardkeydown = 0;
5744             Person::players[i]->leftkeydown = 0;
5745             Person::players[i]->backkeydown = 0;
5746             Person::players[i]->rightkeydown = 0;
5747             Person::players[i]->jumpkeydown = 0;
5748             Person::players[i]->attackkeydown = 0;
5749             Person::players[i]->crouchkeydown = 0;
5750             Person::players[i]->throwkeydown = 0;
5751         }
5752
5753
5754         XYZ facing;
5755         facing = 0;
5756         facing.z = -1;
5757
5758         XYZ flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
5759         facing = flatfacing;
5760
5761         if (Person::players[i]->aitype == attacktypecutoff) {
5762             Person::players[i]->targetheadyaw = 180 - roughDirectionTo(Person::players[i]->coords, Person::players[0]->coords);
5763             Person::players[i]->targetheadpitch = pitchTo(Person::players[i]->coords, Person::players[0]->coords);
5764         } else if (Person::players[i]->howactive >= typesleeping) {
5765             Person::players[i]->targetheadyaw = Person::players[i]->targetyaw;
5766             Person::players[i]->targetheadpitch = 0;
5767         } else {
5768             if (Person::players[i]->interestdelay <= 0) {
5769                 Person::players[i]->interestdelay = .7 + (float)(abs(Random() % 100)) / 100;
5770                 Person::players[i]->headtarget = Person::players[i]->coords;
5771                 Person::players[i]->headtarget.x += (float)(abs(Random() % 200) - 100) / 100;
5772                 Person::players[i]->headtarget.z += (float)(abs(Random() % 200) - 100) / 100;
5773                 Person::players[i]->headtarget.y += (float)(abs(Random() % 200) - 100) / 300;
5774                 Person::players[i]->headtarget += Person::players[i]->facing * 1.5;
5775             }
5776             Person::players[i]->targetheadyaw = 180 - roughDirectionTo(Person::players[i]->coords, Person::players[i]->headtarget);
5777             Person::players[i]->targetheadpitch = pitchTo(Person::players[i]->coords, Person::players[i]->headtarget);
5778         }
5779     }
5780 }
5781
5782
5783
5784 void updateSettingsMenu()
5785 {
5786     char sbuf[256];
5787     if ((float)newscreenwidth > (float)newscreenheight * 1.61 || (float)newscreenwidth < (float)newscreenheight * 1.59)
5788         sprintf (sbuf, "Resolution: %d*%d", (int)newscreenwidth, (int)newscreenheight);
5789     else
5790         sprintf (sbuf, "Resolution: %d*%d (widescreen)", (int)newscreenwidth, (int)newscreenheight);
5791     Menu::setText(0, sbuf);
5792     if (newdetail == 0) Menu::setText(1, "Detail: Low");
5793     if (newdetail == 1) Menu::setText(1, "Detail: Medium");
5794     if (newdetail == 2) Menu::setText(1, "Detail: High");
5795     if (bloodtoggle == 0) Menu::setText(2, "Blood: Off");
5796     if (bloodtoggle == 1) Menu::setText(2, "Blood: On, low detail");
5797     if (bloodtoggle == 2) Menu::setText(2, "Blood: On, high detail (slower)");
5798     if (difficulty == 0) Menu::setText(3, "Difficulty: Easier");
5799     if (difficulty == 1) Menu::setText(3, "Difficulty: Difficult");
5800     if (difficulty == 2) Menu::setText(3, "Difficulty: Insane");
5801     Menu::setText(4, ismotionblur ? "Blur Effects: Enabled (less compatible)" : "Blur Effects: Disabled (more compatible)");
5802     Menu::setText(5, decals ? "Decals: Enabled (slower)" : "Decals: Disabled");
5803     Menu::setText(6, musictoggle ? "Music: Enabled" : "Music: Disabled");
5804     Menu::setText(9, invertmouse ? "Invert mouse: Yes" : "Invert mouse: No");
5805     sprintf (sbuf, "Mouse Speed: %d", (int)(usermousesensitivity * 5));
5806     Menu::setText(10, sbuf);
5807     sprintf (sbuf, "Volume: %d%%", (int)(volume * 100));
5808     Menu::setText(11, sbuf);
5809     Menu::setText(13, showdamagebar ? "Damage Bar: On" : "Damage Bar: Off");
5810     if (newdetail == detail && newscreenheight == (int)screenheight && newscreenwidth == (int)screenwidth)
5811         sprintf (sbuf, "Back");
5812     else
5813         sprintf (sbuf, "Back (some changes take effect next time Lugaru is opened)");
5814     Menu::setText(8, sbuf);
5815 }
5816
5817 void updateStereoConfigMenu()
5818 {
5819     char sbuf[256];
5820     sprintf(sbuf, "Stereo mode: %s", StereoModeName(newstereomode));
5821     Menu::setText(0, sbuf);
5822     sprintf(sbuf, "Stereo separation: %.3f", stereoseparation);
5823     Menu::setText(1, sbuf);
5824     sprintf(sbuf, "Reverse stereo: %s", stereoreverse ? "Yes" : "No");
5825     Menu::setText(2, sbuf);
5826 }
5827
5828 void updateControlsMenu()
5829 {
5830     Menu::setText(0, (string)"Forwards: " + (keyselect == 0 ? "_" : Input::keyToChar(forwardkey)));
5831     Menu::setText(1, (string)"Back: "    + (keyselect == 1 ? "_" : Input::keyToChar(backkey)));
5832     Menu::setText(2, (string)"Left: "    + (keyselect == 2 ? "_" : Input::keyToChar(leftkey)));
5833     Menu::setText(3, (string)"Right: "   + (keyselect == 3 ? "_" : Input::keyToChar(rightkey)));
5834     Menu::setText(4, (string)"Crouch: "  + (keyselect == 4 ? "_" : Input::keyToChar(crouchkey)));
5835     Menu::setText(5, (string)"Jump: "    + (keyselect == 5 ? "_" : Input::keyToChar(jumpkey)));
5836     Menu::setText(6, (string)"Draw: "    + (keyselect == 6 ? "_" : Input::keyToChar(drawkey)));
5837     Menu::setText(7, (string)"Throw: "   + (keyselect == 7 ? "_" : Input::keyToChar(throwkey)));
5838     Menu::setText(8, (string)"Attack: "  + (keyselect == 8 ? "_" : Input::keyToChar(attackkey)));
5839     if (debugmode)
5840         Menu::setText(9, (string)"Console: " + (keyselect == 9 ? "_" : Input::keyToChar(consolekey)));
5841 }
5842
5843 /*
5844 Values of mainmenu :
5845 1 Main menu
5846 2 Menu pause (resume/end game)
5847 3 Option menu
5848 4 Controls configuration menu
5849 5 Main game menu (choose level or challenge)
5850 6 Deleting user menu
5851 7 User managment menu (select/add)
5852 8 Choose difficulty menu
5853 9 Challenge level selection menu
5854 10 End of the campaign congratulation (is that really a menu?)
5855 11 Same that 9 ??? => unused
5856 18 stereo configuration
5857 */
5858
5859 void Game::LoadMenu()
5860 {
5861     Menu::clearMenu();
5862     switch (mainmenu) {
5863     case 1:
5864     case 2:
5865         Menu::addImage(0, Mainmenuitems[0], 150, 480 - 128, 256, 128);
5866         Menu::addButtonImage(1, Mainmenuitems[mainmenu == 1 ? 1 : 5], 18, 480 - 152 - 32, 128, 32);
5867         Menu::addButtonImage(2, Mainmenuitems[2], 18, 480 - 228 - 32, 112, 32);
5868         Menu::addButtonImage(3, Mainmenuitems[mainmenu == 1 ? 3 : 6], 18, 480 - 306 - 32, mainmenu == 1 ? 68 : 132, 32);
5869         break;
5870     case 3:
5871         Menu::addButton( 0, "", 10 + 20, 440);
5872         Menu::addButton( 1, "", 10 + 60, 405);
5873         Menu::addButton( 2, "", 10 + 70, 370);
5874         Menu::addButton( 3, "", 10 + 20 - 1000, 335 - 1000);
5875         Menu::addButton( 4, "", 10   , 335);
5876         Menu::addButton( 5, "", 10 + 60, 300);
5877         Menu::addButton( 6, "", 10 + 70, 265);
5878         Menu::addButton( 9, "", 10   , 230);
5879         Menu::addButton(10, "", 20   , 195);
5880         Menu::addButton(11, "", 10 + 60, 160);
5881         Menu::addButton(13, "", 30   , 125);
5882         Menu::addButton( 7, "-Configure Controls-", 10 + 15, 90);
5883         Menu::addButton(12, "-Configure Stereo -", 10 + 15, 55);
5884         Menu::addButton(8, "Back", 10, 10);
5885         updateSettingsMenu();
5886         break;
5887     case 4:
5888         Menu::addButton(0, "", 10   , 400);
5889         Menu::addButton(1, "", 10 + 40, 360);
5890         Menu::addButton(2, "", 10 + 40, 320);
5891         Menu::addButton(3, "", 10 + 30, 280);
5892         Menu::addButton(4, "", 10 + 20, 240);
5893         Menu::addButton(5, "", 10 + 40, 200);
5894         Menu::addButton(6, "", 10 + 40, 160);
5895         Menu::addButton(7, "", 10 + 30, 120);
5896         Menu::addButton(8, "", 10 + 20, 80);
5897         if (debugmode)
5898             Menu::addButton(9, "", 10 + 10, 40);
5899         Menu::addButton(debugmode ? 10 : 9, "Back", 10, 10);
5900         updateControlsMenu();
5901         break;
5902     case 5: {
5903         LoadCampaign();
5904         Menu::addLabel(-1, accountactive->getName(), 5, 400);
5905         Menu::addButton(1, "Tutorial", 5, 300);
5906         Menu::addButton(2, "Challenge", 5, 240);
5907         Menu::addButton(3, "Delete User", 400, 10);
5908         Menu::addButton(4, "Main Menu", 5, 10);
5909         Menu::addButton(5, "Change User", 5, 180);
5910         Menu::addButton(6, "Campaign : " + accountactive->getCurrentCampaign(), 200, 420);
5911
5912         //show campaign map
5913         //with (2,-5) offset from old code
5914         Menu::addImage(-1, Mainmenuitems[7], 150 + 2, 60 - 5, 400, 400);
5915         //show levels
5916         int numlevels = accountactive->getCampaignChoicesMade();
5917         numlevels += numlevels > 0 ? campaignlevels[numlevels - 1].nextlevel.size() : 1;
5918         for (int i = 0; i < numlevels; i++) {
5919             XYZ midpoint = campaignlevels[i].getCenter();
5920             float itemsize = campaignlevels[i].getWidth();
5921             const bool active = i >= accountactive->getCampaignChoicesMade();
5922             if (!active)
5923                 itemsize /= 2;
5924
5925             if (i >= 1) {
5926                 XYZ start = campaignlevels[i - 1].getCenter();
5927                 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);
5928             }
5929             Menu::addMapMarker(NB_CAMPAIGN_MENU_ITEM + i, Mapcircletexture,
5930                                midpoint.x - itemsize / 2, midpoint.y - itemsize / 2, itemsize, itemsize, active ? 1 : 0.5, 0, 0);
5931
5932             if (active) {
5933                 Menu::addMapLabel(-2, campaignlevels[i].description,
5934                                   campaignlevels[i].getStartX() + 10,
5935                                   campaignlevels[i].getStartY() - 4);
5936             }
5937         }
5938     }
5939     break;
5940     case 6:
5941         Menu::addLabel(-1, "Are you sure you want to delete this user?", 10, 400);
5942         Menu::addButton(1, "Yes", 10, 360);
5943         Menu::addButton(2, "No", 10, 320);
5944         break;
5945     case 7:
5946         if (Account::getNbAccounts() < 8)
5947             Menu::addButton(0, "New User", 10, 400);
5948         else
5949             Menu::addLabel(0, "No More Users", 10, 400);
5950         Menu::addLabel(-2, "", 20, 400);
5951         Menu::addButton(Account::getNbAccounts() + 1, "Back", 10, 10);
5952         for (int i = 0; i < Account::getNbAccounts(); i++)
5953             Menu::addButton(i + 1, Account::get(i)->getName(), 10, 340 - 20 * (i + 1));
5954         break;
5955     case 8:
5956         Menu::addButton(0, "Easier", 10, 400);
5957         Menu::addButton(1, "Difficult", 10, 360);
5958         Menu::addButton(2, "Insane", 10, 320);
5959         break;
5960     case 9:
5961         for (int i = 0; i < numchallengelevels; i++) {
5962             char temp[255];
5963             string name = "";
5964             sprintf (temp, "Level %d", i + 1);
5965             for (int j = strlen(temp); j < 17; j++)
5966                 strcat(temp, " ");
5967             name += temp;
5968             sprintf (temp, "%d", (int)accountactive->getHighScore(i));
5969             for (int j = strlen(temp); j < (32 - 17); j++)
5970                 strcat(temp, " ");
5971             name += temp;
5972             sprintf (temp, "%d:", (int)(((int)accountactive->getFastTime(i) - (int)(accountactive->getFastTime(i)) % 60) / 60));
5973             if ((int)(accountactive->getFastTime(i)) % 60 < 10)
5974                 strcat(temp, "0");
5975             name += temp;
5976             sprintf (temp, "%d", (int)(accountactive->getFastTime(i)) % 60);
5977             name += temp;
5978
5979             Menu::addButton(i, name, 10, 400 - i * 25, i > accountactive->getProgress() ? 0.5 : 1, 0, 0);
5980         }
5981
5982         Menu::addButton(-1, "             High Score      Best Time", 10, 440);
5983         Menu::addButton(numchallengelevels, "Back", 10, 10);
5984         break;
5985     case 10: {
5986         Menu::addLabel(0, "Congratulations!", 220, 330);
5987         Menu::addLabel(1, "You have avenged your family and", 140, 300);
5988         Menu::addLabel(2, "restored peace to the island of Lugaru.", 110, 270);
5989         Menu::addButton(3, "Back", 10, 10);
5990         char sbuf[256];
5991         sprintf(sbuf, "Your score:         %d", (int)accountactive->getCampaignScore());
5992         Menu::addLabel(4, sbuf, 190, 200);
5993         sprintf(sbuf, "Highest score:      %d", (int)accountactive->getCampaignHighScore());
5994         Menu::addLabel(5, sbuf, 190, 180);
5995     }
5996     break;
5997     case 18:
5998         Menu::addButton(0, "", 70, 400);
5999         Menu::addButton(1, "", 10, 360);
6000         Menu::addButton(2, "", 40, 320);
6001         Menu::addButton(3, "Back", 10, 10);
6002         updateStereoConfigMenu();
6003         break;
6004     }
6005 }
6006
6007 extern SDL_Rect **resolutions;
6008
6009 void MenuTick()
6010 {
6011     //menu buttons
6012     selected = Menu::getSelected(mousecoordh * 640 / screenwidth, 480 - mousecoordv * 480 / screenheight);
6013
6014     // some specific case where we do something even if the left mouse button is not pressed.
6015     if ((mainmenu == 5) && (endgame == 2)) {
6016         accountactive->endGame();
6017         endgame = 0;
6018     }
6019     if (mainmenu == 10)
6020         endgame = 2;
6021     if (mainmenu == 18 && Input::isKeyPressed(MOUSEBUTTON2) && selected == 1) {
6022         stereoseparation -= 0.001;
6023         updateStereoConfigMenu();
6024     }
6025
6026     static int oldmainmenu = mainmenu;
6027
6028     char sbuf[256];
6029
6030     if (Input::MouseClicked() && (selected >= 0)) { // handling of the left mouse clic in menus
6031         switch (mainmenu) {
6032         case 1:
6033         case 2:
6034             switch (selected) {
6035             case 1:
6036                 if (gameon) { //resume
6037                     mainmenu = 0;
6038                     pause_sound(stream_menutheme);
6039                     resume_stream(leveltheme);
6040                 } else { //new game
6041                     fireSound(firestartsound);
6042                     flash();
6043                     mainmenu = (accountactive ? 5 : 7);
6044                     selected = -1;
6045                 }
6046                 break;
6047             case 2: //options
6048                 fireSound();
6049                 flash();
6050                 mainmenu = 3;
6051                 if (newdetail > 2)
6052                     newdetail = detail;
6053                 if (newdetail < 0)
6054                     newdetail = detail;
6055                 if (newscreenwidth > 3000)
6056                     newscreenwidth = screenwidth;
6057                 if (newscreenwidth < 0)
6058                     newscreenwidth = screenwidth;
6059                 if (newscreenheight > 3000)
6060                     newscreenheight = screenheight;
6061                 if (newscreenheight < 0)
6062                     newscreenheight = screenheight;
6063                 break;
6064             case 3:
6065                 fireSound();
6066                 flash();
6067                 if (gameon) { //end game
6068                     gameon = 0;
6069                     mainmenu = 1;
6070                 } else { //quit
6071                     tryquit = 1;
6072                     pause_sound(stream_menutheme);
6073                 }
6074                 break;
6075             }
6076             break;
6077         case 3:
6078             fireSound();
6079             bool isCustomResolution, found;
6080             switch (selected) {
6081             case 0:
6082                 isCustomResolution = true;
6083                 found = false;
6084                 for (int i = 0; (!found) && (resolutions[i]); i++) {
6085                     if ((resolutions[i]->w == screenwidth) && (resolutions[i]->h == screenwidth))
6086                         isCustomResolution = false;
6087
6088                     if ((resolutions[i]->w == newscreenwidth) && (resolutions[i]->h == newscreenheight)) {
6089                         i++;
6090                         if (resolutions[i] != NULL) {
6091                             newscreenwidth = (int) resolutions[i]->w;
6092                             newscreenheight = (int) resolutions[i]->h;
6093                         } else if (isCustomResolution) {
6094                             if ((screenwidth == newscreenwidth) && (screenheight == newscreenheight)) {
6095                                 newscreenwidth = (int) resolutions[0]->w;
6096                                 newscreenheight = (int) resolutions[0]->h;
6097                             } else {
6098                                 newscreenwidth = screenwidth;
6099                                 newscreenheight = screenheight;
6100                             }
6101                         } else {
6102                             newscreenwidth = (int) resolutions[0]->w;
6103                             newscreenheight = (int) resolutions[0]->h;
6104                         }
6105                         found = true;
6106                     }
6107                 }
6108
6109                 if (!found) {
6110                     newscreenwidth = (int) resolutions[0]->w;
6111                     newscreenheight = (int) resolutions[0]->h;
6112                 }
6113                 break;
6114             case 1:
6115                 newdetail++;
6116                 if (newdetail > 2)
6117                     newdetail = 0;
6118                 break;
6119             case 2:
6120                 bloodtoggle++;
6121                 if (bloodtoggle > 2)
6122                     bloodtoggle = 0;
6123                 break;
6124             case 3:
6125                 difficulty++;
6126                 if (difficulty > 2)
6127                     difficulty = 0;
6128                 break;
6129             case 4:
6130                 ismotionblur = !ismotionblur;
6131                 break;
6132             case 5:
6133                 decals = !decals;
6134                 break;
6135             case 6:
6136                 musictoggle = !musictoggle;
6137                 if (musictoggle) {
6138                     emit_stream_np(stream_menutheme);
6139                 } else {
6140                     pause_sound(leveltheme);
6141                     pause_sound(stream_fighttheme);
6142                     pause_sound(stream_menutheme);
6143
6144                     for (int i = 0; i < 4; i++) {
6145                         oldmusicvolume[i] = 0;
6146                         musicvolume[i] = 0;
6147                     }
6148                 }
6149                 break;
6150             case 7: // controls
6151                 flash();
6152                 mainmenu = 4;
6153                 selected = -1;
6154                 keyselect = -1;
6155                 break;
6156             case 8:
6157                 flash();
6158                 SaveSettings();
6159                 mainmenu = gameon ? 2 : 1;
6160                 break;
6161             case 9:
6162                 invertmouse = !invertmouse;
6163                 break;
6164             case 10:
6165                 usermousesensitivity += .2;
6166                 if (usermousesensitivity > 2)
6167                     usermousesensitivity = .2;
6168                 break;
6169             case 11:
6170                 volume += .1f;
6171                 if (volume > 1.0001f)
6172                     volume = 0;
6173                 OPENAL_SetSFXMasterVolume((int)(volume * 255));
6174                 break;
6175             case 12:
6176                 flash();
6177                 newstereomode = stereomode;
6178                 mainmenu = 18;
6179                 keyselect = -1;
6180                 break;
6181             case 13:
6182                 showdamagebar = !showdamagebar;
6183                 break;
6184             }
6185             updateSettingsMenu();
6186             break;
6187         case 4:
6188             if (!waiting) {
6189                 fireSound();
6190                 if (selected < (debugmode ? 10 : 9) && keyselect == -1)
6191                     keyselect = selected;
6192                 if (keyselect != -1)
6193                     setKeySelected();
6194                 if (selected == (debugmode ? 10 : 9)) {
6195                     flash();
6196                     mainmenu = 3;
6197                 }
6198             }
6199             updateControlsMenu();
6200             break;
6201         case 5:
6202             fireSound();
6203             flash();
6204             if ((selected - NB_CAMPAIGN_MENU_ITEM >= accountactive->getCampaignChoicesMade())) {
6205                 startbonustotal = 0;
6206
6207                 loading = 2;
6208                 loadtime = 0;
6209                 targetlevel = 7;
6210                 if (firstload)
6211                     TickOnceAfter();
6212                 else
6213                     LoadStuff();
6214                 whichchoice = selected - NB_CAMPAIGN_MENU_ITEM - accountactive->getCampaignChoicesMade();
6215                 actuallevel = (accountactive->getCampaignChoicesMade() > 0 ? campaignlevels[accountactive->getCampaignChoicesMade() - 1].nextlevel[whichchoice] : 0);
6216                 visibleloading = 1;
6217                 stillloading = 1;
6218                 Loadlevel(campaignlevels[actuallevel].mapname.c_str());
6219                 campaign = 1;
6220                 mainmenu = 0;
6221                 gameon = 1;
6222                 pause_sound(stream_menutheme);
6223             }
6224             switch (selected) {
6225             case 1:
6226                 startbonustotal = 0;
6227
6228                 loading = 2;
6229                 loadtime = 0;
6230                 targetlevel = -1;
6231                 if (firstload) {
6232                     TickOnceAfter();
6233                 } else
6234                     LoadStuff();
6235                 Loadlevel(-1);
6236
6237                 mainmenu = 0;
6238                 gameon = 1;
6239                 pause_sound(stream_menutheme);
6240                 break;
6241             case 2:
6242                 mainmenu = 9;
6243                 break;
6244             case 3:
6245                 mainmenu = 6;
6246                 break;
6247             case 4:
6248                 mainmenu = (gameon ? 2 : 1);
6249                 break;
6250             case 5:
6251                 mainmenu = 7;
6252                 break;
6253             case 6:
6254                 vector<string> campaigns = ListCampaigns();
6255                 vector<string>::iterator c;
6256                 if ((c = find(campaigns.begin(), campaigns.end(), accountactive->getCurrentCampaign())) == campaigns.end()) {
6257                     if (!campaigns.empty())
6258                         accountactive->setCurrentCampaign(campaigns.front());
6259                 } else {
6260                     c++;
6261                     if (c == campaigns.end())
6262                         c = campaigns.begin();
6263                     accountactive->setCurrentCampaign(*c);
6264                 }
6265                 LoadMenu();
6266                 break;
6267             }
6268             break;
6269         case 6:
6270             fireSound();
6271             if (selected == 1) {
6272                 flash();
6273                 accountactive = Account::destroy(accountactive);
6274                 mainmenu = 7;
6275             } else if (selected == 2) {
6276                 flash();
6277                 mainmenu = 5;
6278             }
6279             break;
6280         case 7:
6281             fireSound();
6282             if (selected == 0 && Account::getNbAccounts() < 8) {
6283                 entername = 1;
6284             } else if (selected < Account::getNbAccounts() + 1) {
6285                 flash();
6286                 mainmenu = 5;
6287                 accountactive = Account::get(selected - 1);
6288             } else if (selected == Account::getNbAccounts() + 1) {
6289                 flash();
6290                 if (accountactive)
6291                     mainmenu = 5;
6292                 else
6293                     mainmenu = 1;
6294                 for (int j = 0; j < 255; j++) {
6295                     displaytext[0][j] = 0;
6296                 }
6297                 displaychars[0] = 0;
6298                 displayselected = 0;
6299                 entername = 0;
6300             }
6301             break;
6302         case 8:
6303             fireSound();
6304             flash();
6305             if (selected <= 2)
6306                 accountactive->setDifficulty(selected);
6307             mainmenu = 5;
6308             break;
6309         case 9:
6310             if (selected < numchallengelevels && selected <= accountactive->getProgress()) {
6311                 fireSound();
6312                 flash();
6313
6314                 startbonustotal = 0;
6315
6316                 loading = 2;
6317                 loadtime = 0;
6318                 targetlevel = selected;
6319                 if (firstload)
6320                     TickOnceAfter();
6321                 else
6322                     LoadStuff();
6323                 Loadlevel(selected);
6324                 campaign = 0;
6325
6326                 mainmenu = 0;
6327                 gameon = 1;
6328                 pause_sound(stream_menutheme);
6329             }
6330             if (selected == numchallengelevels) {
6331                 fireSound();
6332                 flash();
6333                 mainmenu = 5;
6334             }
6335             break;
6336         case 10:
6337             if (selected == 3) {
6338                 fireSound();
6339                 flash();
6340                 mainmenu = 5;
6341             }
6342             break;
6343         case 18:
6344             if (selected == 1)
6345                 stereoseparation += 0.001;
6346             else {
6347                 fireSound();
6348                 if (selected == 0) {
6349                     newstereomode = (StereoMode)(newstereomode + 1);
6350                     while (!CanInitStereo(newstereomode)) {
6351                         printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode), newstereomode);
6352                         newstereomode = (StereoMode)(newstereomode + 1);
6353                         if (newstereomode >= stereoCount)
6354                             newstereomode = stereoNone;
6355                     }
6356                 } else if (selected == 2) {
6357                     stereoreverse = !stereoreverse;
6358                 } else if (selected == 3) {
6359                     flash();
6360                     mainmenu = 3;
6361
6362                     stereomode = newstereomode;
6363                     InitStereo(stereomode);
6364                 }
6365             }
6366             updateStereoConfigMenu();
6367             break;
6368         }
6369     }
6370
6371     if (Input::isKeyDown(SDLK_q) && Input::isKeyDown(SDLK_LMETA)) {
6372         tryquit = 1;
6373         if (mainmenu == 3) {
6374             SaveSettings();
6375         }
6376     }
6377
6378     OPENAL_SetFrequency(channels[stream_menutheme], 22050);
6379
6380     if (entername) {
6381         inputText(displaytext[0], &displayselected, &displaychars[0]);
6382         if (!waiting) { // the input as finished
6383             if (displaychars[0]) { // with enter
6384                 accountactive = Account::add(string(displaytext[0]));
6385
6386                 mainmenu = 8;
6387
6388                 flash();
6389
6390                 fireSound(firestartsound);
6391
6392                 for (int i = 0; i < 255; i++) {
6393                     displaytext[0][i] = 0;
6394                 }
6395                 displaychars[0] = 0;
6396
6397                 displayselected = 0;
6398             }
6399             entername = 0;
6400             LoadMenu();
6401         }
6402
6403         displayblinkdelay -= multiplier;
6404         if (displayblinkdelay <= 0) {
6405             displayblinkdelay = .3;
6406             displayblink = 1 - displayblink;
6407         }
6408     }
6409
6410     if (entername) {
6411         Menu::setText(0, displaytext[0], 20, 400, -1, -1);
6412         Menu::setText(-2, displayblink ? "_" : "", 20 + displayselected * 10, 400, -1, -1);
6413     }
6414
6415     if (oldmainmenu != mainmenu)
6416         LoadMenu();
6417     oldmainmenu = mainmenu;
6418
6419 }
6420
6421 void Game::Tick()
6422 {
6423     static XYZ facing, flatfacing;
6424     static int target;
6425
6426     for (int i = 0; i < 15; i++) {
6427         displaytime[i] += multiplier;
6428     }
6429
6430     keyboardfrozen = false;
6431     Input::Tick();
6432
6433     if (Input::isKeyPressed(SDLK_F6)) {
6434         if (Input::isKeyDown(SDLK_LSHIFT))
6435             stereoreverse = true;
6436         else
6437             stereoreverse = false;
6438
6439         if (stereoreverse)
6440             printf("Stereo reversed\n");
6441         else
6442             printf("Stereo unreversed\n");
6443     }
6444
6445     if (Input::isKeyDown(SDLK_F7)) {
6446         if (Input::isKeyDown(SDLK_LSHIFT))
6447             stereoseparation -= 0.001;
6448         else
6449             stereoseparation -= 0.010;
6450         printf("Stereo decreased increased to %f\n", stereoseparation);
6451     }
6452
6453     if (Input::isKeyDown(SDLK_F8)) {
6454         if (Input::isKeyDown(SDLK_LSHIFT))
6455             stereoseparation += 0.001;
6456         else
6457             stereoseparation += 0.010;
6458         printf("Stereo separation increased to %f\n", stereoseparation);
6459     }
6460
6461
6462     if (Input::isKeyPressed(SDLK_TAB) && tutoriallevel) {
6463         if (tutorialstage != 51)
6464             tutorialstagetime = tutorialmaxtime;
6465         emit_sound_np(consolefailsound, 128.);
6466     }
6467
6468     /*
6469     Values of mainmenu :
6470     1 Main menu
6471     2 Menu pause (resume/end game)
6472     3 Option menu
6473     4 Controls configuration menu
6474     5 Main game menu (choose level or challenge)
6475     6 Deleting user menu
6476     7 User managment menu (select/add)
6477     8 Choose difficulty menu
6478     9 Challenge level selection menu
6479     10 End of the campaign congratulation (is that really a menu?)
6480     11 Same that 9 ??? => unused
6481     18 stereo configuration
6482     */
6483
6484     if (!console) {
6485         //campaign over?
6486         if (mainmenu && endgame == 1)
6487             mainmenu = 10;
6488         //go to level select after completing a campaign level
6489         if (campaign && winfreeze && mainmenu == 0 && campaignlevels[actuallevel].choosenext == 1) {
6490             mainmenu = 5;
6491             gameon = 0;
6492             winfreeze = 0;
6493             fireSound();
6494             flash();
6495             if (musictoggle) {
6496                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6497                 emit_stream_np(stream_menutheme);
6498                 pause_sound(leveltheme);
6499             }
6500             LoadMenu();
6501         }
6502         //escape key pressed
6503         if (Input::isKeyPressed(SDLK_ESCAPE) &&
6504                 (gameon || mainmenu == 0 || (mainmenu >= 3 && mainmenu != 8 && !(mainmenu == 7 && entername)))) {
6505             selected = -1;
6506             if (mainmenu == 0 && !winfreeze)
6507                 mainmenu = 2; //pause
6508             else if (mainmenu == 1 || mainmenu == 2) {
6509                 mainmenu = 0; //unpause
6510             }
6511             //play menu theme
6512             if (musictoggle && (mainmenu == 1 || mainmenu == 2)) {
6513                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6514                 emit_stream_np(stream_menutheme);
6515                 pause_sound(leveltheme);
6516             }
6517             //on resume, play level music
6518             if (!mainmenu) {
6519                 pause_sound(stream_menutheme);
6520                 resume_stream(leveltheme);
6521             }
6522             //finished with settings menu
6523             if (mainmenu == 3) {
6524                 SaveSettings();
6525             }
6526             //effects
6527             if (mainmenu >= 3 && mainmenu != 8) {
6528                 fireSound();
6529                 flash();
6530             }
6531             //go back
6532             switch (mainmenu) {
6533             case 3:
6534             case 5:
6535                 mainmenu = gameon ? 2 : 1;
6536                 break;
6537             case 4:
6538             case 18:
6539                 mainmenu = 3;
6540                 break;
6541             case 6:
6542             case 7:
6543             case 9:
6544             case 10:
6545                 mainmenu = 5;
6546                 break;
6547             }
6548         }
6549     }
6550
6551     if (mainmenu) {
6552         MenuTick();
6553     }
6554
6555     if (!mainmenu) {
6556         if (hostile == 1)
6557             hostiletime += multiplier;
6558         else
6559             hostiletime = 0;
6560         if (!winfreeze)
6561             leveltime += multiplier;
6562
6563         //keys
6564         if (Input::isKeyPressed(SDLK_v) && debugmode) {
6565             freeze = 1 - freeze;
6566             if (freeze) {
6567                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6568             }
6569         }
6570
6571         if (Input::isKeyPressed(chatkey) && !console && !chatting && debugmode)
6572             chatting = 1;
6573
6574         if (chatting) {
6575             inputText(displaytext[0], &displayselected, &displaychars[0]);
6576             if (!waiting) {
6577                 if (displaychars[0]) {
6578                     for (int j = 0; j < 255; j++)
6579                         displaytext[0][j] = 0;
6580                     displaychars[0] = 0;
6581                     displayselected = 0;
6582                 }
6583                 chatting = 0;
6584             }
6585
6586             displayblinkdelay -= multiplier;
6587             if (displayblinkdelay <= 0) {
6588                 displayblinkdelay = .3;
6589                 displayblink = 1 - displayblink;
6590             }
6591         }
6592         if (chatting)
6593             keyboardfrozen = true;
6594
6595         if (Input::isKeyPressed(consolekey) && debugmode) {
6596             console = !console;
6597             if (console) {
6598                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6599             } else {
6600                 freeze = 0;
6601                 waiting = false;
6602             }
6603         }
6604
6605         if (console)
6606             freeze = 1;
6607         if (console && !Input::isKeyDown(SDLK_LMETA)) {
6608             inputText(consoletext[0], &consoleselected, &consolechars[0]);
6609             if (!waiting) {
6610                 if (consolechars[0] > 0) {
6611                     consoletext[0][consolechars[0]] = '\0';
6612                     cmd_dispatch(consoletext[0]);
6613                     for (int k = 14; k >= 1; k--) {
6614                         for (int j = 0; j < 255; j++)
6615                             consoletext[k][j] = consoletext[k - 1][j];
6616                         consolechars[k] = consolechars[k - 1];
6617                     }
6618                     for (int j = 0; j < 255; j++)
6619                         consoletext[0][j] = 0;
6620                     consolechars[0] = 0;
6621                     consoleselected = 0;
6622                 }
6623             }
6624
6625             consoleblinkdelay -= multiplier;
6626             if (consoleblinkdelay <= 0) {
6627                 consoleblinkdelay = .3;
6628                 consoleblink = 1 - consoleblink;
6629             }
6630         }
6631
6632
6633
6634         if (Input::isKeyDown(SDLK_q) && Input::isKeyDown(SDLK_LMETA)) {
6635             tryquit = 1;
6636             if (mainmenu == 3) {
6637                 SaveSettings();
6638             }
6639         }
6640
6641         static int oldwinfreeze;
6642         if (winfreeze && !oldwinfreeze) {
6643             OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6644             emit_sound_np(consolesuccesssound);
6645         }
6646         if (winfreeze == 0)
6647             oldwinfreeze = winfreeze;
6648         else
6649             oldwinfreeze++;
6650
6651         if ((Input::isKeyPressed(jumpkey) || Input::isKeyPressed(SDLK_SPACE)) && !campaign)
6652             if (winfreeze)
6653                 winfreeze = 0;
6654         if ((Input::isKeyDown(SDLK_ESCAPE)) && !campaign && gameon) {
6655             if (console) {
6656                 console = false;
6657                 freeze = 0;
6658             } else if (winfreeze) {
6659                 mainmenu = 9;
6660                 gameon = 0;
6661             }
6662         }
6663
6664
6665
6666         if (!freeze && !winfreeze && !(mainmenu && gameon) && (gameon || !gamestarted)) {
6667
6668             //dialogues
6669             static float talkdelay = 0;
6670
6671             if (indialogue != -1)
6672                 talkdelay = 1;
6673             talkdelay -= multiplier;
6674
6675             if (talkdelay <= 0 && indialogue == -1 && animation[Person::players[0]->animTarget].height != highheight)
6676                 for (int i = 0; i < numdialogues; i++) {
6677                     int realdialoguetype;
6678                     bool special;
6679                     if (dialoguetype[i] > 49) {
6680                         realdialoguetype = dialoguetype[i] - 50;
6681                         special = 1;
6682                     } else if (dialoguetype[i] > 39) {
6683                         realdialoguetype = dialoguetype[i] - 40;
6684                         special = 1;
6685                     } else if (dialoguetype[i] > 29) {
6686                         realdialoguetype = dialoguetype[i] - 30;
6687                         special = 1;
6688                     } else if (dialoguetype[i] > 19) {
6689                         realdialoguetype = dialoguetype[i] - 20;
6690                         special = 1;
6691                     } else if (dialoguetype[i] > 9) {
6692                         realdialoguetype = dialoguetype[i] - 10;
6693                         special = 1;
6694                     } else {
6695                         realdialoguetype = dialoguetype[i];
6696                         special = 0;
6697                     }
6698                     if ((!hostile || dialoguetype[i] > 40 && dialoguetype[i] < 50) &&
6699                             realdialoguetype < Person::players.size() &&
6700                             realdialoguetype > 0 &&
6701                             (dialoguegonethrough[i] == 0 || !special) &&
6702                             (special || Input::isKeyPressed(attackkey))) {
6703                         if (distsq(&Person::players[0]->coords, &Person::players[realdialoguetype]->coords) < 6 ||
6704                                 Person::players[realdialoguetype]->howactive >= typedead1 ||
6705                                 dialoguetype[i] > 40 && dialoguetype[i] < 50) {
6706                             whichdialogue = i;
6707                             for (int j = 0; j < numdialogueboxes[whichdialogue]; j++) {
6708                                 Person::players[participantfocus[whichdialogue][j]]->coords = participantlocation[whichdialogue][participantfocus[whichdialogue][j]];
6709                                 Person::players[participantfocus[whichdialogue][j]]->yaw = participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
6710                                 Person::players[participantfocus[whichdialogue][j]]->targetyaw = participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
6711                                 Person::players[participantfocus[whichdialogue][j]]->velocity = 0;
6712                                 Person::players[participantfocus[whichdialogue][j]]->animTarget = Person::players[participantfocus[whichdialogue][j]]->getIdle();
6713                                 Person::players[participantfocus[whichdialogue][j]]->frameTarget = 0;
6714                             }
6715                             directing = 0;
6716                             indialogue = 0;
6717                             dialoguetime = 0;
6718                             dialoguegonethrough[i]++;
6719                             if (dialogueboxsound[whichdialogue][indialogue] != 0) {
6720                                 playdialogueboxsound();
6721                             }
6722                         }
6723                     }
6724                 }
6725
6726             windvar += multiplier;
6727             smoketex += multiplier;
6728             tutorialstagetime += multiplier;
6729
6730             //hotspots
6731             static float hotspotvisual[40];
6732             if (numhotspots) {
6733                 XYZ hotspotsprite;
6734                 if (editorenabled)
6735                     for (int i = 0; i < numhotspots; i++)
6736                         hotspotvisual[i] -= multiplier / 320;
6737
6738                 for (int i = 0; i < numhotspots; i++) {
6739                     //if(hotspottype[i]<=10)
6740                     while (hotspotvisual[i] < 0) {
6741                         hotspotsprite = 0;
6742                         hotspotsprite.x = float(abs(Random() % 100000)) / 100000 * hotspotsize[i];
6743                         hotspotsprite = DoRotation(hotspotsprite, 0, 0, Random() % 360);
6744                         hotspotsprite = DoRotation(hotspotsprite, 0, Random() % 360, 0);
6745                         hotspotsprite += hotspot[i];
6746                         Sprite::MakeSprite(breathsprite, hotspotsprite, hotspotsprite * 0, 1, 0.5, 0, 7, 0.4);
6747                         hotspotvisual[i] += 0.1 / hotspotsize[i] / hotspotsize[i] / hotspotsize[i];
6748                     }
6749                 }
6750
6751                 for (int i = 0; i < numhotspots; i++) {
6752                     if (hotspottype[i] <= 10 && hotspottype[i] > 0) {
6753                         hotspot[i] = Person::players[hotspottype[i]]->coords;
6754                     }
6755                 }
6756             }
6757
6758             //Tutorial
6759             if (tutoriallevel) {
6760                 doTutorial();
6761             }
6762
6763             //bonuses
6764             if (tutoriallevel != 1) {
6765                 if (bonustime == 0 &&
6766                         bonus != solidhit &&
6767                         bonus != spinecrusher &&
6768                         bonus != tracheotomy &&
6769                         bonus != backstab &&
6770                         bonusvalue > 10) {
6771                     emit_sound_np(consolesuccesssound);
6772                 }
6773             } else if (bonustime == 0) {
6774                 emit_sound_np(fireendsound);
6775             }
6776             if (bonustime == 0) {
6777                 if (bonus != solidhit &&
6778                         bonus != twoxcombo &&
6779                         bonus != threexcombo &&
6780                         bonus != fourxcombo &&
6781                         bonus != megacombo)
6782                     bonusnum[bonus]++;
6783                 else
6784                     bonusnum[bonus] += 0.15;
6785                 if (tutoriallevel)
6786                     bonusvalue = 0;
6787                 bonusvalue /= bonusnum[bonus];
6788                 bonustotal += bonusvalue;
6789             }
6790             bonustime += multiplier;
6791
6792             //snow effects
6793             if (environment == snowyenvironment) {
6794                 precipdelay -= multiplier;
6795                 while (precipdelay < 0) {
6796                     precipdelay += .04;
6797                     if (!detail)
6798                         precipdelay += .04;
6799                     XYZ footvel, footpoint;
6800
6801                     footvel = 0;
6802                     footpoint = viewer + viewerfacing * 6;
6803                     footpoint.y += ((float)abs(Random() % 1200)) / 100 - 6;
6804                     footpoint.x += ((float)abs(Random() % 1200)) / 100 - 6;
6805                     footpoint.z += ((float)abs(Random() % 1200)) / 100 - 6;
6806                     Sprite::MakeSprite(snowsprite, footpoint, footvel, 1, 1, 1, .1, 1);
6807                 }
6808             }
6809
6810
6811             doAerialAcrobatics();
6812
6813
6814             static XYZ oldviewer;
6815
6816             //control keys
6817             if (indialogue == -1) {
6818                 Person::players[0]->forwardkeydown = Input::isKeyDown(forwardkey);
6819                 Person::players[0]->leftkeydown = Input::isKeyDown(leftkey);
6820                 Person::players[0]->backkeydown = Input::isKeyDown(backkey);
6821                 Person::players[0]->rightkeydown = Input::isKeyDown(rightkey);
6822                 Person::players[0]->jumpkeydown = Input::isKeyDown(jumpkey);
6823                 Person::players[0]->crouchkeydown = Input::isKeyDown(crouchkey);
6824                 Person::players[0]->drawkeydown = Input::isKeyDown(drawkey);
6825                 Person::players[0]->throwkeydown = Input::isKeyDown(throwkey);
6826             } else {
6827                 Person::players[0]->forwardkeydown = 0;
6828                 Person::players[0]->leftkeydown = 0;
6829                 Person::players[0]->backkeydown = 0;
6830                 Person::players[0]->rightkeydown = 0;
6831                 Person::players[0]->jumpkeydown = 0;
6832                 Person::players[0]->crouchkeydown = 0;
6833                 Person::players[0]->drawkeydown = 0;
6834                 Person::players[0]->throwkeydown = 0;
6835             }
6836
6837             if (!Person::players[0]->jumpkeydown)
6838                 Person::players[0]->jumpclimb = 0;
6839
6840
6841             if (indialogue != -1) {
6842                 cameramode = 1;
6843                 if (directing) {
6844                     facing = 0;
6845                     facing.z = -1;
6846
6847                     facing = DoRotation(facing, -pitch, 0, 0);
6848                     facing = DoRotation(facing, 0, 0 - yaw, 0);
6849
6850                     flatfacing = 0;
6851                     flatfacing.z = -1;
6852
6853                     flatfacing = DoRotation(flatfacing, 0, -yaw, 0);
6854
6855                     if (Input::isKeyDown(forwardkey))
6856                         viewer += facing * multiplier * 4;
6857                     if (Input::isKeyDown(backkey))
6858                         viewer -= facing * multiplier * 4;
6859                     if (Input::isKeyDown(leftkey))
6860                         viewer += DoRotation(flatfacing * multiplier, 0, 90, 0) * 4;
6861                     if (Input::isKeyDown(rightkey))
6862                         viewer += DoRotation(flatfacing * multiplier, 0, -90, 0) * 4;
6863                     if (Input::isKeyDown(jumpkey))
6864                         viewer.y += multiplier * 4;
6865                     if (Input::isKeyDown(crouchkey))
6866                         viewer.y -= multiplier * 4;
6867                     if (     Input::isKeyPressed(SDLK_1) ||
6868                              Input::isKeyPressed(SDLK_2) ||
6869                              Input::isKeyPressed(SDLK_3) ||
6870                              Input::isKeyPressed(SDLK_4) ||
6871                              Input::isKeyPressed(SDLK_5) ||
6872                              Input::isKeyPressed(SDLK_6) ||
6873                              Input::isKeyPressed(SDLK_7) ||
6874                              Input::isKeyPressed(SDLK_8) ||
6875                              Input::isKeyPressed(SDLK_9) ||
6876                              Input::isKeyPressed(SDLK_0) ||
6877                              Input::isKeyPressed(SDLK_MINUS)) {
6878                         int whichend;
6879                         if (Input::isKeyPressed(SDLK_1)) whichend = 1;
6880                         if (Input::isKeyPressed(SDLK_2)) whichend = 2;
6881                         if (Input::isKeyPressed(SDLK_3)) whichend = 3;
6882                         if (Input::isKeyPressed(SDLK_4)) whichend = 4;
6883                         if (Input::isKeyPressed(SDLK_5)) whichend = 5;
6884                         if (Input::isKeyPressed(SDLK_6)) whichend = 6;
6885                         if (Input::isKeyPressed(SDLK_7)) whichend = 7;
6886                         if (Input::isKeyPressed(SDLK_8)) whichend = 8;
6887                         if (Input::isKeyPressed(SDLK_9)) whichend = 9;
6888                         if (Input::isKeyPressed(SDLK_0)) whichend = 0;
6889                         if (Input::isKeyPressed(SDLK_MINUS))
6890                             whichend = -1;
6891                         if (whichend != -1) {
6892                             participantfocus[whichdialogue][indialogue] = whichend;
6893                             participantlocation[whichdialogue][whichend] = Person::players[whichend]->coords;
6894                             participantyaw[whichdialogue][whichend] = Person::players[whichend]->yaw;
6895                         }
6896                         if (whichend == -1) {
6897                             participantfocus[whichdialogue][indialogue] = -1;
6898                         }
6899                         if (Person::players[participantfocus[whichdialogue][indialogue]]->dead) {
6900                             indialogue = -1;
6901                             directing = 0;
6902                             cameramode = 0;
6903                         }
6904                         dialoguecamera[whichdialogue][indialogue] = viewer;
6905                         dialoguecamerayaw[whichdialogue][indialogue] = yaw;
6906                         dialoguecamerapitch[whichdialogue][indialogue] = pitch;
6907                         indialogue++;
6908                         if (indialogue < numdialogueboxes[whichdialogue]) {
6909                             if (dialogueboxsound[whichdialogue][indialogue] != 0) {
6910                                 playdialogueboxsound();
6911                             }
6912                         }
6913
6914                         for (int j = 0; j < Person::players.size(); j++) {
6915                             participantfacing[whichdialogue][indialogue][j] = participantfacing[whichdialogue][indialogue - 1][j];
6916                         }
6917                     }
6918                     //TODO: should these be KeyDown or KeyPressed?
6919                     if (     Input::isKeyDown(SDLK_KP1) ||
6920                              Input::isKeyDown(SDLK_KP2) ||
6921                              Input::isKeyDown(SDLK_KP3) ||
6922                              Input::isKeyDown(SDLK_KP4) ||
6923                              Input::isKeyDown(SDLK_KP5) ||
6924                              Input::isKeyDown(SDLK_KP6) ||
6925                              Input::isKeyDown(SDLK_KP7) ||
6926                              Input::isKeyDown(SDLK_KP8) ||
6927                              Input::isKeyDown(SDLK_KP9) ||
6928                              Input::isKeyDown(SDLK_KP0)) {
6929                         int whichend;
6930                         if (Input::isKeyDown(SDLK_KP1)) whichend = 1;
6931                         if (Input::isKeyDown(SDLK_KP2)) whichend = 2;
6932                         if (Input::isKeyDown(SDLK_KP3)) whichend = 3;
6933                         if (Input::isKeyDown(SDLK_KP4)) whichend = 4;
6934                         if (Input::isKeyDown(SDLK_KP5)) whichend = 5;
6935                         if (Input::isKeyDown(SDLK_KP6)) whichend = 6;
6936                         if (Input::isKeyDown(SDLK_KP7)) whichend = 7;
6937                         if (Input::isKeyDown(SDLK_KP8)) whichend = 8;
6938                         if (Input::isKeyDown(SDLK_KP9)) whichend = 9;
6939                         if (Input::isKeyDown(SDLK_KP0)) whichend = 0;
6940                         participantfacing[whichdialogue][indialogue][whichend] = facing;
6941                     }
6942                     if (indialogue >= numdialogueboxes[whichdialogue]) {
6943                         indialogue = -1;
6944                         directing = 0;
6945                         cameramode = 0;
6946                     }
6947                 }
6948                 if (!directing) {
6949                     pause_sound(whooshsound);
6950                     viewer = dialoguecamera[whichdialogue][indialogue];
6951                     viewer.y = max((double)viewer.y, terrain.getHeight(viewer.x, viewer.z) + .1);
6952                     yaw = dialoguecamerayaw[whichdialogue][indialogue];
6953                     pitch = dialoguecamerapitch[whichdialogue][indialogue];
6954                     if (dialoguetime > 0.5)
6955                         if (     Input::isKeyPressed(SDLK_1) ||
6956                                  Input::isKeyPressed(SDLK_2) ||
6957                                  Input::isKeyPressed(SDLK_3) ||
6958                                  Input::isKeyPressed(SDLK_4) ||
6959                                  Input::isKeyPressed(SDLK_5) ||
6960                                  Input::isKeyPressed(SDLK_6) ||
6961                                  Input::isKeyPressed(SDLK_7) ||
6962                                  Input::isKeyPressed(SDLK_8) ||
6963                                  Input::isKeyPressed(SDLK_9) ||
6964                                  Input::isKeyPressed(SDLK_0) ||
6965                                  Input::isKeyPressed(SDLK_MINUS) ||
6966                                  Input::isKeyPressed(attackkey)) {
6967                             indialogue++;
6968                             if (indialogue < numdialogueboxes[whichdialogue]) {
6969                                 if (dialogueboxsound[whichdialogue][indialogue] != 0) {
6970                                     playdialogueboxsound();
6971                                     if (dialogueboxsound[whichdialogue][indialogue] == -5) {
6972                                         hotspot[numhotspots] = Person::players[0]->coords;
6973                                         hotspotsize[numhotspots] = 10;
6974                                         hotspottype[numhotspots] = -1;
6975
6976                                         numhotspots++;
6977                                     }
6978                                     if (dialogueboxsound[whichdialogue][indialogue] == -6) {
6979                                         hostile = 1;
6980                                     }
6981
6982                                     if (Person::players[participantfocus[whichdialogue][indialogue]]->dead) {
6983                                         indialogue = -1;
6984                                         directing = 0;
6985                                         cameramode = 0;
6986                                     }
6987                                 }
6988                             }
6989                         }
6990                     if (indialogue >= numdialogueboxes[whichdialogue]) {
6991                         indialogue = -1;
6992                         directing = 0;
6993                         cameramode = 0;
6994                         if (dialoguetype[whichdialogue] > 19 && dialoguetype[whichdialogue] < 30) {
6995                             hostile = 1;
6996                         }
6997                         if (dialoguetype[whichdialogue] > 29 && dialoguetype[whichdialogue] < 40) {
6998                             windialogue = true;
6999                         }
7000                         if (dialoguetype[whichdialogue] > 49 && dialoguetype[whichdialogue] < 60) {
7001                             hostile = 1;
7002                             for (int i = 1; i < Person::players.size(); i++) {
7003                                 Person::players[i]->aitype = attacktypecutoff;
7004                             }
7005                         }
7006                     }
7007                 }
7008             }
7009
7010             if (!Person::players[0]->jumpkeydown) {
7011                 Person::players[0]->jumptogglekeydown = 0;
7012             }
7013             if (Person::players[0]->jumpkeydown &&
7014                     Person::players[0]->animTarget != jumpupanim &&
7015                     Person::players[0]->animTarget != jumpdownanim &&
7016                     !Person::players[0]->isFlip())
7017                 Person::players[0]->jumptogglekeydown = 1;
7018
7019
7020             dialoguetime += multiplier;
7021             hawkyaw += multiplier * 25;
7022             realhawkcoords = 0;
7023             realhawkcoords.x = 25;
7024             realhawkcoords = DoRotation(realhawkcoords, 0, hawkyaw, 0) + hawkcoords;
7025             hawkcalldelay -= multiplier / 2;
7026
7027             if (hawkcalldelay <= 0) {
7028                 emit_sound_at(hawksound, realhawkcoords);
7029
7030                 hawkcalldelay = 16 + abs(Random() % 8);
7031             }
7032
7033             doDebugKeys();
7034
7035             doAttacks();
7036
7037             doPlayerCollisions();
7038
7039             doJumpReversals();
7040
7041             for (int k = 0; k < Person::players.size(); k++)
7042                 if (k != 0 && Person::players[k]->immobile)
7043                     Person::players[k]->coords = Person::players[k]->realoldcoords;
7044
7045             for (int k = 0; k < Person::players.size(); k++) {
7046                 if (!isnormal(Person::players[k]->coords.x) || !isnormal(Person::players[k]->coords.y) || !isnormal(Person::players[k]->coords.z)) {
7047                     if (!isnormal(Person::players[k]->coords.x) || !isnormal(Person::players[k]->coords.y) || !isnormal(Person::players[k]->coords.z)) {
7048                         Person::players[k]->DoDamage(1000);
7049                     }
7050                 }
7051             }
7052
7053             //respawn
7054             static bool respawnkeydown;
7055             if (!editorenabled &&
7056                     (whichlevel != -2 &&
7057                      (Input::isKeyDown(SDLK_z) &&
7058                       Input::isKeyDown(SDLK_LMETA) &&
7059                       debugmode) ||
7060                      (Input::isKeyDown(jumpkey) &&
7061                       !respawnkeydown &&
7062                       !oldattackkey &&
7063                       Person::players[0]->dead))) {
7064                 targetlevel = whichlevel;
7065                 loading = 1;
7066                 leveltime = 5;
7067             }
7068             if (!Input::isKeyDown(jumpkey))
7069                 respawnkeydown = 0;
7070             if (Input::isKeyDown(jumpkey))
7071                 respawnkeydown = 1;
7072
7073
7074
7075
7076             static bool movekey;
7077
7078             //?
7079             for (int i = 0; i < Person::players.size(); i++) {
7080                 static float oldtargetyaw;
7081                 if (!Person::players[i]->skeleton.free) {
7082                     oldtargetyaw = Person::players[i]->targetyaw;
7083                     if (i == 0 && indialogue == -1) {
7084                         //TODO: refactor repetitive code
7085                         if (!animation[Person::players[0]->animTarget].attack &&
7086                                 Person::players[0]->animTarget != staggerbackhighanim &&
7087                                 Person::players[0]->animTarget != staggerbackhardanim &&
7088                                 Person::players[0]->animTarget != crouchremoveknifeanim &&
7089                                 Person::players[0]->animTarget != removeknifeanim &&
7090                                 Person::players[0]->animTarget != backhandspringanim &&
7091                                 Person::players[0]->animTarget != dodgebackanim &&
7092                                 Person::players[0]->animTarget != walljumprightkickanim &&
7093                                 Person::players[0]->animTarget != walljumpleftkickanim) {
7094                             if (cameramode)
7095                                 Person::players[0]->targetyaw = 0;
7096                             else
7097                                 Person::players[0]->targetyaw = -yaw + 180;
7098                         }
7099
7100                         facing = 0;
7101                         facing.z = -1;
7102
7103                         flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
7104                         if (cameramode) {
7105                             facing = flatfacing;
7106                         } else {
7107                             facing = DoRotation(facing, -pitch, 0, 0);
7108                             facing = DoRotation(facing, 0, 0 - yaw, 0);
7109                         }
7110
7111                         Person::players[0]->lookyaw = -yaw;
7112
7113                         Person::players[i]->targetheadyaw = yaw;
7114                         Person::players[i]->targetheadpitch = pitch;
7115                     }
7116                     if (i != 0 && Person::players[i]->aitype == playercontrolled && indialogue == -1) {
7117                         if (!animation[Person::players[i]->animTarget].attack &&
7118                                 Person::players[i]->animTarget != staggerbackhighanim &&
7119                                 Person::players[i]->animTarget != staggerbackhardanim &&
7120                                 Person::players[i]->animTarget != crouchremoveknifeanim &&
7121                                 Person::players[i]->animTarget != removeknifeanim &&
7122                                 Person::players[i]->animTarget != backhandspringanim &&
7123                                 Person::players[i]->animTarget != dodgebackanim &&
7124                                 Person::players[i]->animTarget != walljumprightkickanim &&
7125                                 Person::players[i]->animTarget != walljumpleftkickanim) {
7126                             Person::players[i]->targetyaw = -Person::players[i]->lookyaw + 180;
7127                         }
7128
7129                         facing = 0;
7130                         facing.z = -1;
7131
7132                         flatfacing = DoRotation(facing, 0, Person::players[i]->yaw + 180, 0);
7133
7134                         facing = DoRotation(facing, -Person::players[i]->lookpitch, 0, 0);
7135                         facing = DoRotation(facing, 0, 0 - Person::players[i]->lookyaw, 0);
7136
7137                         Person::players[i]->targetheadyaw = Person::players[i]->lookyaw;
7138                         Person::players[i]->targetheadpitch = Person::players[i]->lookpitch;
7139                     }
7140                     if (indialogue != -1) {
7141                         Person::players[i]->targetheadyaw = 180 - roughDirection(participantfacing[whichdialogue][indialogue][i]);
7142                         Person::players[i]->targetheadpitch = pitchOf(participantfacing[whichdialogue][indialogue][i]);
7143                     }
7144
7145                     if (leveltime < .5)
7146                         numenvsounds = 0;
7147
7148                     Person::players[i]->avoidsomething = 0;
7149
7150                     //avoid flaming things
7151                     for (int j = 0; j < objects.numobjects; j++)
7152                         if (objects.onfire[j])
7153                             if (distsq(&Person::players[i]->coords, &objects.position[j]) < sq(objects.scale[j]) * 200)
7154                                 if (     distsq(&Person::players[i]->coords, &objects.position[j]) <
7155                                          distsq(&Person::players[i]->coords, &Person::players[0]->coords)) {
7156                                     Person::players[i]->collided = 0;
7157                                     Person::players[i]->avoidcollided = 1;
7158                                     if (Person::players[i]->avoidsomething == 0 ||
7159                                             distsq(&Person::players[i]->coords, &objects.position[j]) <
7160                                             distsq(&Person::players[i]->coords, &Person::players[i]->avoidwhere)) {
7161                                         Person::players[i]->avoidwhere = objects.position[j];
7162                                         Person::players[i]->avoidsomething = 1;
7163                                     }
7164                                 }
7165
7166                     //avoid flaming players
7167                     for (int j = 0; j < Person::players.size(); j++)
7168                         if (Person::players[j]->onfire)
7169                             if (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < sq(0.3) * 200)
7170                                 if (     distsq(&Person::players[i]->coords, &Person::players[j]->coords) <
7171                                          distsq(&Person::players[i]->coords, &Person::players[0]->coords)) {
7172                                     Person::players[i]->collided = 0;
7173                                     Person::players[i]->avoidcollided = 1;
7174                                     if (Person::players[i]->avoidsomething == 0 ||
7175                                             distsq(&Person::players[i]->coords, &Person::players[j]->coords) <
7176                                             distsq(&Person::players[i]->coords, &Person::players[i]->avoidwhere)) {
7177                                         Person::players[i]->avoidwhere = Person::players[j]->coords;
7178                                         Person::players[i]->avoidsomething = 1;
7179                                     }
7180                                 }
7181
7182                     if (Person::players[i]->collided > .8)
7183                         Person::players[i]->avoidcollided = 0;
7184
7185                     doAI(i);
7186
7187                     if (animation[Person::players[i]->animTarget].attack == reversed) {
7188                         //Person::players[i]->targetyaw=Person::players[i]->yaw;
7189                         Person::players[i]->forwardkeydown = 0;
7190                         Person::players[i]->leftkeydown = 0;
7191                         Person::players[i]->backkeydown = 0;
7192                         Person::players[i]->rightkeydown = 0;
7193                         Person::players[i]->jumpkeydown = 0;
7194                         Person::players[i]->attackkeydown = 0;
7195                         //Person::players[i]->crouchkeydown=0;
7196                         Person::players[i]->throwkeydown = 0;
7197                     }
7198
7199                     if (indialogue != -1) {
7200                         Person::players[i]->forwardkeydown = 0;
7201                         Person::players[i]->leftkeydown = 0;
7202                         Person::players[i]->backkeydown = 0;
7203                         Person::players[i]->rightkeydown = 0;
7204                         Person::players[i]->jumpkeydown = 0;
7205                         Person::players[i]->crouchkeydown = 0;
7206                         Person::players[i]->drawkeydown = 0;
7207                         Person::players[i]->throwkeydown = 0;
7208                     }
7209
7210                     if (Person::players[i]->collided < -.3)
7211                         Person::players[i]->collided = -.3;
7212                     if (Person::players[i]->collided > 1)
7213                         Person::players[i]->collided = 1;
7214                     Person::players[i]->collided -= multiplier * 4;
7215                     Person::players[i]->whichdirectiondelay -= multiplier;
7216                     if (Person::players[i]->avoidcollided < -.3 || Person::players[i]->whichdirectiondelay <= 0) {
7217                         Person::players[i]->avoidcollided = -.3;
7218                         Person::players[i]->whichdirection = abs(Random() % 2);
7219                         Person::players[i]->whichdirectiondelay = .4;
7220                     }
7221                     if (Person::players[i]->avoidcollided > 1)
7222                         Person::players[i]->avoidcollided = 1;
7223                     Person::players[i]->avoidcollided -= multiplier / 4;
7224                     if (!Person::players[i]->skeleton.free) {
7225                         Person::players[i]->stunned -= multiplier;
7226                         Person::players[i]->surprised -= multiplier;
7227                     }
7228                     if (i != 0 && Person::players[i]->surprised <= 0 &&
7229                             Person::players[i]->aitype == attacktypecutoff &&
7230                             !Person::players[i]->dead &&
7231                             !Person::players[i]->skeleton.free &&
7232                             animation[Person::players[i]->animTarget].attack == neutral)
7233                         numresponded = 1;
7234
7235                     if (!Person::players[i]->throwkeydown)
7236                         Person::players[i]->throwtogglekeydown = 0;
7237
7238                     //pick up weapon
7239                     if (Person::players[i]->throwkeydown && !Person::players[i]->throwtogglekeydown) {
7240                         if (Person::players[i]->weaponactive == -1 &&
7241                                 Person::players[i]->num_weapons < 2 &&
7242                                 (Person::players[i]->isIdle() ||
7243                                  Person::players[i]->isCrouch() ||
7244                                  Person::players[i]->animTarget == sneakanim ||
7245                                  Person::players[i]->animTarget == rollanim ||
7246                                  Person::players[i]->animTarget == backhandspringanim ||
7247                                  Person::players[i]->isFlip() ||
7248                                  Person::players[i]->isFlip() ||
7249                                  Person::players[i]->aitype != playercontrolled)) {
7250                             for (int j = 0; j < weapons.size(); j++) {
7251                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
7252                                         Person::players[i]->aitype == playercontrolled) &&
7253                                         weapons[j].owner == -1 &&
7254                                         Person::players[i]->weaponactive == -1)
7255                                     if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2) {
7256                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 2) {
7257                                             if (Person::players[i]->isCrouch() ||
7258                                                     Person::players[i]->animTarget == sneakanim ||
7259                                                     Person::players[i]->isRun() ||
7260                                                     Person::players[i]->isIdle() ||
7261                                                     Person::players[i]->aitype != playercontrolled) {
7262                                                 Person::players[i]->throwtogglekeydown = 1;
7263                                                 Person::players[i]->setAnimation(crouchremoveknifeanim);
7264                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[j].position);
7265                                                 Person::players[i]->hasvictim = 0;
7266                                             }
7267                                             if (Person::players[i]->animTarget == rollanim || Person::players[i]->animTarget == backhandspringanim) {
7268                                                 Person::players[i]->throwtogglekeydown = 1;
7269                                                 Person::players[i]->hasvictim = 0;
7270
7271                                                 if ((weapons[j].velocity.x == 0 && weapons[j].velocity.y == 0 && weapons[j].velocity.z == 0 ||
7272                                                         Person::players[i]->aitype == playercontrolled) &&
7273                                                         weapons[j].owner == -1 ||
7274                                                         Person::players[i]->victim &&
7275                                                         weapons[j].owner == Person::players[i]->victim->id)
7276                                                     if (distsqflat(&Person::players[i]->coords, &weapons[j].position) < 2 && Person::players[i]->weaponactive == -1)
7277                                                         if (distsq(&Person::players[i]->coords, &weapons[j].position) < 1 || Person::players[i]->victim) {
7278                                                             if (weapons[j].getType() != staff)
7279                                                                 emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
7280
7281                                                             Person::players[i]->weaponactive = 0;
7282                                                             weapons[j].owner = Person::players[i]->id;
7283                                                             if (Person::players[i]->num_weapons > 0)
7284                                                                 Person::players[i]->weaponids[Person::players[i]->num_weapons] = Person::players[i]->weaponids[0];
7285                                                             Person::players[i]->num_weapons++;
7286                                                             Person::players[i]->weaponids[0] = j;
7287                                                         }
7288                                             }
7289                                         } else if ((Person::players[i]->isIdle() ||
7290                                                     Person::players[i]->isFlip() ||
7291                                                     Person::players[i]->aitype != playercontrolled) &&
7292                                                    distsq(&Person::players[i]->coords, &weapons[j].position) < 5 &&
7293                                                    Person::players[i]->coords.y < weapons[j].position.y) {
7294                                             if (!Person::players[i]->isFlip()) {
7295                                                 Person::players[i]->throwtogglekeydown = 1;
7296                                                 Person::players[i]->setAnimation(removeknifeanim);
7297                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, weapons[j].position);
7298                                             }
7299                                             if (Person::players[i]->isFlip()) {
7300                                                 Person::players[i]->throwtogglekeydown = 1;
7301                                                 Person::players[i]->hasvictim = 0;
7302
7303                                                 for (int k = 0; k < weapons.size(); k++) {
7304                                                     if (Person::players[i]->weaponactive == -1)
7305                                                         if ((weapons[k].velocity.x == 0 && weapons[k].velocity.y == 0 && weapons[k].velocity.z == 0 ||
7306                                                                 Person::players[i]->aitype == playercontrolled) &&
7307                                                                 weapons[k].owner == -1 ||
7308                                                                 Person::players[i]->victim &&
7309                                                                 weapons[k].owner == Person::players[i]->victim->id)
7310                                                             if (distsqflat(&Person::players[i]->coords, &weapons[k].position) < 3 &&
7311                                                                     Person::players[i]->weaponactive == -1) {
7312                                                                 if (weapons[k].getType() != staff)
7313                                                                     emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
7314
7315                                                                 Person::players[i]->weaponactive = 0;
7316                                                                 weapons[k].owner = Person::players[i]->id;
7317                                                                 if (Person::players[i]->num_weapons > 0)
7318                                                                     Person::players[i]->weaponids[Person::players[i]->num_weapons] = Person::players[i]->weaponids[0];
7319                                                                 Person::players[i]->num_weapons++;
7320                                                                 Person::players[i]->weaponids[0] = k;
7321                                                             }
7322                                                 }
7323                                             }
7324                                         }
7325                                     }
7326                             }
7327                             if (Person::players[i]->isCrouch() ||
7328                                     Person::players[i]->animTarget == sneakanim ||
7329                                     Person::players[i]->isRun() ||
7330                                     Person::players[i]->isIdle() || Person::players[i]->animTarget == rollanim ||
7331                                     Person::players[i]->animTarget == backhandspringanim) {
7332                                 if (Person::players.size() > 1)
7333                                     for (int j = 0; j < Person::players.size(); j++) {
7334                                         if (Person::players[i]->weaponactive == -1)
7335                                             if (j != i)
7336                                                 if (Person::players[j]->num_weapons &&
7337                                                         Person::players[j]->skeleton.free &&
7338                                                         distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 2/*&&Person::players[j]->dead*/ &&
7339                                                         (((Person::players[j]->skeleton.forward.y < 0 &&
7340                                                            Person::players[j]->weaponstuckwhere == 0) ||
7341                                                           (Person::players[j]->skeleton.forward.y > 0 &&
7342                                                            Person::players[j]->weaponstuckwhere == 1)) ||
7343                                                          Person::players[j]->weaponstuck == -1 ||
7344                                                          Person::players[j]->num_weapons > 1)) {
7345                                                     if (Person::players[i]->animTarget != rollanim && Person::players[i]->animTarget != backhandspringanim) {
7346                                                         Person::players[i]->throwtogglekeydown = 1;
7347                                                         Person::players[i]->victim = Person::players[j];
7348                                                         Person::players[i]->hasvictim = 1;
7349                                                         Person::players[i]->setAnimation(crouchremoveknifeanim);
7350                                                         Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[j]->coords);
7351                                                     }
7352                                                     if (Person::players[i]->animTarget == rollanim || Person::players[i]->animTarget == backhandspringanim) {
7353                                                         Person::players[i]->throwtogglekeydown = 1;
7354                                                         Person::players[i]->victim = Person::players[j];
7355                                                         Person::players[i]->hasvictim = 1;
7356                                                         int k = Person::players[j]->weaponids[0];
7357                                                         if (Person::players[i]->hasvictim) {
7358                                                             bool fleshstuck;
7359                                                             fleshstuck = 0;
7360                                                             if (Person::players[i]->victim->weaponstuck != -1) {
7361                                                                 if (Person::players[i]->victim->weaponids[Person::players[i]->victim->weaponstuck] == k) {
7362                                                                     fleshstuck = 1;
7363                                                                 }
7364                                                             }
7365                                                             if (!fleshstuck) {
7366                                                                 if (weapons[k].getType() != staff)
7367                                                                     emit_sound_at(knifedrawsound, Person::players[i]->coords, 128.);
7368                                                             }
7369                                                             if (fleshstuck)
7370                                                                 emit_sound_at(fleshstabremovesound, Person::players[i]->coords, 128.);
7371
7372                                                             Person::players[i]->weaponactive = 0;
7373                                                             if (weapons[k].owner != -1) {
7374                                                                 if (Person::players[i]->victim->num_weapons == 1)
7375                                                                     Person::players[i]->victim->num_weapons = 0;
7376                                                                 else
7377                                                                     Person::players[i]->victim->num_weapons = 1;
7378
7379                                                                 Person::players[i]->victim->skeleton.longdead = 0;
7380                                                                 Person::players[i]->victim->skeleton.free = 1;
7381                                                                 Person::players[i]->victim->skeleton.broken = 0;
7382
7383                                                                 for (int l = 0; l < Person::players[i]->victim->skeleton.num_joints; l++) {
7384                                                                     Person::players[i]->victim->skeleton.joints[l].velchange = 0;
7385                                                                     Person::players[i]->victim->skeleton.joints[l].locked = 0;
7386                                                                 }
7387
7388                                                                 XYZ relative;
7389                                                                 relative = 0;
7390                                                                 relative.y = 10;
7391                                                                 Normalise(&relative);
7392                                                                 XYZ footvel, footpoint;
7393                                                                 footvel = 0;
7394                                                                 footpoint = weapons[k].position;
7395                                                                 if (Person::players[i]->victim->weaponstuck != -1) {
7396                                                                     if (Person::players[i]->victim->weaponids[Person::players[i]->victim->weaponstuck] == k) {
7397                                                                         if (bloodtoggle)
7398                                                                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
7399                                                                         weapons[k].bloody = 2;
7400                                                                         weapons[k].blooddrip = 5;
7401                                                                         Person::players[i]->victim->weaponstuck = -1;
7402                                                                         Person::players[i]->victim->bloodloss += 2000;
7403                                                                         Person::players[i]->victim->DoDamage(2000);
7404                                                                     }
7405                                                                 }
7406                                                                 if (Person::players[i]->victim->num_weapons > 0) {
7407                                                                     if (Person::players[i]->victim->weaponstuck != 0 && Person::players[i]->victim->weaponstuck != -1)
7408                                                                         Person::players[i]->victim->weaponstuck = 0;
7409                                                                     if (Person::players[i]->victim->weaponids[0] == k)
7410                                                                         Person::players[i]->victim->weaponids[0] = Person::players[i]->victim->weaponids[Person::players[i]->victim->num_weapons];
7411                                                                 }
7412
7413                                                                 Person::players[i]->victim->weaponactive = -1;
7414
7415                                                                 Person::players[i]->victim->jointVel(abdomen) += relative * 6;
7416                                                                 Person::players[i]->victim->jointVel(neck) += relative * 6;
7417                                                                 Person::players[i]->victim->jointVel(rightshoulder) += relative * 6;
7418                                                                 Person::players[i]->victim->jointVel(leftshoulder) += relative * 6;
7419                                                             }
7420                                                             weapons[k].owner = i;
7421                                                             if (Person::players[i]->num_weapons > 0) {
7422                                                                 Person::players[i]->weaponids[Person::players[i]->num_weapons] = Person::players[i]->weaponids[0];
7423                                                             }
7424                                                             Person::players[i]->num_weapons++;
7425                                                             Person::players[i]->weaponids[0] = k;
7426                                                         }
7427                                                     }
7428                                                 }
7429                                     }
7430                             }
7431                         }
7432                         if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
7433                             if (weapons[Person::players[i]->weaponids[0]].getType() == knife) {
7434                                 if (Person::players[i]->isIdle() ||
7435                                         Person::players[i]->isRun() ||
7436                                         Person::players[i]->isCrouch() ||
7437                                         Person::players[i]->animTarget == sneakanim ||
7438                                         Person::players[i]->isFlip())
7439                                     if (Person::players.size() > 1)
7440                                         for (int j = 0; j < Person::players.size(); j++) {
7441                                             if (i != j)
7442                                                 if (tutoriallevel != 1 || tutorialstage == 49)
7443                                                     if (hostile)
7444                                                         if (normaldotproduct(Person::players[i]->facing, Person::players[i]->coords - Person::players[j]->coords) < 0 &&
7445                                                                 distsq(&Person::players[i]->coords, &Person::players[j]->coords) < 100 &&
7446                                                                 distsq(&Person::players[i]->coords, &Person::players[j]->coords) > 1.5 &&
7447                                                                 !Person::players[j]->skeleton.free &&
7448                                                                 -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)) {
7449                                                             if (!Person::players[i]->isFlip()) {
7450                                                                 Person::players[i]->throwtogglekeydown = 1;
7451                                                                 Person::players[i]->victim = Person::players[j];
7452                                                                 Person::players[i]->setAnimation(knifethrowanim);
7453                                                                 Person::players[i]->targetyaw = roughDirectionTo(Person::players[i]->coords, Person::players[j]->coords);
7454                                                                 Person::players[i]->targettilt2 = pitchTo(Person::players[i]->coords, Person::players[j]->coords);
7455                                                             }
7456                                                             if (Person::players[i]->isFlip()) {
7457                                                                 if (Person::players[i]->weaponactive != -1) {
7458                                                                     Person::players[i]->throwtogglekeydown = 1;
7459                                                                     Person::players[i]->victim = Person::players[j];
7460                                                                     XYZ aim;
7461                                                                     weapons[Person::players[i]->weaponids[0]].owner = -1;
7462                                                                     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);
7463                                                                     Normalise(&aim);
7464
7465                                                                     aim = DoRotation(aim, (float)abs(Random() % 30) - 15, (float)abs(Random() % 30) - 15, 0);
7466
7467                                                                     weapons[Person::players[i]->weaponids[0]].velocity = aim * 50;
7468                                                                     weapons[Person::players[i]->weaponids[0]].tipvelocity = aim * 50;
7469                                                                     weapons[Person::players[i]->weaponids[0]].missed = 0;
7470                                                                     weapons[Person::players[i]->weaponids[0]].freetime = 0;
7471                                                                     weapons[Person::players[i]->weaponids[0]].firstfree = 1;
7472                                                                     weapons[Person::players[i]->weaponids[0]].physics = 0;
7473                                                                     Person::players[i]->num_weapons--;
7474                                                                     if (Person::players[i]->num_weapons) {
7475                                                                         Person::players[i]->weaponids[0] = Person::players[i]->weaponids[Person::players[i]->num_weapons];
7476                                                                     }
7477                                                                     Person::players[i]->weaponactive = -1;
7478                                                                 }
7479                                                             }
7480                                                         }
7481                                         }
7482                             }
7483                         }
7484                         if (Person::players[i]->weaponactive != -1 && Person::players[i]->aitype == playercontrolled) {
7485                             if (Person::players[i]->isCrouch() || Person::players[i]->animTarget == sneakanim) {
7486                                 Person::players[i]->throwtogglekeydown = 1;
7487                                 weapons[Person::players[i]->weaponids[0]].owner = -1;
7488                                 weapons[Person::players[i]->weaponids[0]].velocity = Person::players[i]->velocity * .2;
7489                                 if (weapons[Person::players[i]->weaponids[0]].velocity.x == 0)
7490                                     weapons[Person::players[i]->weaponids[0]].velocity.x = .1;
7491                                 weapons[Person::players[i]->weaponids[0]].tipvelocity = weapons[Person::players[i]->weaponids[0]].velocity;
7492                                 weapons[Person::players[i]->weaponids[0]].missed = 1;
7493                                 weapons[Person::players[i]->weaponids[0]].freetime = 0;
7494                                 weapons[Person::players[i]->weaponids[0]].firstfree = 1;
7495                                 weapons[Person::players[i]->weaponids[0]].physics = 1;
7496                                 Person::players[i]->num_weapons--;
7497                                 if (Person::players[i]->num_weapons) {
7498                                     Person::players[i]->weaponids[0] = Person::players[i]->weaponids[Person::players[i]->num_weapons];
7499                                     if (Person::players[i]->weaponstuck == Person::players[i]->num_weapons)
7500                                         Person::players[i]->weaponstuck = 0;
7501                                 }
7502
7503                                 Person::players[i]->weaponactive = -1;
7504                                 for (int j = 0; j < Person::players.size(); j++) {
7505                                     Person::players[j]->wentforweapon = 0;
7506                                 }
7507                             }
7508                         }
7509
7510                     }
7511
7512                     //draw weapon
7513                     if (i == 0 || !Person::players[0]->dead || (Person::players[i]->weaponactive != -1)) {
7514                         if (Person::players[i]->drawkeydown && !Person::players[i]->drawtogglekeydown ||
7515                                 (Person::players[i]->num_weapons == 2) &&
7516                                 (Person::players[i]->weaponactive == -1) &&
7517                                 Person::players[i]->isIdle() ||
7518                                 Person::players[0]->dead &&
7519                                 (Person::players[i]->weaponactive != -1) &&
7520                                 i != 0) {
7521                             bool isgood = true;
7522                             if (Person::players[i]->weaponactive != -1)
7523                                 if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == staff)
7524                                     isgood = false;
7525                             if (isgood && Person::players[i]->creature != wolftype) {
7526                                 if (Person::players[i]->isIdle() && Person::players[i]->num_weapons && weapons[Person::players[i]->weaponids[0]].getType() == knife) {
7527                                     Person::players[i]->setAnimation(drawrightanim);
7528                                     Person::players[i]->drawtogglekeydown = 1;
7529                                 }
7530                                 if ((Person::players[i]->isIdle() ||
7531                                         (Person::players[i]->aitype != playercontrolled &&
7532                                          Person::players[0]->weaponactive != -1 &&
7533                                          Person::players[i]->isRun())) &&
7534                                         Person::players[i]->num_weapons &&
7535                                         weapons[Person::players[i]->weaponids[0]].getType() == sword) {
7536                                     Person::players[i]->setAnimation(drawleftanim);
7537                                     Person::players[i]->drawtogglekeydown = 1;
7538                                 }
7539                                 if (Person::players[i]->isCrouch() && Person::players[i]->num_weapons && weapons[Person::players[i]->weaponids[0]].getType() == knife) {
7540                                     Person::players[i]->setAnimation(crouchdrawrightanim);
7541                                     Person::players[i]->drawtogglekeydown = 1;
7542                                 }
7543                             }
7544                         }
7545                     }
7546
7547                     //clean weapon
7548                     if (Person::players[i]->weaponactive != -1) {
7549                         if (Person::players[i]->isCrouch() &&
7550                                 weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].bloody &&
7551                                 bloodtoggle &&
7552                                 Person::players[i]->onterrain &&
7553                                 Person::players[i]->num_weapons &&
7554                                 Person::players[i]->attackkeydown &&
7555                                 musictype != stream_fighttheme) {
7556                             if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == knife)
7557                                 Person::players[i]->setAnimation(crouchstabanim);
7558                             if (weapons[Person::players[i]->weaponids[Person::players[i]->weaponactive]].getType() == sword)
7559                                 Person::players[i]->setAnimation(swordgroundstabanim);
7560                             Person::players[i]->hasvictim = 0;
7561                         }
7562                     }
7563
7564                     if (!Person::players[i]->drawkeydown)
7565                         Person::players[i]->drawtogglekeydown = 0;
7566
7567                     XYZ absflatfacing;
7568                     if (i == 0) {
7569                         absflatfacing = 0;
7570                         absflatfacing.z = -1;
7571
7572                         absflatfacing = DoRotation(absflatfacing, 0, -yaw, 0);
7573                     } else
7574                         absflatfacing = flatfacing;
7575
7576                     if (indialogue != -1) {
7577                         Person::players[i]->forwardkeydown = 0;
7578                         Person::players[i]->leftkeydown = 0;
7579                         Person::players[i]->backkeydown = 0;
7580                         Person::players[i]->rightkeydown = 0;
7581                         Person::players[i]->jumpkeydown = 0;
7582                         Person::players[i]->crouchkeydown = 0;
7583                         Person::players[i]->drawkeydown = 0;
7584                         Person::players[i]->throwkeydown = 0;
7585                     }
7586                     movekey = 0;
7587                     //Do controls
7588                     if (!animation[Person::players[i]->animTarget].attack &&
7589                             Person::players[i]->animTarget != staggerbackhighanim &&
7590                             Person::players[i]->animTarget != staggerbackhardanim &&
7591                             Person::players[i]->animTarget != backhandspringanim &&
7592                             Person::players[i]->animTarget != dodgebackanim) {
7593                         if (!Person::players[i]->forwardkeydown)
7594                             Person::players[i]->forwardstogglekeydown = 0;
7595                         if (Person::players[i]->crouchkeydown) {
7596                             //Crouch
7597                             target = -2;
7598                             if (i == 0) {
7599                                 Person::players[i]->superruntoggle = 1;
7600                                 if (Person::players.size() > 1)
7601                                     for (int j = 0; j < Person::players.size(); j++)
7602                                         if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->aitype == passivetype)
7603                                             if (distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 16)
7604                                                 Person::players[i]->superruntoggle = 0;
7605                             }
7606
7607                             if (Person::players.size() > 1)
7608                                 for (int j = 0; j < Person::players.size(); j++) {
7609                                     if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->victim && Person::players[i]->lowreversaldelay <= 0) {
7610                                         if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
7611                                                 Person::players[j]->victim == Person::players[i] &&
7612                                                 (Person::players[j]->animTarget == sweepanim ||
7613                                                  Person::players[j]->animTarget == upunchanim ||
7614                                                  Person::players[j]->animTarget == wolfslapanim ||
7615                                                  ((Person::players[j]->animTarget == swordslashanim ||
7616                                                    Person::players[j]->animTarget == knifeslashstartanim ||
7617                                                    Person::players[j]->animTarget == staffhitanim ||
7618                                                    Person::players[j]->animTarget == staffspinhitanim) &&
7619                                                   distsq(&Person::players[j]->coords, &Person::players[i]->coords) < 2))) {
7620                                             if (target >= 0)
7621                                                 target = -1;
7622                                             else
7623                                                 target = j;
7624                                         }
7625                                     }
7626                                 }
7627                             if (target >= 0)
7628                                 Person::players[target]->Reverse();
7629                             Person::players[i]->lowreversaldelay = .5;
7630
7631                             if (Person::players[i]->isIdle()) {
7632                                 Person::players[i]->setAnimation(Person::players[i]->getCrouch());
7633                                 Person::players[i]->transspeed = 10;
7634                             }
7635                             if (Person::players[i]->isRun() ||
7636                                     (Person::players[i]->isStop() &&
7637                                      (Person::players[i]->leftkeydown ||
7638                                       Person::players[i]->rightkeydown ||
7639                                       Person::players[i]->forwardkeydown ||
7640                                       Person::players[i]->backkeydown))) {
7641                                 Person::players[i]->setAnimation(rollanim);
7642                                 Person::players[i]->transspeed = 20;
7643                             }
7644                         }
7645                         if (!Person::players[i]->crouchkeydown) {
7646                             //Uncrouch
7647                             if (!Person::players[i]->isRun() && Person::players[i]->animTarget != sneakanim && i == 0)
7648                                 Person::players[i]->superruntoggle = 0;
7649                             target = -2;
7650                             if (Person::players[i]->isCrouch()) {
7651                                 if (Person::players.size() > 1)
7652                                     for (int j = 0; j < Person::players.size(); j++) {
7653                                         if (j != i &&
7654                                                 !Person::players[j]->skeleton.free &&
7655                                                 Person::players[j]->victim &&
7656                                                 Person::players[i]->highreversaldelay <= 0) {
7657                                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
7658                                                     Person::players[j]->victim == Person::players[i] &&
7659                                                     (Person::players[j]->animTarget == spinkickanim) &&
7660                                                     Person::players[i]->isCrouch()) {
7661                                                 if (target >= 0)
7662                                                     target = -1;
7663                                                 else
7664                                                     target = j;
7665                                             }
7666                                         }
7667                                     }
7668                                 if (target >= 0)
7669                                     Person::players[target]->Reverse();
7670                                 Person::players[i]->highreversaldelay = .5;
7671
7672                                 if (Person::players[i]->isCrouch()) {
7673                                     if (!Person::players[i]->wasCrouch()) {
7674                                         Person::players[i]->animCurrent = Person::players[i]->getCrouch();
7675                                         Person::players[i]->frameCurrent = 0;
7676                                     }
7677                                     Person::players[i]->setAnimation(Person::players[i]->getIdle());
7678                                     Person::players[i]->transspeed = 10;
7679                                 }
7680                             }
7681                             if (Person::players[i]->animTarget == sneakanim) {
7682                                 Person::players[i]->setAnimation(Person::players[i]->getIdle());
7683                                 Person::players[i]->transspeed = 10;
7684                             }
7685                         }
7686                         if (Person::players[i]->forwardkeydown) {
7687                             if (Person::players[i]->isIdle() ||
7688                                     (Person::players[i]->isStop() &&
7689                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
7690                                     (Person::players[i]->isLanding() &&
7691                                      Person::players[i]->frameTarget > 0 &&
7692                                      !Person::players[i]->jumpkeydown) ||
7693                                     (Person::players[i]->isLandhard() &&
7694                                      Person::players[i]->frameTarget > 0 &&
7695                                      !Person::players[i]->jumpkeydown &&
7696                                      Person::players[i]->crouchkeydown)) {
7697                                 if (Person::players[i]->aitype == passivetype)
7698                                     Person::players[i]->setAnimation(walkanim);
7699                                 else
7700                                     Person::players[i]->setAnimation(Person::players[i]->getRun());
7701                             }
7702                             if (Person::players[i]->isCrouch()) {
7703                                 Person::players[i]->animTarget = sneakanim;
7704                                 if (Person::players[i]->wasCrouch())
7705                                     Person::players[i]->target = 0;
7706                                 Person::players[i]->frameTarget = 0;
7707                             }
7708                             if (Person::players[i]->animTarget == hanganim/*&&(!Person::players[i]->forwardstogglekeydown||Person::players[i]->aitype!=playercontrolled)*/) {
7709                                 Person::players[i]->setAnimation(climbanim);
7710                                 Person::players[i]->frameTarget = 1;
7711                                 Person::players[i]->jumpclimb = 1;
7712                             }
7713                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
7714                                 Person::players[i]->velocity += absflatfacing * 5 * multiplier;
7715                             }
7716                             Person::players[i]->forwardstogglekeydown = 1;
7717                             movekey = 1;
7718                         }
7719                         if (Person::players[i]->rightkeydown) {
7720                             if (Person::players[i]->isIdle() ||
7721                                     (Person::players[i]->isStop() &&
7722                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
7723                                     (Person::players[i]->isLanding() &&
7724                                      Person::players[i]->frameTarget > 0 &&
7725                                      !Person::players[i]->jumpkeydown) ||
7726                                     (Person::players[i]->isLandhard() &&
7727                                      Person::players[i]->frameTarget > 0 &&
7728                                      !Person::players[i]->jumpkeydown &&
7729                                      Person::players[i]->crouchkeydown)) {
7730                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
7731                             }
7732                             if (Person::players[i]->isCrouch()) {
7733                                 Person::players[i]->animTarget = sneakanim;
7734                                 if (Person::players[i]->wasCrouch())
7735                                     Person::players[i]->target = 0;
7736                                 Person::players[i]->frameTarget = 0;
7737                             }
7738                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
7739                                 Person::players[i]->velocity += DoRotation(absflatfacing * 5 * multiplier, 0, -90, 0);
7740                             }
7741                             Person::players[i]->targetyaw -= 90;
7742                             if (Person::players[i]->forwardkeydown)
7743                                 Person::players[i]->targetyaw += 45;
7744                             if (Person::players[i]->backkeydown)
7745                                 Person::players[i]->targetyaw -= 45;
7746                             movekey = 1;
7747                         }
7748                         if ( Person::players[i]->leftkeydown) {
7749                             if (Person::players[i]->isIdle() ||
7750                                     (Person::players[i]->isStop() &&
7751                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
7752                                     (Person::players[i]->isLanding() &&
7753                                      Person::players[i]->frameTarget > 0 &&
7754                                      !Person::players[i]->jumpkeydown) ||
7755                                     (Person::players[i]->isLandhard() &&
7756                                      Person::players[i]->frameTarget > 0 &&
7757                                      !Person::players[i]->jumpkeydown &&
7758                                      Person::players[i]->crouchkeydown)) {
7759                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
7760                             }
7761                             if (Person::players[i]->isCrouch()) {
7762                                 Person::players[i]->animTarget = sneakanim;
7763                                 if (Person::players[i]->wasCrouch())
7764                                     Person::players[i]->target = 0;
7765                                 Person::players[i]->frameTarget = 0;
7766                             }
7767                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
7768                                 Person::players[i]->velocity -= DoRotation(absflatfacing * 5 * multiplier, 0, -90, 0);
7769                             }
7770                             Person::players[i]->targetyaw += 90;
7771                             if (Person::players[i]->forwardkeydown)
7772                                 Person::players[i]->targetyaw -= 45;
7773                             if (Person::players[i]->backkeydown)
7774                                 Person::players[i]->targetyaw += 45;
7775                             movekey = 1;
7776                         }
7777                         if (Person::players[i]->backkeydown) {
7778                             if (Person::players[i]->isIdle() ||
7779                                     (Person::players[i]->isStop() &&
7780                                      Person::players[i]->targetyaw == Person::players[i]->yaw) ||
7781                                     (Person::players[i]->isLanding() &&
7782                                      Person::players[i]->frameTarget > 0 &&
7783                                      !Person::players[i]->jumpkeydown) ||
7784                                     (Person::players[i]->isLandhard() &&
7785                                      Person::players[i]->frameTarget > 0 &&
7786                                      !Person::players[i]->jumpkeydown &&
7787                                      Person::players[i]->crouchkeydown)) {
7788                                 Person::players[i]->setAnimation(Person::players[i]->getRun());
7789                             }
7790                             if (Person::players[i]->isCrouch()) {
7791                                 Person::players[i]->animTarget = sneakanim;
7792                                 if (Person::players[i]->wasCrouch())
7793                                     Person::players[i]->target = 0;
7794                                 Person::players[i]->frameTarget = 0;
7795                             }
7796                             if (Person::players[i]->animTarget == jumpupanim || Person::players[i]->animTarget == jumpdownanim || Person::players[i]->isFlip()) {
7797                                 Person::players[i]->velocity -= absflatfacing * 5 * multiplier;
7798                             }
7799                             if (Person::players[i]->animTarget == hanganim) {
7800                                 Person::players[i]->animCurrent = jumpdownanim;
7801                                 Person::players[i]->animTarget = jumpdownanim;
7802                                 Person::players[i]->target = 0;
7803                                 Person::players[i]->frameCurrent = 0;
7804                                 Person::players[i]->frameTarget = 1;
7805                                 Person::players[i]->velocity = 0;
7806                                 Person::players[i]->velocity.y += gravity;
7807                                 Person::players[i]->coords.y -= 1.4;
7808                                 Person::players[i]->grabdelay = 1;
7809                             }
7810                             if ( !Person::players[i]->leftkeydown && !Person::players[i]->rightkeydown)
7811                                 Person::players[i]->targetyaw += 180;
7812                             movekey = 1;
7813                         }
7814                         if ((Person::players[i]->jumpkeydown && !Person::players[i]->jumpclimb) || Person::players[i]->jumpstart) {
7815                             if ((((Person::players[i]->isLanding() && Person::players[i]->frameTarget >= 3) ||
7816                                     Person::players[i]->isRun() ||
7817                                     Person::players[i]->animTarget == walkanim ||
7818                                     Person::players[i]->isCrouch() ||
7819                                     Person::players[i]->animTarget == sneakanim) &&
7820                                     Person::players[i]->jumppower > 1) &&
7821                                     ((Person::players[i]->animTarget != rabbitrunninganim &&
7822                                       Person::players[i]->animTarget != wolfrunninganim) || i != 0)) {
7823                                 Person::players[i]->jumpstart = 0;
7824                                 Person::players[i]->setAnimation(jumpupanim);
7825                                 Person::players[i]->yaw = Person::players[i]->targetyaw;
7826                                 Person::players[i]->transspeed = 20;
7827                                 Person::players[i]->FootLand(0, 1);
7828                                 Person::players[i]->FootLand(1, 1);
7829
7830                                 facing = 0;
7831                                 facing.z = -1;
7832                                 flatfacing = DoRotation(facing, 0, Person::players[i]->targetyaw + 180, 0);
7833
7834                                 if (movekey)
7835                                     Person::players[i]->velocity = flatfacing * Person::players[i]->speed * 45 * Person::players[i]->scale;
7836                                 if (!movekey)
7837                                     Person::players[i]->velocity = 0;
7838
7839                                 //Dodge sweep?
7840                                 target = -2;
7841                                 if (Person::players.size() > 1)
7842                                     for (int j = 0; j < Person::players.size(); j++) {
7843                                         if (j != i && !Person::players[j]->skeleton.free && Person::players[j]->victim) {
7844                                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 3 &&
7845                                                     (Person::players[j]->victim == Person::players[i]) &&
7846                                                     (Person::players[j]->animTarget == sweepanim)) {
7847                                                 if (target >= 0)
7848                                                     target = -1;
7849                                                 else
7850                                                     target = j;
7851                                             }
7852                                         }
7853                                     }
7854                                 if (target >= 0)
7855                                     Person::players[i]->velocity.y = 1;
7856                                 else
7857                                     if (Person::players[i]->crouchkeydown || Person::players[i]->aitype != playercontrolled) {
7858                                     Person::players[i]->velocity.y = 7;
7859                                     Person::players[i]->crouchtogglekeydown = 1;
7860                                 } else Person::players[i]->velocity.y = 5;
7861
7862                                 if (mousejump && i == 0 && debugmode) {
7863                                     if (!Person::players[i]->isLanding())
7864                                         Person::players[i]->tempdeltav = deltav;
7865                                     if (Person::players[i]->tempdeltav < 0)
7866                                         Person::players[i]->velocity.y -= (float)(Person::players[i]->tempdeltav) / multiplier / 1000;
7867                                 }
7868
7869                                 Person::players[i]->coords.y += .2;
7870                                 Person::players[i]->jumppower -= 1;
7871
7872                                 if (!i)
7873                                     emit_sound_at(whooshsound, Person::players[i]->coords, 128.);
7874
7875                                 emit_sound_at(jumpsound, Person::players[i]->coords, 128.);
7876                             }
7877                             if ((Person::players[i]->isIdle()) && Person::players[i]->jumppower > 1) {
7878                                 Person::players[i]->setAnimation(Person::players[i]->getLanding());
7879                                 Person::players[i]->frameTarget = 2;
7880                                 Person::players[i]->landhard = 0;
7881                                 Person::players[i]->jumpstart = 1;
7882                                 Person::players[i]->tempdeltav = deltav;
7883                             }
7884                             if (Person::players[i]->animTarget == jumpupanim &&
7885                                     (((!floatjump &&
7886                                        !editorenabled) ||
7887                                       !debugmode) ||
7888                                      Person::players[i]->aitype != playercontrolled)) {
7889                                 if (Person::players[i]->jumppower > multiplier * 6) {
7890                                     Person::players[i]->velocity.y += multiplier * 6;
7891                                     Person::players[i]->jumppower -= multiplier * 6;
7892                                 }
7893                                 if (Person::players[i]->jumppower <= multiplier * 6) {
7894                                     Person::players[i]->velocity.y += Person::players[i]->jumppower;
7895                                     Person::players[i]->jumppower = 0;
7896                                 }
7897                             }
7898                             if (((floatjump || editorenabled) && debugmode) && i == 0)
7899                                 Person::players[i]->velocity.y += multiplier * 30;
7900                         }
7901
7902                         if (!movekey) {
7903                             if (Person::players[i]->isRun() || Person::players[i]->animTarget == walkanim)
7904                                 Person::players[i]->setAnimation(Person::players[i]->getStop());
7905                             if (Person::players[i]->animTarget == sneakanim) {
7906                                 Person::players[i]->animTarget = Person::players[i]->getCrouch();
7907                                 if (Person::players[i]->animCurrent == sneakanim)
7908                                     Person::players[i]->target = 0;
7909                                 Person::players[i]->frameTarget = 0;
7910                             }
7911                         }
7912                         if (Person::players[i]->animTarget == walkanim &&
7913                                 (Person::players[i]->aitype == attacktypecutoff ||
7914                                  Person::players[i]->aitype == searchtype ||
7915                                  (Person::players[i]->aitype == passivetype &&
7916                                   Person::players[i]->numwaypoints <= 1)))
7917                             Person::players[i]->setAnimation(Person::players[i]->getStop());
7918                         if (Person::players[i]->isRun() && (Person::players[i]->aitype == passivetype))
7919                             Person::players[i]->setAnimation(Person::players[i]->getStop());
7920                     }
7921                 }
7922                 if (Person::players[i]->animTarget == rollanim)
7923                     Person::players[i]->targetyaw = oldtargetyaw;
7924             }
7925
7926             //Rotation
7927             for (int k = 0; k < Person::players.size(); k++) {
7928                 if (fabs(Person::players[k]->yaw - Person::players[k]->targetyaw) > 180) {
7929                     if (Person::players[k]->yaw > Person::players[k]->targetyaw)
7930                         Person::players[k]->yaw -= 360;
7931                     else
7932                         Person::players[k]->yaw += 360;
7933                 }
7934
7935                 //stop to turn in right direction
7936                 if (fabs(Person::players[k]->yaw - Person::players[k]->targetyaw) > 90 && (Person::players[k]->isRun() || Person::players[k]->animTarget == walkanim))
7937                     Person::players[k]->setAnimation(Person::players[k]->getStop());
7938
7939                 if (Person::players[k]->animTarget == backhandspringanim || Person::players[k]->animTarget == dodgebackanim)
7940                     Person::players[k]->targettilt = 0;
7941
7942                 if (Person::players[k]->animTarget != jumpupanim &&
7943                         Person::players[k]->animTarget != backhandspringanim &&
7944                         Person::players[k]->animTarget != jumpdownanim &&
7945                         !Person::players[k]->isFlip()) {
7946                     Person::players[k]->targettilt = 0;
7947                     if (Person::players[k]->jumppower < 0 && !Person::players[k]->jumpkeydown)
7948                         Person::players[k]->jumppower = 0;
7949                     Person::players[k]->jumppower += multiplier * 7;
7950                     if (Person::players[k]->isCrouch())
7951                         Person::players[k]->jumppower += multiplier * 7;
7952                     if (Person::players[k]->jumppower > 5)
7953                         Person::players[k]->jumppower = 5;
7954                 }
7955
7956                 if (Person::players[k]->isRun())
7957                     Person::players[k]->targettilt = (Person::players[k]->yaw - Person::players[k]->targetyaw) / 4;
7958
7959                 Person::players[k]->tilt = stepTowardf(Person::players[k]->tilt, Person::players[k]->targettilt, multiplier * 150);
7960                 Person::players[k]->grabdelay -= multiplier;
7961             }
7962
7963             //do animations
7964             for (int k = 0; k < Person::players.size(); k++) {
7965                 Person::players[k]->DoAnimations();
7966                 Person::players[k]->whichpatchx = Person::players[k]->coords.x / (terrain.size / subdivision * terrain.scale);
7967                 Person::players[k]->whichpatchz = Person::players[k]->coords.z / (terrain.size / subdivision * terrain.scale);
7968             }
7969
7970             //do stuff
7971             objects.DoStuff();
7972
7973             for (int j = numenvsounds - 1; j >= 0; j--) {
7974                 envsoundlife[j] -= multiplier;
7975                 if (envsoundlife[j] < 0) {
7976                     numenvsounds--;
7977                     envsoundlife[j] = envsoundlife[numenvsounds];
7978                     envsound[j] = envsound[numenvsounds];
7979                 }
7980             }
7981             if (slomo)
7982                 OPENAL_SetFrequency(OPENAL_ALL, slomofreq);
7983             else
7984                 OPENAL_SetFrequency(OPENAL_ALL, 22050);
7985
7986             if (tutoriallevel == 1) {
7987                 XYZ temp;
7988                 XYZ temp2;
7989                 XYZ temp3;
7990                 XYZ oldtemp;
7991                 XYZ oldtemp2;
7992                 temp.x = 1011;
7993                 temp.y = 84;
7994                 temp.z = 491;
7995                 temp2.x = 1025;
7996                 temp2.y = 75;
7997                 temp2.z = 447;
7998                 temp3.x = 1038;
7999                 temp3.y = 76;
8000                 temp3.z = 453;
8001                 oldtemp = temp;
8002                 oldtemp2 = temp2;
8003                 if (tutorialstage >= 51)
8004                     if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) {
8005                         OPENAL_StopSound(OPENAL_ALL);  // hack...OpenAL renderer isn't stopping music after tutorial goes to level menu...
8006                         OPENAL_SetFrequency(OPENAL_ALL, 0.001);
8007
8008                         emit_stream_np(stream_menutheme);
8009
8010                         gameon = 0;
8011                         mainmenu = 5;
8012
8013                         fireSound();
8014
8015                         flash();
8016                     }
8017                 if (tutorialstage < 51)
8018                     if (distsq(&temp, &Person::players[0]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[0]->coords) < 4) {
8019                         emit_sound_at(fireendsound, Person::players[0]->coords);
8020
8021                         Person::players[0]->coords = (oldtemp + oldtemp2) / 2;
8022
8023                         flash();
8024                     }
8025                 if (tutorialstage >= 14 && tutorialstage < 50)
8026                     if (distsq(&temp, &Person::players[1]->coords) >= distsq(&temp, &temp2) - 1 || distsq(&temp3, &Person::players[1]->coords) < 4) {
8027                         emit_sound_at(fireendsound, Person::players[1]->coords);
8028
8029                         for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
8030                             if (Random() % 2 == 0) {
8031                                 if (!Person::players[1]->skeleton.free)
8032                                     temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
8033                                 if (Person::players[1]->skeleton.free)
8034                                     temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
8035                                 if (!Person::players[1]->skeleton.free)
8036                                     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;
8037                                 if (Person::players[1]->skeleton.free)
8038                                     temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
8039                                 Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
8040                             }
8041                         }
8042
8043                         Person::players[1]->coords = (oldtemp + oldtemp2) / 2;
8044                         for (int i = 0; i < Person::players[1]->skeleton.num_joints; i++) {
8045                             Person::players[1]->skeleton.joints[i].velocity = 0;
8046                             if (Random() % 2 == 0) {
8047                                 if (!Person::players[1]->skeleton.free)
8048                                     temp2 = (Person::players[1]->coords - Person::players[1]->oldcoords) / multiplier / 2; //velocity/2;
8049                                 if (Person::players[1]->skeleton.free)
8050                                     temp2 = Person::players[1]->skeleton.joints[i].velocity * Person::players[1]->scale / 2;
8051                                 if (!Person::players[1]->skeleton.free)
8052                                     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;
8053                                 if (Person::players[1]->skeleton.free)
8054                                     temp = Person::players[1]->skeleton.joints[i].position * Person::players[1]->scale + Person::players[1]->coords;
8055                                 Sprite::MakeSprite(breathsprite, temp, temp2, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
8056                             }
8057                         }
8058                     }
8059             }
8060
8061
8062             //3d sound
8063             static float gLoc[3];
8064             gLoc[0] = viewer.x;
8065             gLoc[1] = viewer.y;
8066             gLoc[2] = viewer.z;
8067             static float vel[3];
8068             vel[0] = (viewer.x - oldviewer.x) / multiplier;
8069             vel[1] = (viewer.y - oldviewer.y) / multiplier;
8070             vel[2] = (viewer.z - oldviewer.z) / multiplier;
8071
8072             //Set orientation with forward and up vectors
8073             static XYZ upvector;
8074             upvector = 0;
8075             upvector.z = -1;
8076
8077             upvector = DoRotation(upvector, -pitch + 90, 0, 0);
8078             upvector = DoRotation(upvector, 0, 0 - yaw, 0);
8079
8080             facing = 0;
8081             facing.z = -1;
8082
8083             facing = DoRotation(facing, -pitch, 0, 0);
8084             facing = DoRotation(facing, 0, 0 - yaw, 0);
8085
8086
8087             static float ori[6];
8088             ori[0] = -facing.x;
8089             ori[1] = facing.y;
8090             ori[2] = -facing.z;
8091             ori[3] = -upvector.x;
8092             ori[4] = upvector.y;
8093             ori[5] = -upvector.z;
8094
8095             OPENAL_3D_Listener_SetAttributes(&gLoc[0], &vel[0], ori[0], ori[1], ori[2], ori[3], ori[4], ori[5]);
8096             OPENAL_Update();
8097
8098             oldviewer = viewer;
8099         }
8100     }
8101
8102     if (Input::isKeyPressed(SDLK_F1))
8103         Screenshot();
8104 }
8105
8106 void Game::TickOnce()
8107 {
8108     if (mainmenu)
8109         yaw += multiplier * 5;
8110     else if (directing || indialogue == -1) {
8111         yaw += deltah * .7;
8112         if (!invertmouse)
8113             pitch += deltav * .7;
8114         if (invertmouse)
8115             pitch -= deltav * .7;
8116         if (pitch > 90)
8117             pitch = 90;
8118         if (pitch < -70)
8119             pitch = -70;
8120     }
8121 }
8122
8123 void Game::TickOnceAfter()
8124 {
8125     static XYZ colviewer;
8126     static XYZ coltarget;
8127     static XYZ target;
8128     static XYZ col;
8129     static XYZ facing;
8130     static float changedelay;
8131     static bool alldead;
8132     static float unseendelay;
8133     static float cameraspeed;
8134
8135     if (!mainmenu) {
8136         static int oldmusictype = musictype;
8137
8138         if (environment == snowyenvironment)
8139             leveltheme = stream_snowtheme;
8140         if (environment == grassyenvironment)
8141             leveltheme = stream_grasstheme;
8142         if (environment == desertenvironment)
8143             leveltheme = stream_deserttheme;
8144
8145         realthreat = 0;
8146
8147         musictype = leveltheme;
8148         for (int i = 0; i < Person::players.size(); i++) {
8149             if ((Person::players[i]->aitype == attacktypecutoff ||
8150                     Person::players[i]->aitype == getweapontype ||
8151                     Person::players[i]->aitype == gethelptype ||
8152                     Person::players[i]->aitype == searchtype) &&
8153                     !Person::players[i]->dead/*&&Person::players[i]->surprised<=0*/ &&
8154                     (Person::players[i]->animTarget != sneakattackedanim &&
8155                      Person::players[i]->animTarget != knifesneakattackedanim &&
8156                      Person::players[i]->animTarget != swordsneakattackedanim)) {
8157                 musictype = stream_fighttheme;
8158                 realthreat = 1;
8159             }
8160         }
8161         if (Person::players[0]->dead)
8162             musictype = stream_menutheme;
8163
8164
8165         if (musictype == stream_fighttheme)
8166             unseendelay = 1;
8167
8168         if (oldmusictype == stream_fighttheme && musictype != stream_fighttheme) {
8169             unseendelay -= multiplier;
8170             if (unseendelay > 0)
8171                 musictype = stream_fighttheme;
8172         }
8173
8174
8175         if (loading == 2) {
8176             musictype = stream_menutheme;
8177             musicvolume[2] = 512;
8178             musicvolume[0] = 0;
8179             musicvolume[1] = 0;
8180             musicvolume[3] = 0;
8181         }
8182
8183         if (musictoggle)
8184             if (musictype != oldmusictype && musictype == stream_fighttheme)
8185                 emit_sound_np(alarmsound);
8186         musicselected = musictype;
8187
8188         if (musicselected == leveltheme)
8189             musicvolume[0] += multiplier * 450;
8190         else
8191             musicvolume[0] -= multiplier * 450;
8192         if (musicselected == stream_fighttheme)
8193             musicvolume[1] += multiplier * 450;
8194         else
8195             musicvolume[1] -= multiplier * 450;
8196         if (musicselected == stream_menutheme)
8197             musicvolume[2] += multiplier * 450;
8198         else
8199             musicvolume[2] -= multiplier * 450;
8200
8201         for (int i = 0; i < 3; i++) {
8202             if (musicvolume[i] < 0)
8203                 musicvolume[i] = 0;
8204             if (musicvolume[i] > 512)
8205                 musicvolume[i] = 512;
8206         }
8207
8208         if (musicvolume[2] > 128 && !loading && !mainmenu)
8209             musicvolume[2] = 128;
8210
8211         if (musictoggle) {
8212             if (musicvolume[0] > 0 && oldmusicvolume[0] <= 0)
8213                 emit_stream_np(leveltheme, musicvolume[0]);
8214             if (musicvolume[1] > 0 && oldmusicvolume[1] <= 0)
8215                 emit_stream_np(stream_fighttheme, musicvolume[1]);
8216             if (musicvolume[2] > 0 && oldmusicvolume[2] <= 0)
8217                 emit_stream_np(stream_menutheme, musicvolume[2]);
8218             if (musicvolume[0] <= 0 && oldmusicvolume[0] > 0)
8219                 pause_sound(leveltheme);
8220             if (musicvolume[1] <= 0 && oldmusicvolume[1] > 0)
8221                 pause_sound(stream_fighttheme);
8222             if (musicvolume[2] <= 0 && oldmusicvolume[2] > 0)
8223                 pause_sound(stream_menutheme);
8224
8225             if (musicvolume[0] != oldmusicvolume[0])
8226                 OPENAL_SetVolume(channels[leveltheme], musicvolume[0]);
8227             if (musicvolume[1] != oldmusicvolume[1])
8228                 OPENAL_SetVolume(channels[stream_fighttheme], musicvolume[1]);
8229             if (musicvolume[2] != oldmusicvolume[2])
8230                 OPENAL_SetVolume(channels[stream_menutheme], musicvolume[2]);
8231
8232             for (int i = 0; i < 3; i++)
8233                 oldmusicvolume[i] = musicvolume[i];
8234         } else {
8235             pause_sound(leveltheme);
8236             pause_sound(stream_fighttheme);
8237             pause_sound(stream_menutheme);
8238
8239             for (int i = 0; i < 4; i++) {
8240                 oldmusicvolume[i] = 0;
8241                 musicvolume[i] = 0;
8242             }
8243         }
8244
8245         killhotspot = 2;
8246         for (int i = 0; i < numhotspots; i++) {
8247             if (hotspottype[i] > 10 && hotspottype[i] < 20) {
8248                 if (Person::players[hotspottype[i] - 10]->dead == 0)
8249                     killhotspot = 0;
8250                 else if (killhotspot == 2)
8251                     killhotspot = 1;
8252             }
8253         }
8254         if (killhotspot == 2)
8255             killhotspot = 0;
8256
8257
8258         winhotspot = false;
8259         for (int i = 0; i < numhotspots; i++)
8260             if (hotspottype[i] == -1)
8261                 if (distsq(&Person::players[0]->coords, &hotspot[i]) < hotspotsize[i])
8262                     winhotspot = true;
8263
8264         int numalarmed = 0;
8265         for (int i = 1; i < Person::players.size(); i++)
8266             if (!Person::players[i]->dead && Person::players[i]->aitype == attacktypecutoff && Person::players[i]->surprised <= 0)
8267                 numalarmed++;
8268         if (numalarmed > maxalarmed)
8269             maxalarmed = numalarmed;
8270
8271         if (changedelay <= 0 && !loading && !editorenabled && gameon && !tutoriallevel && changedelay != -999 && !won) {
8272             if (Person::players[0]->dead && changedelay <= 0) {
8273                 changedelay = 1;
8274                 targetlevel = whichlevel;
8275             }
8276             alldead = true;
8277             for (int i = 1; i < Person::players.size(); i++) {
8278                 if (!Person::players[i]->dead && Person::players[i]->howactive < typedead1) {
8279                     alldead = false;
8280                     break;
8281                 }
8282             }
8283
8284
8285             if (alldead && !Person::players[0]->dead && maptype == mapkilleveryone) {
8286                 changedelay = 1;
8287                 targetlevel = whichlevel + 1;
8288                 if (targetlevel > numchallengelevels - 1)
8289                     targetlevel = 0;
8290             }
8291             if (winhotspot || windialogue) {
8292                 changedelay = 0.1;
8293                 targetlevel = whichlevel + 1;
8294                 if (targetlevel > numchallengelevels - 1)
8295                     targetlevel = 0;
8296             }
8297
8298
8299             if (killhotspot) {
8300                 changedelay = 1;
8301                 targetlevel = whichlevel + 1;
8302                 if (targetlevel > numchallengelevels - 1)
8303                     targetlevel = 0;
8304             }
8305
8306             if (changedelay > 0 && !Person::players[0]->dead && !won) {
8307                 //high scores, awards, win
8308                 if (campaign) {
8309                     accountactive->winCampaignLevel(whichchoice, bonustotal, leveltime);
8310                     scoreadded = 1;
8311                 } else {
8312                     accountactive->winLevel(whichlevel, bonustotal - startbonustotal, leveltime);
8313                 }
8314                 won = 1;
8315             }
8316         }
8317
8318         if (!winfreeze) {
8319
8320             if (leveltime < 1) {
8321                 loading = 0;
8322                 changedelay = .1;
8323                 alldead = false;
8324                 winhotspot = false;
8325                 killhotspot = 0;
8326             }
8327
8328             if (!editorenabled && gameon && !mainmenu) {
8329                 if (changedelay != -999)
8330                     changedelay -= multiplier / 7;
8331                 if (Person::players[0]->dead)
8332                     targetlevel = whichlevel;
8333                 if (loading == 2 && !campaign) {
8334                     flash();
8335
8336                     fireSound(firestartsound);
8337
8338                     if (!Person::players[0]->dead && targetlevel != whichlevel)
8339                         startbonustotal = bonustotal;
8340                     if (Person::players[0]->dead)
8341                         Loadlevel(whichlevel);
8342                     else
8343                         Loadlevel(targetlevel);
8344
8345                     fireSound();
8346
8347                     loading = 3;
8348                 }
8349                 if (loading == 2 && targetlevel == whichlevel) {
8350                     flash();
8351                     loadtime = 0;
8352
8353                     fireSound(firestartsound);
8354
8355                     Loadlevel(campaignlevels[accountactive->getCampaignChoicesMade()].mapname.c_str());
8356
8357                     fireSound();
8358
8359                     loading = 3;
8360                 }
8361                 if (changedelay <= -999 &&
8362                         whichlevel != -2 &&
8363                         !loading &&
8364                         (Person::players[0]->dead ||
8365                          (alldead && maptype == mapkilleveryone) ||
8366                          (winhotspot) ||
8367                          (killhotspot)))
8368                     loading = 1;
8369                 if ((Person::players[0]->dead ||
8370                         (alldead && maptype == mapkilleveryone) ||
8371                         (winhotspot) ||
8372                         (windialogue) ||
8373                         (killhotspot)) &&
8374                         changedelay <= 0) {
8375                     if (whichlevel != -2 && !loading && !Person::players[0]->dead) {
8376                         winfreeze = true;
8377                         changedelay = -999;
8378                     }
8379                     if (Person::players[0]->dead)
8380                         loading = 1;
8381                 }
8382             }
8383
8384             if (campaign) {
8385                 // campaignchoosenext determines what to do when the level is complete:
8386                 // 0 = load next level
8387                 // 1 = go back to level select screen
8388                 // 2 = stealthload next level
8389                 if (mainmenu == 0 && winfreeze && (campaignlevels[actuallevel].choosenext) == 1) {
8390                     if (campaignlevels[actuallevel].nextlevel.empty())
8391                         endgame = 1;
8392                 } else if (mainmenu == 0 && winfreeze) {
8393                     stealthloading = (campaignlevels[actuallevel].choosenext == 2);
8394
8395                     if (!stealthloading) {
8396                         fireSound(firestartsound);
8397
8398                         flash();
8399                     }
8400
8401                     startbonustotal = 0;
8402
8403                     LoadCampaign();
8404
8405                     loading = 2;
8406                     loadtime = 0;
8407                     targetlevel = 7;
8408                     if (!firstload)
8409                         LoadStuff();
8410                     whichchoice = 0;
8411                     actuallevel = campaignlevels[actuallevel].nextlevel.front();
8412                     visibleloading = 1;
8413                     stillloading = 1;
8414                     Loadlevel(campaignlevels[actuallevel].mapname.c_str());
8415                     campaign = 1;
8416                     mainmenu = 0;
8417                     gameon = 1;
8418                     pause_sound(stream_menutheme);
8419
8420                     stealthloading = 0;
8421                 }
8422             }
8423
8424             if (loading == 3)
8425                 loading = 0;
8426
8427         }
8428
8429         oldmusictype = musictype;
8430     }
8431
8432     facing = 0;
8433     facing.z = -1;
8434
8435     facing = DoRotation(facing, -pitch, 0, 0);
8436     facing = DoRotation(facing, 0, 0 - yaw, 0);
8437     viewerfacing = facing;
8438
8439     if (!cameramode) {
8440         if ((animation[Person::players[0]->animTarget].attack != 3 && animation[Person::players[0]->animCurrent].attack != 3) || Person::players[0]->skeleton.free)
8441             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;
8442         else
8443             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;
8444         target.y += .1;
8445         if (Person::players[0]->skeleton.free) {
8446             for (int i = 0; i < Person::players[0]->skeleton.num_joints; i++) {
8447                 if (Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y > target.y)
8448                     target.y = Person::players[0]->skeleton.joints[i].position.y * Person::players[0]->scale + Person::players[0]->coords.y;
8449             }
8450             target.y += .1;
8451         }
8452         if (Person::players[0]->skeleton.free != 2/*&&!autocam*/) {
8453             cameraspeed = 20;
8454             if (findLengthfast(&Person::players[0]->velocity) > 400) {
8455                 cameraspeed = 20 + (findLength(&Person::players[0]->velocity) - 20) * .96;
8456             }
8457             if (Person::players[0]->skeleton.free == 0 && Person::players[0]->animTarget != hanganim && Person::players[0]->animTarget != climbanim)
8458                 target.y += 1.4;
8459             coltarget = target - cameraloc;
8460             if (findLengthfast(&coltarget) < multiplier * multiplier * 400)
8461                 cameraloc = target;
8462             else {
8463                 Normalise(&coltarget);
8464                 if (Person::players[0]->animTarget != hanganim && Person::players[0]->animTarget != climbanim && Person::players[0]->animCurrent != climbanim && Person::players[0]->currentoffset.x == 0)
8465                     cameraloc = cameraloc + coltarget * multiplier * cameraspeed;
8466                 else
8467                     cameraloc = cameraloc + coltarget * multiplier * 8;
8468             }
8469             if (editorenabled)
8470                 cameraloc = target;
8471             cameradist += multiplier * 5;
8472             if (cameradist > 2.3)
8473                 cameradist = 2.3;
8474             viewer = cameraloc - facing * cameradist;
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)
8484                         viewer = col;
8485                 }
8486             if (terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz])
8487                 for (int j = 0; j < terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz]; j++) {
8488                     int i = terrain.patchobjects[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz][j];
8489                     colviewer = viewer;
8490                     if (objects.model[i].SphereCheck(&colviewer, .15, &col, &objects.position[i], &objects.yaw[i]) != -1) {
8491                         viewer = colviewer;
8492                     }
8493                 }
8494             cameradist = findDistance(&viewer, &target);
8495             viewer.y = max((double)viewer.y, terrain.getHeight(viewer.x, viewer.z) + .6);
8496             if (cameraloc.y < terrain.getHeight(cameraloc.x, cameraloc.z)) {
8497                 cameraloc.y = terrain.getHeight(cameraloc.x, cameraloc.z);
8498             }
8499         }
8500         /*
8501         //what did autocam do?
8502         if(Person::players[0]->skeleton.free!=2&&autocam){
8503             cameraspeed=20;
8504             if(findLengthfast(&Person::players[0]->velocity)>400){
8505                 cameraspeed=20+(findLength(&Person::players[0]->velocity)-20)*.96;
8506             }
8507             if(Person::players[0]->skeleton.free==0&&Person::players[0]->animTarget!=hanganim&&Person::players[0]->animTarget!=climbanim)target.y+=1.4;
8508             cameradist+=multiplier*5;
8509             if(cameradist>3.3)cameradist=3.3;
8510             coltarget=target-cameraloc;
8511             if(findLengthfast(&coltarget)<multiplier*multiplier*400)cameraloc=target;
8512             else if(findLengthfast(&coltarget)>1)
8513             {
8514                 Normalise(&coltarget);
8515                 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;
8516                 else cameraloc=cameraloc+coltarget*multiplier*8;
8517             }
8518             if(editorenabled)cameraloc=target;
8519             viewer=cameraloc;
8520             colviewer=viewer;
8521             coltarget=cameraloc;
8522             objects.SphereCheckPossible(&colviewer, findDistance(&colviewer,&coltarget));
8523             if(terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz])
8524                 for(int j=0;j<terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz];j++){
8525                     int i=terrain.patchobjects[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz][j];
8526                     colviewer=viewer;
8527                     coltarget=cameraloc;
8528                     if(objects.model[i].LineCheckPossible(&colviewer,&coltarget,&col,&objects.position[i],&objects.yaw[i])!=-1)viewer=col;
8529                 }
8530             if(terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz])
8531                 for(int j=0;j<terrain.patchobjectnum[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz];j++){
8532                     int i=terrain.patchobjects[Person::players[0]->whichpatchx][Person::players[0]->whichpatchz][j];
8533                     colviewer=viewer;
8534                     if(objects.model[i].SphereCheck(&colviewer,.15,&col,&objects.position[i],&objects.yaw[i])!=-1){
8535                         viewer=colviewer;
8536                     }
8537                 }
8538             cameradist=findDistance(&viewer,&target);
8539             viewer.y=max((double)viewer.y,terrain.getHeight(viewer.x,viewer.z)+.6);
8540             if(cameraloc.y<terrain.getHeight(cameraloc.x,cameraloc.z)){
8541                 cameraloc.y=terrain.getHeight(cameraloc.x,cameraloc.z);
8542             }
8543         }
8544         */
8545         if (camerashake > .8)
8546             camerashake = .8;
8547         //if(woozy>10)woozy=10;
8548         //woozy+=multiplier;
8549         woozy += multiplier;
8550         if (Person::players[0]->dead)
8551             camerashake = 0;
8552         if (Person::players[0]->dead)
8553             woozy = 0;
8554         camerashake -= multiplier * 2;
8555         blackout -= multiplier * 2;
8556         //if(Person::players[0]->isCrouch())woozy-=multiplier*8;
8557         if (camerashake < 0)
8558             camerashake = 0;
8559         if (blackout < 0)
8560             blackout = 0;
8561         //if(woozy<0)woozy=0;
8562         if (camerashake) {
8563             viewer.x += (float)(Random() % 100) * .0005 * camerashake;
8564             viewer.y += (float)(Random() % 100) * .0005 * camerashake;
8565             viewer.z += (float)(Random() % 100) * .0005 * camerashake;
8566         }
8567     }
8568 }
8569