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