]> git.jsancho.org Git - lugaru.git/blob - Source/GameTick.cpp
03c0efdd8eeac66e358032b2498821bfeb56c875
[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 extern SDL_Rect **resolutions;
5775
5776 void MenuTick(){
5777     //menu buttons
5778     selected=Menu::getSelected(mousecoordh*640/screenwidth,480-mousecoordv*480/screenheight);
5779
5780     // some specific case where we do something even if the left mouse button is not pressed.
5781         if((mainmenu==5) && (endgame==2)) {
5782                 accountactive->endGame();
5783                 endgame=0;
5784         }
5785         if(mainmenu==10)
5786                 endgame=2;
5787         if(mainmenu==18 && Input::isKeyPressed(MOUSEBUTTON2) && selected==1){
5788                 stereoseparation-=0.001;
5789         updateStereoConfigMenu();
5790     }
5791
5792     static int oldmainmenu=mainmenu;
5793
5794     char sbuf[256];
5795
5796     if(Input::MouseClicked() && (selected >= 0)) { // handling of the left mouse clic in menus
5797                 switch(mainmenu) {
5798                         case 1:
5799                         case 2:
5800                                 switch(selected) {
5801                                         case 1:
5802                                                 if(gameon) { //resume
5803                                                         mainmenu=0;
5804                                                         pause_sound(stream_menutheme);
5805                                                         resume_stream(leveltheme);
5806                                                 } else { //new game
5807                                                         fireSound(firestartsound);
5808                                                         flash();
5809                                                         mainmenu=(accountactive?5:7);
5810                                                         selected=-1;
5811                                                 }
5812                                                 break;
5813                                         case 2: //options
5814                                                 fireSound();
5815                                                 flash();
5816                                                 mainmenu=3;
5817                                                 if(newdetail>2) newdetail=detail;
5818                                                 if(newdetail<0) newdetail=detail;
5819                                                 if(newscreenwidth>3000) newscreenwidth=screenwidth;
5820                                                 if(newscreenwidth<0) newscreenwidth=screenwidth;
5821                                                 if(newscreenheight>3000) newscreenheight=screenheight;
5822                                                 if(newscreenheight<0) newscreenheight=screenheight;
5823                                                 break;
5824                                         case 3:
5825                                                 fireSound();
5826                                                 flash();
5827                                                 if(gameon){ //end game
5828                                                         gameon=0;
5829                                                         mainmenu=1;
5830                                                 } else { //quit
5831                                                         tryquit=1;
5832                                                         pause_sound(stream_menutheme);
5833                                                 }
5834                                                 break;
5835                                 }
5836                                 break;
5837                         case 3:
5838                                 fireSound();
5839                                 bool isCustomResolution,found;
5840                                 switch(selected){
5841                                         case 0:
5842                                                 isCustomResolution = true;
5843                                                 found = false;
5844                                                 for(int i = 0; (!found) && (resolutions[i]); i++) {
5845                                                         if((resolutions[i]->w == screenwidth) && (resolutions[i]->h == screenwidth))
5846                                                                 isCustomResolution = false;
5847
5848                                                         if((resolutions[i]->w == newscreenwidth) && (resolutions[i]->h == newscreenheight)) {
5849                                                                 i++;
5850                                                                 if(resolutions[i] != NULL) {
5851                                                                         newscreenwidth = (int) resolutions[i]->w;
5852                                                                         newscreenheight = (int) resolutions[i]->h;
5853                                                                 } else if(isCustomResolution){
5854                                                                         if((screenwidth == newscreenwidth) && (screenheight == newscreenheight)) {
5855                                                                                 newscreenwidth = (int) resolutions[0]->w;
5856                                                                                 newscreenheight = (int) resolutions[0]->h;
5857                                                                         } else {
5858                                                                                 newscreenwidth = screenwidth;
5859                                                                                 newscreenheight = screenheight;
5860                                                                         }
5861                                                                 } else {
5862                                                                         newscreenwidth = (int) resolutions[0]->w;
5863                                                                         newscreenheight = (int) resolutions[0]->h;
5864                                                                 }
5865                                                                 found = true;
5866                                                         }
5867                                                 }
5868
5869                                                 if(!found) {
5870                                                         newscreenwidth = (int) resolutions[0]->w;
5871                                                         newscreenheight = (int) resolutions[0]->h;
5872                                                 }
5873                                                 break;
5874                                         case 1:
5875                                                 newdetail++;
5876                                                 if(newdetail>2) newdetail=0;
5877                                                 break;
5878                                         case 2:
5879                                                 bloodtoggle++;
5880                                                 if(bloodtoggle>2) bloodtoggle=0;
5881                                                 break;
5882                                         case 3:
5883                                                 difficulty++;
5884                                                 if(difficulty>2) difficulty=0;
5885                                                 break;
5886                                         case 4:
5887                                                 ismotionblur = !ismotionblur;
5888                                                 break;
5889                                         case 5:
5890                                                 decals = !decals;
5891                                                 break;
5892                                         case 6:
5893                                                 musictoggle = !musictoggle;
5894                                                 if(musictoggle) {
5895                                                   emit_stream_np(stream_menutheme);
5896                                                 } else {
5897                                                         pause_sound(leveltheme);
5898                                                         pause_sound(stream_fighttheme);
5899                                                         pause_sound(stream_menutheme);
5900
5901                                                         for(int i=0;i<4;i++){
5902                                                                 oldmusicvolume[i]=0;
5903                                                                 musicvolume[i]=0;
5904                                                         }
5905                                                 }
5906                                                 break;
5907                                         case 7: // controls
5908                                                 flash();
5909                                                 mainmenu=4;
5910                                                 selected=-1;
5911                                                 keyselect=-1;
5912                                                 break;
5913                                         case 8:
5914                                                 flash();
5915                                                 SaveSettings();
5916                                                 mainmenu=gameon?2:1;
5917                                                 break;
5918                                         case 9:
5919                                                 invertmouse = !invertmouse;
5920                                                 break;
5921                                         case 10:
5922                                                 usermousesensitivity+=.2;
5923                                                 if(usermousesensitivity>2)
5924                             usermousesensitivity=.2;
5925                                                 break;
5926                                         case 11:
5927                                                 volume+=.1f;
5928                                                 if(volume>1.0001f)
5929                             volume=0;
5930                                                 OPENAL_SetSFXMasterVolume((int)(volume*255));
5931                                                 break;
5932                                         case 12:
5933                                                 flash();
5934                                                 newstereomode = stereomode;
5935                                                 mainmenu=18;
5936                                                 keyselect=-1;
5937                                                 break;
5938                                         case 13:
5939                                                 showdamagebar = !showdamagebar;
5940                                                 break;
5941                                 }
5942                 updateSettingsMenu();
5943                                 break;
5944                         case 4:
5945                                 if(!waiting) {
5946                                         fireSound();
5947                                         if(selected<(debugmode?10:9) && keyselect==-1)
5948                                                 keyselect=selected;
5949                                         if(keyselect!=-1)
5950                                                 setKeySelected();
5951                                         if(selected==(debugmode?10:9)){
5952                                                 flash();
5953                                                 mainmenu=3;
5954                                         }
5955                                 }
5956                 updateControlsMenu();
5957                                 break;
5958                         case 5:
5959                                 fireSound();
5960                                 flash();
5961                                 if((selected-NB_CAMPAIGN_MENU_ITEM >= accountactive->getCampaignChoicesMade())) {
5962                                         startbonustotal=0;
5963
5964                                         loading=2;
5965                                         loadtime=0;
5966                                         targetlevel=7;
5967                                         if(firstload)
5968                                                 TickOnceAfter();
5969                                         else
5970                                                 LoadStuff();
5971                                         whichchoice=selected-NB_CAMPAIGN_MENU_ITEM-accountactive->getCampaignChoicesMade();
5972                                         actuallevel=(accountactive->getCampaignChoicesMade()>0?campaignlevels[accountactive->getCampaignChoicesMade()-1].nextlevel[whichchoice]:0);
5973                                         visibleloading=1;
5974                                         stillloading=1;
5975                                         Loadlevel(campaignlevels[actuallevel].mapname.c_str());
5976                                         campaign=1;
5977                                         mainmenu=0;
5978                                         gameon=1;
5979                                         pause_sound(stream_menutheme);
5980                                 }
5981                                 switch(selected){
5982                                         case 1:
5983                                                 startbonustotal=0;
5984
5985                                                 loading=2;
5986                                                 loadtime=0;
5987                                                 targetlevel=-1;
5988                                                 if(firstload) {
5989                                                         TickOnceAfter();
5990                                                 } else
5991                                                         LoadStuff();
5992                                                 Loadlevel(-1);
5993
5994                                                 mainmenu=0;
5995                                                 gameon=1;
5996                                                 pause_sound(stream_menutheme);
5997                                                 break;
5998                                         case 2:
5999                                                 mainmenu=9;
6000                                                 break;
6001                                         case 3:
6002                                                 mainmenu=6;
6003                                                 break;
6004                                         case 4:
6005                                                 mainmenu=(gameon?2:1);
6006                                                 break;
6007                                         case 5:
6008                                                 mainmenu=7;
6009                                                 break;
6010                                         case 6:
6011                                                 vector<string> campaigns = ListCampaigns();
6012                                                 vector<string>::iterator c;
6013                                                 if ((c = find(campaigns.begin(),campaigns.end(),accountactive->getCurrentCampaign()))==campaigns.end()) {
6014                                                         if(!campaigns.empty())
6015                                                                 accountactive->setCurrentCampaign(campaigns.front());
6016                                                 } else {
6017                                                         c++;
6018                                                         if(c==campaigns.end())
6019                                                                 c=campaigns.begin();
6020                                                         accountactive->setCurrentCampaign(*c);
6021                                                 }
6022                                                 LoadMenu();
6023                                                 break;
6024                                 }
6025                                 break;
6026                         case 6:
6027                                 fireSound();
6028                                 if(selected==1) {
6029                                         flash();
6030                                         accountactive = Account::destroy(accountactive);
6031                                         mainmenu=7;
6032                                 } else if(selected==2) {
6033                                         flash();
6034                                         mainmenu=5;
6035                                 }
6036                                 break;
6037                         case 7:
6038                                 fireSound();
6039                                 if(selected==0 && Account::getNbAccounts()<8){
6040                                         entername=1;
6041                                 } else if (selected < Account::getNbAccounts()+1) {
6042                                         flash();
6043                                         mainmenu=5;
6044                                         accountactive=Account::get(selected-1);
6045                                 } else if (selected == Account::getNbAccounts()+1) {
6046                                         flash();
6047                     if(accountactive)
6048                         mainmenu=5;
6049                     else
6050                         mainmenu=1;
6051                                         for(int j=0;j<255;j++){
6052                                                 displaytext[0][j]=0;
6053                                         }
6054                                         displaychars[0]=0;
6055                                         displayselected=0;
6056                                         entername=0;
6057                                 }
6058                                 break;
6059                         case 8:
6060                                 fireSound();
6061                                 flash();
6062                                 if(selected<=2)
6063                                         accountactive->setDifficulty(selected);
6064                                 mainmenu=5;
6065                                 break;
6066                         case 9:
6067                                 if(selected<numchallengelevels && selected<=accountactive->getProgress()){
6068                                         fireSound();
6069                                         flash();
6070
6071                                         startbonustotal=0;
6072
6073                                         loading=2;
6074                                         loadtime=0;
6075                                         targetlevel=selected;
6076                                         if(firstload)
6077                                                 TickOnceAfter();
6078                                         else
6079                                                 LoadStuff();
6080                                         Loadlevel(selected);
6081                                         campaign=0;
6082
6083                                         mainmenu=0;
6084                                         gameon=1;
6085                                         pause_sound(stream_menutheme);
6086                                 }
6087                                 if(selected==numchallengelevels){
6088                                         fireSound();
6089                                         flash();
6090                                         mainmenu=5;
6091                                 }
6092                                 break;
6093                         case 10:
6094                                 if(selected==3){
6095                                         fireSound();
6096                                         flash();
6097                                         mainmenu=5;
6098                                 }
6099                                 break;
6100                         case 18:
6101                                 if(selected==1)
6102                                         stereoseparation+=0.001;
6103                                 else {
6104                                         fireSound();
6105                                         if(selected==0){
6106                                                 newstereomode = (StereoMode)(newstereomode + 1);
6107                                                 while(!CanInitStereo(newstereomode)){
6108                                                         printf("Failed to initialize mode %s (%i)\n", StereoModeName(newstereomode), newstereomode);
6109                                                         newstereomode = (StereoMode)(newstereomode + 1);
6110                                                         if(newstereomode >= stereoCount)
6111                                                                 newstereomode = stereoNone;
6112                                                 }
6113                                         } else if(selected==2) {
6114                                                 stereoreverse = !stereoreverse;
6115                                         } else if(selected==3) {
6116                                                 flash();
6117                                                 mainmenu=3;
6118
6119                                                 stereomode = newstereomode;
6120                                                 InitStereo(stereomode);
6121                                         }
6122                                 }
6123                 updateStereoConfigMenu();
6124                                 break;
6125                 }
6126         }
6127
6128     if(Input::isKeyDown(SDLK_q) && Input::isKeyDown(SDLK_LMETA)){
6129         tryquit=1;
6130         if(mainmenu==3) {
6131             SaveSettings();
6132         }
6133     }
6134
6135     OPENAL_SetFrequency(channels[stream_menutheme], 22050);
6136
6137     if(entername){
6138         inputText(displaytext[0],&displayselected,&displaychars[0]);
6139         if(!waiting) { // the input as finished
6140             if(displaychars[0]){ // with enter
6141                 accountactive = Account::add(string(displaytext[0]));
6142
6143                 mainmenu=8;
6144
6145                 flash();
6146
6147                 fireSound(firestartsound);
6148
6149                 for(int i=0;i<255;i++){
6150                     displaytext[0][i]=0;
6151                 }
6152                 displaychars[0]=0;
6153
6154                 displayselected=0;
6155             }
6156             entername=0;
6157             LoadMenu();
6158         }
6159         
6160         displayblinkdelay-=multiplier;
6161         if(displayblinkdelay<=0){
6162             displayblinkdelay=.3;
6163             displayblink=1-displayblink;
6164         }
6165     }
6166
6167     if(entername){
6168         Menu::setText(0,displaytext[0],20,400,-1,-1);
6169         Menu::setText(-2,displayblink?"_":"",20+displayselected*10,400,-1,-1);
6170     }
6171
6172     if(oldmainmenu!=mainmenu)
6173         LoadMenu();
6174         oldmainmenu=mainmenu;
6175
6176 }
6177
6178 void Game::Tick(){
6179         static XYZ facing,flatfacing;
6180         static int target;
6181
6182         for(int i=0;i<15;i++){
6183                 displaytime[i]+=multiplier;
6184         }
6185
6186         keyboardfrozen=false;
6187     Input::Tick();
6188
6189         if(Input::isKeyPressed(SDLK_F6)){
6190                 if(Input::isKeyDown(SDLK_LSHIFT))
6191                         stereoreverse=true;
6192                 else
6193                         stereoreverse=false;
6194
6195                 if(stereoreverse)
6196                         printf("Stereo reversed\n");
6197                 else
6198                         printf("Stereo unreversed\n");
6199         }
6200
6201         if(Input::isKeyDown(SDLK_F7)){
6202                 if(Input::isKeyDown(SDLK_LSHIFT))
6203                         stereoseparation -= 0.001;
6204                 else
6205                         stereoseparation -= 0.010;
6206                 printf("Stereo decreased increased to %f\n", stereoseparation);
6207         }
6208
6209         if(Input::isKeyDown(SDLK_F8)){
6210                 if(Input::isKeyDown(SDLK_LSHIFT))
6211                         stereoseparation += 0.001;
6212                 else
6213                         stereoseparation += 0.010;
6214                 printf("Stereo separation increased to %f\n", stereoseparation);
6215         }
6216
6217
6218         if(Input::isKeyPressed(SDLK_TAB)&&tutoriallevel){
6219                 if(tutorialstage!=51)
6220                         tutorialstagetime=tutorialmaxtime;
6221                 emit_sound_np(consolefailsound, 128.);
6222         }
6223
6224     /*
6225     Values of mainmenu :
6226     1 Main menu
6227     2 Menu pause (resume/end game)
6228     3 Option menu
6229     4 Controls configuration menu
6230     5 Main game menu (choose level or challenge)
6231     6 Deleting user menu
6232     7 User managment menu (select/add)
6233     8 Choose difficulty menu
6234     9 Challenge level selection menu
6235     10 End of the campaign congratulation (is that really a menu?)
6236     11 Same that 9 ??? => unused
6237     18 stereo configuration
6238     */
6239         
6240         if(!console) {
6241         //campaign over?
6242                 if(mainmenu&&endgame==1)
6243             mainmenu=10;
6244         //go to level select after completing a campaign level
6245         if(campaign&&winfreeze&&mainmenu==0&&campaignlevels[actuallevel].choosenext==1) {
6246             mainmenu=5;
6247             gameon=0;
6248             winfreeze=0;
6249             fireSound();
6250             flash();
6251             if(musictoggle) {
6252                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6253                 emit_stream_np(stream_menutheme);
6254                 pause_sound(leveltheme);
6255             }
6256                         LoadMenu();
6257         }
6258         //escape key pressed
6259                 if(Input::isKeyPressed(SDLK_ESCAPE)&&
6260                 (gameon||mainmenu==0||(mainmenu>=3&&mainmenu!=8&&!(mainmenu==7&&entername)))) {
6261                         selected=-1;
6262             if(mainmenu==0&&!winfreeze)
6263                 mainmenu=2; //pause
6264             else if(mainmenu==1||mainmenu==2){
6265                 mainmenu=0; //unpause
6266             }
6267             //play menu theme
6268             if(musictoggle&&(mainmenu==1||mainmenu==2)){
6269                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6270                 emit_stream_np(stream_menutheme);
6271                 pause_sound(leveltheme);
6272             }
6273             //on resume, play level music
6274             if(!mainmenu){
6275                 pause_sound(stream_menutheme);
6276                 resume_stream(leveltheme);
6277             }
6278             //finished with settings menu
6279                         if(mainmenu==3){
6280                                 SaveSettings();
6281                         }
6282             //effects
6283                         if(mainmenu>=3&&mainmenu!=8){
6284                                 fireSound();
6285                                 flash();
6286                         }
6287             //go back
6288             switch(mainmenu){
6289                 case 3: case 5:
6290                     mainmenu=gameon?2:1; break;
6291                 case 4: case 18:
6292                     mainmenu=3; break;
6293                 case 6: case 7: case 9: case 10:
6294                     mainmenu=5; break;
6295             }
6296                 }
6297         }
6298
6299         if(mainmenu) {
6300         MenuTick();
6301         }
6302
6303         if(!mainmenu) {
6304                 if(hostile==1)hostiletime+=multiplier;
6305                 else hostiletime=0;
6306                 if(!winfreeze)leveltime+=multiplier;
6307
6308         //keys
6309                 if(Input::isKeyPressed(SDLK_v)&&debugmode){
6310                         freeze=1-freeze;
6311                         if(freeze){
6312                                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6313                         }
6314                 }
6315
6316                 if(Input::isKeyPressed(chatkey)&&!console&&!chatting&&debugmode)
6317                         chatting=1;
6318
6319                 if(chatting){
6320                         inputText(displaytext[0],&displayselected,&displaychars[0]);
6321                         if(!waiting) {
6322                                 if(displaychars[0]){
6323                                         for(int j=0;j<255;j++)
6324                                                 displaytext[0][j]=0;
6325                                         displaychars[0]=0;
6326                                         displayselected=0;
6327                                 }       
6328                                 chatting=0;             
6329                         }
6330
6331                         displayblinkdelay-=multiplier;
6332                         if(displayblinkdelay<=0){
6333                                 displayblinkdelay=.3;
6334                                 displayblink=1-displayblink;
6335                         }
6336                 }
6337                 if(chatting)
6338             keyboardfrozen=true;
6339
6340                 if(Input::isKeyPressed(consolekey)&&debugmode) {
6341                         console=!console;
6342                         if(console) {
6343                                 OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6344                         } else {
6345                                 freeze=0;
6346                                 waiting=false;
6347                         }
6348                 }
6349
6350                 if(console)
6351             freeze=1;
6352                 if(console&&!Input::isKeyDown(SDLK_LMETA)) {
6353                         inputText(consoletext[0],&consoleselected,&consolechars[0]);
6354                         if(!waiting) {
6355                                 if(consolechars[0]>0) {
6356                     consoletext[0][consolechars[0]]='\0';
6357                     cmd_dispatch(consoletext[0]);
6358                                         for(int k=14;k>=1;k--) {
6359                                                 for(int j=0;j<255;j++)
6360                                                         consoletext[k][j]=consoletext[k-1][j];
6361                                                 consolechars[k]=consolechars[k-1];
6362                                         }
6363                                         for(int j=0;j<255;j++)
6364                                                 consoletext[0][j]=0;
6365                                         consolechars[0]=0;
6366                                         consoleselected=0;
6367                                 }
6368                         }
6369
6370                         consoleblinkdelay-=multiplier;
6371                         if(consoleblinkdelay<=0) {
6372                                 consoleblinkdelay=.3;
6373                                 consoleblink=1-consoleblink;
6374                         }
6375                 }
6376
6377
6378
6379                 if(Input::isKeyDown(SDLK_q)&&Input::isKeyDown(SDLK_LMETA)){
6380                         tryquit=1;
6381                         if(mainmenu==3) {
6382                                 SaveSettings();
6383                         }
6384                 }
6385
6386                 static int oldwinfreeze;
6387                 if(winfreeze&&!oldwinfreeze){
6388                         OPENAL_SetFrequency(OPENAL_ALL, 0.001);
6389                         emit_sound_np(consolesuccesssound);
6390                 }
6391                 if(winfreeze==0)
6392             oldwinfreeze=winfreeze;
6393                 else
6394             oldwinfreeze++;
6395
6396                 if((Input::isKeyPressed(jumpkey)||Input::isKeyPressed(SDLK_SPACE))&&!campaign)
6397                         if(winfreeze)
6398                 winfreeze=0;
6399                 if((Input::isKeyDown(SDLK_ESCAPE))&&!campaign&&gameon){
6400             if(console){
6401                 console=false;
6402                 freeze=0;
6403             } else if(winfreeze) {
6404                                 mainmenu=9;
6405                                 gameon=0;
6406                         }
6407         }
6408
6409
6410
6411                 if(!freeze&&!winfreeze&&!(mainmenu&&gameon)&&(gameon||!gamestarted)){
6412
6413             //dialogues
6414             static float talkdelay = 0;
6415
6416                         if(indialogue!=-1)
6417                 talkdelay=1;
6418                         talkdelay-=multiplier;
6419
6420                         if(talkdelay<=0&&indialogue==-1&&animation[player[0].targetanimation].height!=highheight)
6421                 for(int i=0;i<numdialogues;i++){
6422                     int realdialoguetype;
6423                     bool special;
6424                     if(dialoguetype[i]>49){
6425                         realdialoguetype=dialoguetype[i]-50;
6426                         special=1;
6427                     }
6428                     else if(dialoguetype[i]>39){
6429                         realdialoguetype=dialoguetype[i]-40;
6430                         special=1;
6431                     }
6432                     else if(dialoguetype[i]>29){
6433                         realdialoguetype=dialoguetype[i]-30;
6434                         special=1;
6435                     }
6436                     else if(dialoguetype[i]>19){
6437                         realdialoguetype=dialoguetype[i]-20;
6438                         special=1;
6439                     }
6440                     else if(dialoguetype[i]>9){
6441                         realdialoguetype=dialoguetype[i]-10;
6442                         special=1;
6443                     }
6444                     else {
6445                         realdialoguetype=dialoguetype[i];
6446                         special=0;
6447                     }
6448                     if((!hostile||dialoguetype[i]>40&&dialoguetype[i]<50)&&
6449                             realdialoguetype<numplayers&&
6450                             realdialoguetype>0&&
6451                             (dialoguegonethrough[i]==0||!special)&&
6452                             (special||Input::isKeyPressed(attackkey))){
6453                         if(findDistancefast(&player[0].coords,&player[realdialoguetype].coords)<6||
6454                                 player[realdialoguetype].howactive>=typedead1||
6455                                 dialoguetype[i]>40&&dialoguetype[i]<50){
6456                             whichdialogue=i;
6457                             for(int j=0;j<numdialogueboxes[whichdialogue];j++){
6458                                 player[participantfocus[whichdialogue][j]].coords=participantlocation[whichdialogue][participantfocus[whichdialogue][j]];
6459                                 player[participantfocus[whichdialogue][j]].yaw=participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
6460                                 player[participantfocus[whichdialogue][j]].targetyaw=participantyaw[whichdialogue][participantfocus[whichdialogue][j]];
6461                                 player[participantfocus[whichdialogue][j]].velocity=0;
6462                                 player[participantfocus[whichdialogue][j]].targetanimation=player[participantfocus[whichdialogue][j]].getIdle();
6463                                 player[participantfocus[whichdialogue][j]].targetframe=0;
6464                             }
6465                             directing=0;
6466                             indialogue=0;
6467                             dialoguetime=0;
6468                             dialoguegonethrough[i]++;
6469                             if(dialogueboxsound[whichdialogue][indialogue]!=0){
6470                                 playdialogueboxsound();
6471                             }
6472                         }
6473                     }
6474                 }
6475
6476             windvar+=multiplier;
6477             smoketex+=multiplier;
6478             tutorialstagetime+=multiplier;
6479
6480             //hotspots
6481             static float hotspotvisual[40];
6482             if(numhotspots){
6483                 XYZ hotspotsprite;
6484                 if(editorenabled)
6485                     for(int i=0;i<numhotspots;i++)
6486                         hotspotvisual[i]-=multiplier/320;
6487
6488                 for(int i=0;i<numhotspots;i++){
6489                     //if(hotspottype[i]<=10)
6490                     while(hotspotvisual[i]<0){
6491                         hotspotsprite=0;
6492                         hotspotsprite.x=float(abs(Random()%100000))/100000*hotspotsize[i];
6493                         hotspotsprite=DoRotation(hotspotsprite,0,0,Random()%360);
6494                         hotspotsprite=DoRotation(hotspotsprite,0,Random()%360,0);
6495                         hotspotsprite+=hotspot[i];
6496                         Sprite::MakeSprite(breathsprite, hotspotsprite, hotspotsprite*0, 1,0.5,0, 7, 0.4);
6497                         hotspotvisual[i]+=0.1/hotspotsize[i]/hotspotsize[i]/hotspotsize[i];
6498                     }
6499                 }
6500
6501                 for(int i=0;i<numhotspots;i++){
6502                     if(hotspottype[i]<=10&&hotspottype[i]>0){
6503                         hotspot[i]=player[hotspottype[i]].coords;
6504                     }
6505                 }
6506             }
6507
6508             //Tutorial
6509             if(tutoriallevel){
6510                 doTutorial();
6511             }
6512
6513             //bonuses
6514             if(tutoriallevel!=1){
6515                 if(bonustime==0&&
6516                         bonus!=solidhit&&
6517                         bonus!=spinecrusher&&
6518                         bonus!=tracheotomy&&
6519                         bonus!=backstab&&
6520                         bonusvalue>10){
6521                     emit_sound_np(consolesuccesssound);
6522                 }
6523             } else if(bonustime==0){
6524                 emit_sound_np(fireendsound);
6525             }
6526             if(bonustime==0){
6527                 if(bonus!=solidhit&&
6528                         bonus!=twoxcombo&&
6529                         bonus!=threexcombo&&
6530                         bonus!=fourxcombo&&
6531                         bonus!=megacombo)
6532                     bonusnum[bonus]++;
6533                 else
6534                     bonusnum[bonus]+=0.15;
6535                 if(tutoriallevel)
6536                     bonusvalue=0;
6537                 bonusvalue/=bonusnum[bonus];
6538                 bonustotal+=bonusvalue;
6539             }
6540             bonustime+=multiplier;
6541
6542             //snow effects
6543             if(environment==snowyenvironment){
6544                 precipdelay-=multiplier;
6545                 while(precipdelay<0){
6546                     precipdelay+=.04;
6547                     if(!detail)
6548                         precipdelay+=.04;
6549                     XYZ footvel,footpoint;
6550
6551                     footvel=0;
6552                     footpoint=viewer+viewerfacing*6;
6553                     footpoint.y+=((float)abs(Random()%1200))/100-6;
6554                     footpoint.x+=((float)abs(Random()%1200))/100-6;
6555                     footpoint.z+=((float)abs(Random()%1200))/100-6;
6556                     Sprite::MakeSprite(snowsprite, footpoint,footvel, 1,1,1, .1, 1);
6557                 }
6558             }
6559
6560
6561             doAerialAcrobatics();
6562
6563
6564             static XYZ oldviewer;
6565
6566             //control keys
6567             if(indialogue==-1){
6568                 player[0].forwardkeydown=Input::isKeyDown(forwardkey);
6569                 player[0].leftkeydown=Input::isKeyDown(leftkey);
6570                 player[0].backkeydown=Input::isKeyDown(backkey);
6571                 player[0].rightkeydown=Input::isKeyDown(rightkey);
6572                 player[0].jumpkeydown=Input::isKeyDown(jumpkey);
6573                 player[0].crouchkeydown=Input::isKeyDown(crouchkey);
6574                 player[0].drawkeydown=Input::isKeyDown(drawkey);
6575                 player[0].throwkeydown=Input::isKeyDown(throwkey);
6576             }
6577             else
6578             {
6579                 player[0].forwardkeydown=0;
6580                 player[0].leftkeydown=0;
6581                 player[0].backkeydown=0;
6582                 player[0].rightkeydown=0;
6583                 player[0].jumpkeydown=0;
6584                 player[0].crouchkeydown=0;
6585                 player[0].drawkeydown=0;
6586                 player[0].throwkeydown=0;
6587             }
6588
6589             if(!player[0].jumpkeydown)
6590                 player[0].jumpclimb=0;
6591
6592
6593             if(indialogue!=-1){
6594                 cameramode=1;
6595                 if(directing){
6596                     facing=0;
6597                     facing.z=-1;
6598
6599                     facing=DoRotation(facing,-pitch,0,0);
6600                     facing=DoRotation(facing,0,0-yaw,0);
6601
6602                     flatfacing=0;
6603                     flatfacing.z=-1;
6604
6605                     flatfacing=DoRotation(flatfacing,0,-yaw,0);
6606
6607                     if(Input::isKeyDown(forwardkey))
6608                         viewer+=facing*multiplier*4;
6609                     if(Input::isKeyDown(backkey))
6610                         viewer-=facing*multiplier*4;
6611                     if(Input::isKeyDown(leftkey))
6612                         viewer+=DoRotation(flatfacing*multiplier,0,90,0)*4;
6613                     if(Input::isKeyDown(rightkey))
6614                         viewer+=DoRotation(flatfacing*multiplier,0,-90,0)*4;
6615                     if(Input::isKeyDown(jumpkey))
6616                         viewer.y+=multiplier*4;
6617                     if(Input::isKeyDown(crouchkey))
6618                         viewer.y-=multiplier*4;
6619                     if(     Input::isKeyPressed(SDLK_1)||
6620                             Input::isKeyPressed(SDLK_2)||
6621                             Input::isKeyPressed(SDLK_3)||
6622                             Input::isKeyPressed(SDLK_4)||
6623                             Input::isKeyPressed(SDLK_5)||
6624                             Input::isKeyPressed(SDLK_6)||
6625                             Input::isKeyPressed(SDLK_7)||
6626                             Input::isKeyPressed(SDLK_8)||
6627                             Input::isKeyPressed(SDLK_9)||
6628                             Input::isKeyPressed(SDLK_0)||
6629                             Input::isKeyPressed(SDLK_MINUS)){
6630                         int whichend;
6631                         if(Input::isKeyPressed(SDLK_1))whichend=1;
6632                         if(Input::isKeyPressed(SDLK_2))whichend=2;
6633                         if(Input::isKeyPressed(SDLK_3))whichend=3;
6634                         if(Input::isKeyPressed(SDLK_4))whichend=4;
6635                         if(Input::isKeyPressed(SDLK_5))whichend=5;
6636                         if(Input::isKeyPressed(SDLK_6))whichend=6;
6637                         if(Input::isKeyPressed(SDLK_7))whichend=7;
6638                         if(Input::isKeyPressed(SDLK_8))whichend=8;
6639                         if(Input::isKeyPressed(SDLK_9))whichend=9;
6640                         if(Input::isKeyPressed(SDLK_0))whichend=0;
6641                         if(Input::isKeyPressed(SDLK_MINUS))
6642                             whichend=-1;
6643                         if(whichend!=-1){
6644                             participantfocus[whichdialogue][indialogue]=whichend;
6645                             participantlocation[whichdialogue][whichend]=player[whichend].coords;
6646                             participantyaw[whichdialogue][whichend]=player[whichend].yaw;
6647                         }
6648                         if(whichend==-1){
6649                             participantfocus[whichdialogue][indialogue]=-1;
6650                         }
6651                         if(player[participantfocus[whichdialogue][indialogue]].dead){
6652                             indialogue=-1;
6653                             directing=0;
6654                             cameramode=0;
6655                         }
6656                         dialoguecamera[whichdialogue][indialogue]=viewer;
6657                         dialoguecamerayaw[whichdialogue][indialogue]=yaw;
6658                         dialoguecamerapitch[whichdialogue][indialogue]=pitch;
6659                         indialogue++;
6660                         if(indialogue<numdialogueboxes[whichdialogue]){
6661                             if(dialogueboxsound[whichdialogue][indialogue]!=0){
6662                                 playdialogueboxsound();
6663                             }
6664                         }
6665
6666                         for(int j=0;j<numplayers;j++){
6667                             participantfacing[whichdialogue][indialogue][j]=participantfacing[whichdialogue][indialogue-1][j];
6668                         }
6669                     }
6670                     //TODO: should these be KeyDown or KeyPressed?
6671                     if(     Input::isKeyDown(SDLK_KP1)||
6672                             Input::isKeyDown(SDLK_KP2)||
6673                             Input::isKeyDown(SDLK_KP3)||
6674                             Input::isKeyDown(SDLK_KP4)||
6675                             Input::isKeyDown(SDLK_KP5)||
6676                             Input::isKeyDown(SDLK_KP6)||
6677                             Input::isKeyDown(SDLK_KP7)||
6678                             Input::isKeyDown(SDLK_KP8)||
6679                             Input::isKeyDown(SDLK_KP9)||
6680                             Input::isKeyDown(SDLK_KP0)){
6681                         int whichend;
6682                         if(Input::isKeyDown(SDLK_KP1))whichend=1;
6683                         if(Input::isKeyDown(SDLK_KP2))whichend=2;
6684                         if(Input::isKeyDown(SDLK_KP3))whichend=3;
6685                         if(Input::isKeyDown(SDLK_KP4))whichend=4;
6686                         if(Input::isKeyDown(SDLK_KP5))whichend=5;
6687                         if(Input::isKeyDown(SDLK_KP6))whichend=6;
6688                         if(Input::isKeyDown(SDLK_KP7))whichend=7;
6689                         if(Input::isKeyDown(SDLK_KP8))whichend=8;
6690                         if(Input::isKeyDown(SDLK_KP9))whichend=9;
6691                         if(Input::isKeyDown(SDLK_KP0))whichend=0;
6692                         participantfacing[whichdialogue][indialogue][whichend]=facing;
6693                     }
6694                     if(indialogue>=numdialogueboxes[whichdialogue]){
6695                         indialogue=-1;
6696                         directing=0;
6697                         cameramode=0;
6698                     }
6699                 }
6700                 if(!directing){
6701                     pause_sound(whooshsound);
6702                     viewer=dialoguecamera[whichdialogue][indialogue];
6703                     viewer.y=max((double)viewer.y,terrain.getHeight(viewer.x,viewer.z)+.1);
6704                     yaw=dialoguecamerayaw[whichdialogue][indialogue];
6705                     pitch=dialoguecamerapitch[whichdialogue][indialogue];
6706                     if(dialoguetime>0.5)
6707                         if(     Input::isKeyPressed(SDLK_1)||
6708                                 Input::isKeyPressed(SDLK_2)||
6709                                 Input::isKeyPressed(SDLK_3)||
6710                                 Input::isKeyPressed(SDLK_4)||
6711                                 Input::isKeyPressed(SDLK_5)||
6712                                 Input::isKeyPressed(SDLK_6)||
6713                                 Input::isKeyPressed(SDLK_7)||
6714                                 Input::isKeyPressed(SDLK_8)||
6715                                 Input::isKeyPressed(SDLK_9)||
6716                                 Input::isKeyPressed(SDLK_0)||
6717                                 Input::isKeyPressed(SDLK_MINUS)||
6718                                 Input::isKeyPressed(attackkey)){
6719                             indialogue++;
6720                             if(indialogue<numdialogueboxes[whichdialogue]){
6721                                 if(dialogueboxsound[whichdialogue][indialogue]!=0){
6722                                     playdialogueboxsound();
6723                                     if(dialogueboxsound[whichdialogue][indialogue]==-5){
6724                                         hotspot[numhotspots]=player[0].coords;
6725                                         hotspotsize[numhotspots]=10;
6726                                         hotspottype[numhotspots]=-1;
6727
6728                                         numhotspots++;
6729                                     }
6730                                     if(dialogueboxsound[whichdialogue][indialogue]==-6){
6731                                         hostile=1;
6732                                     }
6733
6734                                     if(player[participantfocus[whichdialogue][indialogue]].dead){
6735                                         indialogue=-1;
6736                                         directing=0;
6737                                         cameramode=0;
6738                                     }
6739                                 }
6740                             }
6741                         }
6742                     if(indialogue>=numdialogueboxes[whichdialogue]){
6743                         indialogue=-1;
6744                         directing=0;
6745                         cameramode=0;
6746                         if(dialoguetype[whichdialogue]>19&&dialoguetype[whichdialogue]<30){
6747                             hostile=1;
6748                         }
6749                         if(dialoguetype[whichdialogue]>29&&dialoguetype[whichdialogue]<40){
6750                             windialogue=true;
6751                         }
6752                         if(dialoguetype[whichdialogue]>49&&dialoguetype[whichdialogue]<60){
6753                             hostile=1;
6754                             for(int i=1;i<numplayers;i++){
6755                                 player[i].aitype = attacktypecutoff;
6756                             }
6757                         }
6758                     }
6759                 }
6760             }
6761
6762             if(!player[0].jumpkeydown){
6763                 player[0].jumptogglekeydown=0;
6764             }
6765             if(player[0].jumpkeydown&&
6766                     player[0].targetanimation!=jumpupanim&&
6767                     player[0].targetanimation!=jumpdownanim&&
6768                     !player[0].isFlip())
6769                 player[0].jumptogglekeydown=1;
6770
6771
6772             dialoguetime+=multiplier;
6773             hawkyaw+=multiplier*25;
6774             realhawkcoords=0;
6775             realhawkcoords.x=25;
6776             realhawkcoords=DoRotation(realhawkcoords,0,hawkyaw,0)+hawkcoords;
6777             hawkcalldelay-=multiplier/2;
6778
6779             if(hawkcalldelay<=0){
6780                 emit_sound_at(hawksound, realhawkcoords);
6781
6782                 hawkcalldelay=16+abs(Random()%8);
6783             }
6784
6785             doDebugKeys();
6786
6787             doAttacks();
6788
6789             doPlayerCollisions();
6790
6791             doJumpReversals();
6792
6793             for(int k=0;k<numplayers;k++)
6794                 if(k!=0&&player[k].immobile)
6795                     player[k].coords=player[k].realoldcoords;
6796
6797             for(int k=0;k<numplayers;k++){
6798                 if(!isnormal(player[k].coords.x)||!isnormal(player[k].coords.y)||!isnormal(player[k].coords.z)){
6799                     if(!isnormal(player[k].coords.x)||!isnormal(player[k].coords.y)||!isnormal(player[k].coords.z)){
6800                         player[k].DoDamage(1000);
6801                     }
6802                 }
6803             }
6804
6805             //respawn
6806             static bool respawnkeydown;
6807             if(!editorenabled&&
6808                     (whichlevel!=-2&&
6809                      (Input::isKeyDown(SDLK_z)&&
6810                       Input::isKeyDown(SDLK_LMETA)&&
6811                       debugmode)||
6812                      (Input::isKeyDown(jumpkey)&&
6813                       !respawnkeydown&&
6814                       !oldattackkey&&
6815                       player[0].dead))){
6816                 targetlevel=whichlevel;
6817                 loading=1;
6818                 leveltime=5;
6819             }
6820             if(!Input::isKeyDown(jumpkey))
6821                 respawnkeydown=0;
6822             if(Input::isKeyDown(jumpkey))
6823                 respawnkeydown=1;
6824
6825
6826
6827
6828             static bool movekey;
6829
6830             //?
6831             for(int i=0;i<numplayers;i++){
6832                 static float oldtargetyaw;
6833                 if(!player[i].skeleton.free){
6834                     oldtargetyaw=player[i].targetyaw;
6835                     if(i==0&&indialogue==-1){
6836                         //TODO: refactor repetitive code
6837                         if(!animation[player[0].targetanimation].attack&&
6838                                 player[0].targetanimation!=staggerbackhighanim&&
6839                                 player[0].targetanimation!=staggerbackhardanim&&
6840                                 player[0].targetanimation!=crouchremoveknifeanim&&
6841                                 player[0].targetanimation!=removeknifeanim&&
6842                                 player[0].targetanimation!=backhandspringanim&&
6843                                 player[0].targetanimation!=dodgebackanim&&
6844                                 player[0].targetanimation!=walljumprightkickanim&&
6845                                 player[0].targetanimation!=walljumpleftkickanim){
6846                             if(cameramode)
6847                                 player[0].targetyaw=0;
6848                             else
6849                                 player[0].targetyaw=-yaw+180;
6850                         }
6851
6852                         facing=0;
6853                         facing.z=-1;
6854
6855                         flatfacing=DoRotation(facing,0,player[i].yaw+180,0);
6856                         if(cameramode){
6857                             facing=flatfacing;
6858                         }else{
6859                             facing=DoRotation(facing,-pitch,0,0);
6860                             facing=DoRotation(facing,0,0-yaw,0);
6861                         }
6862
6863                         player[0].lookyaw=-yaw;
6864
6865                         player[i].targetheadyaw=yaw;
6866                         player[i].targetheadpitch=pitch;
6867                     }
6868                     if(i!=0&&player[i].aitype==playercontrolled&&indialogue==-1){
6869                         if(!animation[player[i].targetanimation].attack&&
6870                                 player[i].targetanimation!=staggerbackhighanim&&
6871                                 player[i].targetanimation!=staggerbackhardanim&&
6872                                 player[i].targetanimation!=crouchremoveknifeanim&&
6873                                 player[i].targetanimation!=removeknifeanim&&
6874                                 player[i].targetanimation!=backhandspringanim&&
6875                                 player[i].targetanimation!=dodgebackanim&&
6876                                 player[i].targetanimation!=walljumprightkickanim&&
6877                                 player[i].targetanimation!=walljumpleftkickanim){
6878                             player[i].targetyaw=-player[i].lookyaw+180;
6879                         }
6880
6881                         facing=0;
6882                         facing.z=-1;
6883
6884                         flatfacing=DoRotation(facing,0,player[i].yaw+180,0);
6885
6886                         facing=DoRotation(facing,-player[i].lookpitch,0,0);
6887                         facing=DoRotation(facing,0,0-player[i].lookyaw,0);
6888
6889                         player[i].targetheadyaw=player[i].lookyaw;
6890                         player[i].targetheadpitch=player[i].lookpitch;
6891                     }
6892                     if(indialogue!=-1){
6893                         player[i].targetheadyaw=180-roughDirection(participantfacing[whichdialogue][indialogue][i]);
6894                         player[i].targetheadpitch=pitchOf(participantfacing[whichdialogue][indialogue][i]);
6895                     }
6896
6897                     if(leveltime<.5)
6898                         numenvsounds=0;
6899
6900                     player[i].avoidsomething=0;
6901
6902                     //avoid flaming things
6903                     for(int j=0;j<objects.numobjects;j++)
6904                         if(objects.onfire[j])
6905                             if(findDistancefast(&player[i].coords,&objects.position[j])<sq(objects.scale[j])*200)
6906                                 if(     findDistancefast(&player[i].coords,&objects.position[j])<
6907                                         findDistancefast(&player[i].coords,&player[0].coords)){
6908                                     player[i].collided=0;
6909                                     player[i].avoidcollided=1;
6910                                     if(player[i].avoidsomething==0||
6911                                             findDistancefast(&player[i].coords,&objects.position[j])<
6912                                             findDistancefast(&player[i].coords,&player[i].avoidwhere)){
6913                                         player[i].avoidwhere=objects.position[j];
6914                                         player[i].avoidsomething=1;
6915                                     }
6916                                 }
6917
6918                     //avoid flaming players
6919                     for(int j=0;j<numplayers;j++)
6920                         if(player[j].onfire)
6921                             if(findDistancefast(&player[j].coords,&player[i].coords)<sq(0.3)*200)
6922                                 if(     findDistancefast(&player[i].coords,&player[j].coords)<
6923                                         findDistancefast(&player[i].coords,&player[0].coords)){
6924                                     player[i].collided=0;
6925                                     player[i].avoidcollided=1;
6926                                     if(player[i].avoidsomething==0||
6927                                             findDistancefast(&player[i].coords,&player[j].coords)<
6928                                             findDistancefast(&player[i].coords,&player[i].avoidwhere)){
6929                                         player[i].avoidwhere=player[j].coords;
6930                                         player[i].avoidsomething=1;
6931                                     }
6932                                 }
6933
6934                     if(player[i].collided>.8)
6935                         player[i].avoidcollided=0;
6936
6937                     doAI(i);
6938
6939                     if(animation[player[i].targetanimation].attack==reversed){
6940                         //player[i].targetyaw=player[i].yaw;
6941                         player[i].forwardkeydown=0;
6942                         player[i].leftkeydown=0;
6943                         player[i].backkeydown=0;
6944                         player[i].rightkeydown=0;
6945                         player[i].jumpkeydown=0;
6946                         player[i].attackkeydown=0;
6947                         //player[i].crouchkeydown=0;
6948                         player[i].throwkeydown=0;
6949                     }
6950
6951                     if(indialogue!=-1){
6952                         player[i].forwardkeydown=0;
6953                         player[i].leftkeydown=0;
6954                         player[i].backkeydown=0;
6955                         player[i].rightkeydown=0;
6956                         player[i].jumpkeydown=0;
6957                         player[i].crouchkeydown=0;
6958                         player[i].drawkeydown=0;
6959                         player[i].throwkeydown=0;
6960                     }
6961
6962                     if(player[i].collided<-.3)
6963                         player[i].collided=-.3;
6964                     if(player[i].collided>1)
6965                         player[i].collided=1;
6966                     player[i].collided-=multiplier*4;
6967                     player[i].whichdirectiondelay-=multiplier;
6968                     if(player[i].avoidcollided<-.3||player[i].whichdirectiondelay<=0){
6969                         player[i].avoidcollided=-.3;
6970                         player[i].whichdirection=abs(Random()%2);
6971                         player[i].whichdirectiondelay=.4;
6972                     }
6973                     if(player[i].avoidcollided>1)
6974                         player[i].avoidcollided=1;
6975                     player[i].avoidcollided-=multiplier/4;
6976                     if(!player[i].skeleton.free){
6977                         player[i].stunned-=multiplier;
6978                         player[i].surprised-=multiplier;
6979                     }
6980                     if(i!=0&&player[i].surprised<=0&&
6981                             player[i].aitype==attacktypecutoff&&
6982                             !player[i].dead&&
6983                             !player[i].skeleton.free&&
6984                             animation[player[i].targetanimation].attack==neutral)
6985                         numresponded=1;
6986
6987                     if(!player[i].throwkeydown)
6988                         player[i].throwtogglekeydown=0;
6989
6990                     //pick up weapon
6991                     if(player[i].throwkeydown&&!player[i].throwtogglekeydown){
6992                         if(player[i].weaponactive==-1&&
6993                                 player[i].num_weapons<2&&
6994                                 (player[i].isIdle()||
6995                                  player[i].isCrouch()||
6996                                  player[i].targetanimation==sneakanim||
6997                                  player[i].targetanimation==rollanim||
6998                                  player[i].targetanimation==backhandspringanim||
6999                                  player[i].isFlip()||
7000                                  player[i].isFlip()||
7001                                  player[i].aitype!=playercontrolled)){
7002                             for(int j=0;j<weapons.size();j++){
7003                                 if((weapons[j].velocity.x==0&&weapons[j].velocity.y==0&&weapons[j].velocity.z==0||
7004                                             player[i].aitype==playercontrolled)&&
7005                                         weapons[j].owner==-1&&
7006                                         player[i].weaponactive==-1)
7007                                     if(findDistancefastflat(&player[i].coords,&weapons[j].position)<2){
7008                                         if(findDistancefast(&player[i].coords,&weapons[j].position)<2){
7009                                             if(player[i].isCrouch()||
7010                                                     player[i].targetanimation==sneakanim||
7011                                                     player[i].isRun()||
7012                                                     player[i].isIdle()||
7013                                                     player[i].aitype!=playercontrolled){
7014                                                 player[i].throwtogglekeydown=1;
7015                                                 player[i].setAnimation(crouchremoveknifeanim);
7016                                                 player[i].targetyaw=roughDirectionTo(player[i].coords,weapons[j].position);
7017                                                 player[i].hasvictim=0;
7018                                             }
7019                                             if(player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim){
7020                                                 player[i].throwtogglekeydown=1;
7021                                                 player[i].hasvictim=0;
7022
7023                                                 if((weapons[j].velocity.x==0&&weapons[j].velocity.y==0&&weapons[j].velocity.z==0||
7024                                                                 player[i].aitype==playercontrolled)&&
7025                                                             weapons[j].owner==-1||
7026                                                         player[i].victim&&
7027                                                         weapons[j].owner==player[i].victim->id)
7028                                                     if(findDistancefastflat(&player[i].coords,&weapons[j].position)<2&&player[i].weaponactive==-1)
7029                                                         if(findDistancefast(&player[i].coords,&weapons[j].position)<1||player[i].victim){
7030                                                             if(weapons[j].getType()!=staff)
7031                                                                 emit_sound_at(knifedrawsound, player[i].coords, 128.);
7032
7033                                                             player[i].weaponactive=0;
7034                                                             weapons[j].owner=player[i].id;
7035                                                             if(player[i].num_weapons>0)
7036                                                                 player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
7037                                                             player[i].num_weapons++;
7038                                                             player[i].weaponids[0]=j;
7039                                                         }
7040                                             }
7041                                         }else if((player[i].isIdle()||
7042                                                     player[i].isFlip()||
7043                                                     player[i].aitype!=playercontrolled)&&
7044                                                 findDistancefast(&player[i].coords,&weapons[j].position)<5&&
7045                                                 player[i].coords.y<weapons[j].position.y){
7046                                             if(!player[i].isFlip()){
7047                                                 player[i].throwtogglekeydown=1;
7048                                                 player[i].setAnimation(removeknifeanim);
7049                                                 player[i].targetyaw=roughDirectionTo(player[i].coords,weapons[j].position);
7050                                             }
7051                                             if(player[i].isFlip()){
7052                                                 player[i].throwtogglekeydown=1;
7053                                                 player[i].hasvictim=0;
7054
7055                                                 for(int k=0;k<weapons.size();k++){
7056                                                     if(player[i].weaponactive==-1)
7057                                                         if((weapons[k].velocity.x==0&&weapons[k].velocity.y==0&&weapons[k].velocity.z==0||
7058                                                                         player[i].aitype==playercontrolled)&&
7059                                                                     weapons[k].owner==-1||
7060                                                                 player[i].victim&&
7061                                                                  weapons[k].owner==player[i].victim->id)
7062                                                             if(findDistancefastflat(&player[i].coords,&weapons[k].position)<3&&
7063                                                                     player[i].weaponactive==-1){
7064                                                                 if(weapons[k].getType()!=staff)
7065                                                                     emit_sound_at(knifedrawsound, player[i].coords, 128.);
7066
7067                                                                 player[i].weaponactive=0;
7068                                                                 weapons[k].owner=player[i].id;
7069                                                                 if(player[i].num_weapons>0)
7070                                                                     player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
7071                                                                 player[i].num_weapons++;
7072                                                                 player[i].weaponids[0]=k;
7073                                                             }
7074                                                 }
7075                                             }
7076                                         }
7077                                     }
7078                             }
7079                             if(player[i].isCrouch()||
7080                                     player[i].targetanimation==sneakanim||
7081                                     player[i].isRun()||
7082                                     player[i].isIdle()||player[i].targetanimation==rollanim||
7083                                     player[i].targetanimation==backhandspringanim){
7084                                 if(numplayers>1)
7085                                     for(int j=0;j<numplayers;j++){
7086                                         if(player[i].weaponactive==-1)
7087                                             if(j!=i)
7088                                                 if(player[j].num_weapons&&
7089                                                         player[j].skeleton.free&&
7090                                                         findDistancefast(&player[i].coords,&player[j].coords)<2/*&&player[j].dead*/&&
7091                                                         (((player[j].skeleton.forward.y<0&&
7092                                                            player[j].weaponstuckwhere==0)||
7093                                                           (player[j].skeleton.forward.y>0&&
7094                                                            player[j].weaponstuckwhere==1))||
7095                                                          player[j].weaponstuck==-1||
7096                                                          player[j].num_weapons>1)){
7097                                                     if(player[i].targetanimation!=rollanim&&player[i].targetanimation!=backhandspringanim){
7098                                                         player[i].throwtogglekeydown=1;
7099                                                         player[i].victim=&player[j];
7100                                                         player[i].hasvictim=1;
7101                                                         player[i].setAnimation(crouchremoveknifeanim);
7102                                                         player[i].targetyaw=roughDirectionTo(player[i].coords,player[j].coords);
7103                                                     }
7104                                                     if(player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim){
7105                                                         player[i].throwtogglekeydown=1;
7106                                                         player[i].victim=&player[j];
7107                                                         player[i].hasvictim=1;
7108                                                         int k = player[j].weaponids[0];
7109                                                         if(player[i].hasvictim){
7110                                                             bool fleshstuck;
7111                                                             fleshstuck=0;
7112                                                             if(player[i].victim->weaponstuck!=-1){
7113                                                                 if(player[i].victim->weaponids[player[i].victim->weaponstuck]==k){
7114                                                                     fleshstuck=1;
7115                                                                 }
7116                                                             }
7117                                                             if(!fleshstuck){
7118                                                                 if(weapons[k].getType()!=staff)
7119                                                                   emit_sound_at(knifedrawsound, player[i].coords, 128.);
7120                                                             }
7121                                                             if(fleshstuck)
7122                                                               emit_sound_at(fleshstabremovesound, player[i].coords, 128.);
7123
7124                                                             player[i].weaponactive=0;
7125                                                             if(weapons[k].owner!=-1){
7126                                                                 if(player[i].victim->num_weapons==1)player[i].victim->num_weapons=0;
7127                                                                 else player[i].victim->num_weapons=1;
7128
7129                                                                 player[i].victim->skeleton.longdead=0;
7130                                                                 player[i].victim->skeleton.free=1;
7131                                                                 player[i].victim->skeleton.broken=0;
7132
7133                                                                 for(int l=0;l<player[i].victim->skeleton.num_joints;l++){
7134                                                                     player[i].victim->skeleton.joints[l].velchange=0;
7135                                                                     player[i].victim->skeleton.joints[l].locked=0;
7136                                                                 }
7137
7138                                                                 XYZ relative;
7139                                                                 relative=0;
7140                                                                 relative.y=10;
7141                                                                 Normalise(&relative);
7142                                                                 XYZ footvel,footpoint;
7143                                                                 footvel=0;
7144                                                                 footpoint=weapons[k].position;
7145                                                                 if(player[i].victim->weaponstuck!=-1){
7146                                                                     if(player[i].victim->weaponids[player[i].victim->weaponstuck]==k){
7147                                                                         if(bloodtoggle)Sprite::MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .8, .3);
7148                                                                         weapons[k].bloody=2;
7149                                                                         weapons[k].blooddrip=5;
7150                                                                         player[i].victim->weaponstuck=-1;
7151                                                                         player[i].victim->bloodloss+=2000;
7152                                                                         player[i].victim->DoDamage(2000);
7153                                                                     }
7154                                                                 }
7155                                                                 if(player[i].victim->num_weapons>0){
7156                                                                     if(player[i].victim->weaponstuck!=0&&player[i].victim->weaponstuck!=-1)player[i].victim->weaponstuck=0;
7157                                                                     if(player[i].victim->weaponids[0]==k)
7158                                                                         player[i].victim->weaponids[0]=player[i].victim->weaponids[player[i].victim->num_weapons];
7159                                                                 }
7160
7161                                                                 player[i].victim->weaponactive=-1;
7162
7163                                                                 player[i].victim->getJointFor(abdomen).velocity+=relative*6;
7164                                                                 player[i].victim->getJointFor(neck).velocity+=relative*6;
7165                                                                 player[i].victim->getJointFor(rightshoulder).velocity+=relative*6;
7166                                                                 player[i].victim->getJointFor(leftshoulder).velocity+=relative*6;
7167                                                             }
7168                                                             weapons[k].owner=i;
7169                                                             if(player[i].num_weapons>0){
7170                                                                 player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
7171                                                             }
7172                                                             player[i].num_weapons++;
7173                                                             player[i].weaponids[0]=k;
7174                                                         }
7175                                                     }
7176                                                 }
7177                                     }
7178                             }
7179                         }
7180                         if(player[i].weaponactive!=-1&&player[i].aitype==playercontrolled){
7181                             if(weapons[player[i].weaponids[0]].getType()==knife){
7182                                 if(player[i].isIdle()||
7183                                         player[i].isRun()||
7184                                         player[i].isCrouch()||
7185                                         player[i].targetanimation==sneakanim||
7186                                         player[i].isFlip())
7187                                     if(numplayers>1)
7188                                         for(int j=0;j<numplayers;j++){
7189                                             if(i!=j)
7190                                                 if(tutoriallevel!=1||tutorialstage==49)
7191                                                     if(hostile)
7192                                                         if(normaldotproduct(player[i].facing,player[i].coords-player[j].coords)<0&&
7193                                                                 findDistancefast(&player[i].coords,&player[j].coords)<100&&
7194                                                                 findDistancefast(&player[i].coords,&player[j].coords)>1.5&&
7195                                                                 !player[j].skeleton.free&&
7196                                                                 -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)){
7197                                                             if(!player[i].isFlip()){
7198                                                                 player[i].throwtogglekeydown=1;
7199                                                                 player[i].victim=&player[j];
7200                                                                 player[i].setAnimation(knifethrowanim);
7201                                                                 player[i].targetyaw=roughDirectionTo(player[i].coords,player[j].coords);
7202                                                                 player[i].targettilt2=pitchTo(player[i].coords,player[j].coords);
7203                                                             }
7204                                                             if(player[i].isFlip()){
7205                                                                 if(player[i].weaponactive!=-1){
7206                                                                     player[i].throwtogglekeydown=1;
7207                                                                     player[i].victim=&player[j];
7208                                                                     XYZ aim;
7209                                                                     weapons[player[i].weaponids[0]].owner=-1;
7210                                                                     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);
7211                                                                     Normalise(&aim);
7212
7213                                                                     aim=DoRotation(aim,(float)abs(Random()%30)-15,(float)abs(Random()%30)-15,0);
7214
7215                                                                     weapons[player[i].weaponids[0]].velocity=aim*50;
7216                                                                     weapons[player[i].weaponids[0]].tipvelocity=aim*50;
7217                                                                     weapons[player[i].weaponids[0]].missed=0;
7218                                                                     weapons[player[i].weaponids[0]].freetime=0;
7219                                                                     weapons[player[i].weaponids[0]].firstfree=1;
7220                                                                     weapons[player[i].weaponids[0]].physics=0;
7221                                                                     player[i].num_weapons--;
7222                                                                     if(player[i].num_weapons){
7223                                                                         player[i].weaponids[0]=player[i].weaponids[player[i].num_weapons];
7224                                                                     }
7225                                                                     player[i].weaponactive=-1;
7226                                                                 }
7227                                                             }
7228                                                         }
7229                                         }
7230                             }
7231                         }
7232                         if(player[i].weaponactive!=-1&&player[i].aitype==playercontrolled){
7233                             if(player[i].isCrouch()||player[i].targetanimation==sneakanim){
7234                                 player[i].throwtogglekeydown=1;
7235                                 weapons[player[i].weaponids[0]].owner=-1;
7236                                 weapons[player[i].weaponids[0]].velocity=player[i].velocity*.2;
7237                                 if(weapons[player[i].weaponids[0]].velocity.x==0)weapons[player[i].weaponids[0]].velocity.x=.1;
7238                                 weapons[player[i].weaponids[0]].tipvelocity=weapons[player[i].weaponids[0]].velocity;
7239                                 weapons[player[i].weaponids[0]].missed=1;
7240                                 weapons[player[i].weaponids[0]].freetime=0;
7241                                 weapons[player[i].weaponids[0]].firstfree=1;
7242                                 weapons[player[i].weaponids[0]].physics=1;
7243                                 player[i].num_weapons--;
7244                                 if(player[i].num_weapons){
7245                                     player[i].weaponids[0]=player[i].weaponids[player[i].num_weapons];
7246                                     if(player[i].weaponstuck==player[i].num_weapons)player[i].weaponstuck=0;
7247                                 }
7248
7249                                 player[i].weaponactive=-1;
7250                                 for(int j=0;j<numplayers;j++){
7251                                     player[j].wentforweapon=0;
7252                                 }
7253                             }
7254                         }
7255
7256                     }
7257
7258                     //draw weapon
7259                     if(i==0||!player[0].dead||player[i].weaponactive!=-1) {
7260                         if(player[i].drawkeydown&&!player[i].drawtogglekeydown||
7261                                 player[i].num_weapons==2&&
7262                                 player[i].weaponactive==-1&&
7263                                 player[i].isIdle()||
7264                                 player[0].dead&&
7265                                 player[i].weaponactive!=-1&&
7266                                 i!=0) {
7267                             bool isgood=true;
7268                             if(player[i].weaponactive!=-1)
7269                                 if(weapons[player[i].weaponids[player[i].weaponactive]].getType()==staff)
7270                                     isgood=false;
7271                             if(isgood&&player[i].creature!=wolftype){
7272                                 if(player[i].isIdle()&&player[i].num_weapons&&weapons[player[i].weaponids[0]].getType()==knife){
7273                                     player[i].setAnimation(drawrightanim);
7274                                     player[i].drawtogglekeydown=1;
7275                                 }
7276                                 if((player[i].isIdle()||
7277                                             (player[i].aitype!=playercontrolled&&
7278                                              player[0].weaponactive!=-1&&
7279                                              player[i].isRun()))&&
7280                                         player[i].num_weapons&&
7281                                         weapons[player[i].weaponids[0]].getType()==sword){
7282                                     player[i].setAnimation(drawleftanim);
7283                                     player[i].drawtogglekeydown=1;
7284                                 }
7285                                 if(player[i].isCrouch()&&player[i].num_weapons&&weapons[player[i].weaponids[0]].getType()==knife){
7286                                     player[i].setAnimation(crouchdrawrightanim);
7287                                     player[i].drawtogglekeydown=1;
7288                                 }
7289                             }
7290                         }
7291                     }
7292                     
7293                     //clean weapon
7294                     if(player[i].weaponactive!=-1) {
7295                                                 if (player[i].isCrouch()&&
7296                                                         weapons[player[i].weaponids[player[i].weaponactive]].bloody&&
7297                                                         bloodtoggle&&
7298                                                         player[i].onterrain&&
7299                                                         player[i].num_weapons&&
7300                                                         player[i].attackkeydown&&
7301                                                         musictype!=stream_fighttheme) {
7302                                                                 if(weapons[player[i].weaponids[player[i].weaponactive]].getType()==knife)
7303                                                                         player[i].setAnimation(crouchstabanim);
7304                                                                 if(weapons[player[i].weaponids[player[i].weaponactive]].getType()==sword)
7305                                                                         player[i].setAnimation(swordgroundstabanim);
7306                                                                 player[i].hasvictim=0;
7307                                                 }
7308                                         }
7309
7310                     if(!player[i].drawkeydown)
7311                         player[i].drawtogglekeydown=0;
7312
7313                     XYZ absflatfacing;
7314                     if(i==0) {
7315                         absflatfacing=0;
7316                         absflatfacing.z=-1;
7317
7318                         absflatfacing=DoRotation(absflatfacing,0,-yaw,0);
7319                     } else
7320                                                 absflatfacing=flatfacing;
7321
7322                     if(indialogue!=-1){
7323                         player[i].forwardkeydown=0;
7324                         player[i].leftkeydown=0;
7325                         player[i].backkeydown=0;
7326                         player[i].rightkeydown=0;
7327                         player[i].jumpkeydown=0;
7328                         player[i].crouchkeydown=0;
7329                         player[i].drawkeydown=0;
7330                         player[i].throwkeydown=0;
7331                     }
7332                     movekey=0;
7333                     //Do controls
7334                     if(!animation[player[i].targetanimation].attack&&
7335                             player[i].targetanimation!=staggerbackhighanim&&
7336                             player[i].targetanimation!=staggerbackhardanim&&
7337                             player[i].targetanimation!=backhandspringanim&&
7338                             player[i].targetanimation!=dodgebackanim){
7339                         if(!player[i].forwardkeydown)
7340                             player[i].forwardstogglekeydown=0;
7341                         if(player[i].crouchkeydown){
7342                             //Crouch
7343                             target=-2;
7344                             if(i==0){
7345                                 player[i].superruntoggle=1;
7346                                 if(numplayers>1)
7347                                     for(int j=0;j<numplayers;j++)
7348                                         if(j!=i&&!player[j].skeleton.free&&player[j].aitype==passivetype)
7349                                             if(findDistancefast(&player[j].coords,&player[i].coords)<16)
7350                                                 player[i].superruntoggle=0;
7351                             }
7352
7353                             if(numplayers>1)
7354                                 for(int j=0;j<numplayers;j++){
7355                                     if(j!=i&&!player[j].skeleton.free&&player[j].victim&&player[i].lowreversaldelay<=0){
7356                                         if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&
7357                                                 player[j].victim==&player[i]&&
7358                                                 (player[j].targetanimation==sweepanim||
7359                                                  player[j].targetanimation==upunchanim||
7360                                                  player[j].targetanimation==wolfslapanim||
7361                                                  ((player[j].targetanimation==swordslashanim||
7362                                                    player[j].targetanimation==knifeslashstartanim||
7363                                                    player[j].targetanimation==staffhitanim||
7364                                                    player[j].targetanimation==staffspinhitanim)&&
7365                                                   findDistancefast(&player[j].coords,&player[i].coords)<2))){
7366                                             if(target>=0)
7367                                                 target=-1;
7368                                             else
7369                                                 target=j;
7370                                         }
7371                                     }
7372                                 }
7373                             if(target>=0)
7374                                 player[target].Reverse();
7375                             player[i].lowreversaldelay=.5;
7376
7377                             if(player[i].isIdle()){
7378                                 player[i].setAnimation(player[i].getCrouch());
7379                                 player[i].transspeed=10;
7380                             }
7381                             if(player[i].isRun()||
7382                                     (player[i].isStop()&&
7383                                      (player[i].leftkeydown||
7384                                       player[i].rightkeydown||
7385                                       player[i].forwardkeydown||
7386                                       player[i].backkeydown))){
7387                                 player[i].setAnimation(rollanim);
7388                                 player[i].transspeed=20;
7389                             }
7390                         }
7391                         if(!player[i].crouchkeydown){
7392                             //Uncrouch
7393                             if(!player[i].isRun()&&player[i].targetanimation!=sneakanim&&i==0)player[i].superruntoggle=0;
7394                             target=-2;
7395                             if(player[i].isCrouch()){
7396                                 if(numplayers>1)
7397                                     for(int j=0;j<numplayers;j++){
7398                                         if(j!=i&&
7399                                                 !player[j].skeleton.free&&
7400                                                 player[j].victim&&
7401                                                 player[i].highreversaldelay<=0){
7402                                             if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&
7403                                                     player[j].victim==&player[i]&&
7404                                                     (player[j].targetanimation==spinkickanim)&&
7405                                                     player[i].isCrouch()){
7406                                                 if(target>=0)
7407                                                     target=-1;
7408                                                 else
7409                                                     target=j;
7410                                             }
7411                                         }
7412                                     }
7413                                 if(target>=0)
7414                                     player[target].Reverse();
7415                                 player[i].highreversaldelay=.5;
7416
7417                                 if(player[i].isCrouch()){
7418                                     if(!player[i].wasCrouch()){
7419                                         player[i].currentanimation=player[i].getCrouch();
7420                                         player[i].currentframe=0;
7421                                     }
7422                                     player[i].setAnimation(player[i].getIdle());
7423                                     player[i].transspeed=10;
7424                                 }
7425                             }
7426                             if(player[i].targetanimation==sneakanim){
7427                                 player[i].setAnimation(player[i].getIdle());
7428                                 player[i].transspeed=10;
7429                             }
7430                         }
7431                         if(player[i].forwardkeydown){
7432                             if(player[i].isIdle()||
7433                                     (player[i].isStop()&&
7434                                      player[i].targetyaw==player[i].yaw)||
7435                                     (player[i].isLanding()&&
7436                                      player[i].targetframe>0&&
7437                                      !player[i].jumpkeydown)||
7438                                     (player[i].isLandhard()&&
7439                                      player[i].targetframe>0&&
7440                                      !player[i].jumpkeydown&&
7441                                      player[i].crouchkeydown)){
7442                                 if(player[i].aitype==passivetype)
7443                                     player[i].setAnimation(walkanim);
7444                                 else
7445                                     player[i].setAnimation(player[i].getRun());
7446                             }
7447                             if(player[i].isCrouch()){
7448                                 player[i].targetanimation=sneakanim;
7449                                 if(player[i].wasCrouch())
7450                                     player[i].target=0;
7451                                 player[i].targetframe=0;
7452                             }
7453                             if(player[i].targetanimation==hanganim/*&&(!player[i].forwardstogglekeydown||player[i].aitype!=playercontrolled)*/){
7454                                 player[i].setAnimation(climbanim);
7455                                 player[i].targetframe=1;
7456                                 player[i].jumpclimb=1;
7457                             }
7458                             if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
7459                                 player[i].velocity+=absflatfacing*5*multiplier;
7460                             }
7461                             player[i].forwardstogglekeydown=1;
7462                             movekey=1;
7463                         }
7464                         if (player[i].rightkeydown){
7465                             if(player[i].isIdle()||
7466                                     (player[i].isStop()&&
7467                                      player[i].targetyaw==player[i].yaw)||
7468                                     (player[i].isLanding()&&
7469                                      player[i].targetframe>0&&
7470                                      !player[i].jumpkeydown)||
7471                                     (player[i].isLandhard()&&
7472                                      player[i].targetframe>0&&
7473                                      !player[i].jumpkeydown&&
7474                                      player[i].crouchkeydown)){
7475                                 player[i].setAnimation(player[i].getRun());
7476                             }
7477                             if(player[i].isCrouch()){
7478                                 player[i].targetanimation=sneakanim;
7479                                 if(player[i].wasCrouch())
7480                                     player[i].target=0;
7481                                 player[i].targetframe=0;
7482                             }
7483                             if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
7484                                 player[i].velocity+=DoRotation(absflatfacing*5*multiplier,0,-90,0);
7485                             }
7486                             player[i].targetyaw-=90;
7487                             if(player[i].forwardkeydown)player[i].targetyaw+=45;
7488                             if(player[i].backkeydown)player[i].targetyaw-=45;
7489                             movekey=1;
7490                         }
7491                         if ( player[i].leftkeydown){
7492                             if(player[i].isIdle()||
7493                                     (player[i].isStop()&&
7494                                      player[i].targetyaw==player[i].yaw)||
7495                                     (player[i].isLanding()&&
7496                                      player[i].targetframe>0&&
7497                                      !player[i].jumpkeydown)||
7498                                     (player[i].isLandhard()&&
7499                                      player[i].targetframe>0&&
7500                                      !player[i].jumpkeydown&&
7501                                      player[i].crouchkeydown)){
7502                                 player[i].setAnimation(player[i].getRun());
7503                             }
7504                             if(player[i].isCrouch()){
7505                                 player[i].targetanimation=sneakanim;
7506                                 if(player[i].wasCrouch())
7507                                     player[i].target=0;
7508                                 player[i].targetframe=0;
7509                             }
7510                             if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
7511                                 player[i].velocity-=DoRotation(absflatfacing*5*multiplier,0,-90,0);
7512                             }
7513                             player[i].targetyaw+=90;
7514                             if(player[i].forwardkeydown)player[i].targetyaw-=45;
7515                             if(player[i].backkeydown)player[i].targetyaw+=45;
7516                             movekey=1;
7517                         }
7518                         if(player[i].backkeydown){
7519                             if(player[i].isIdle()||
7520                                     (player[i].isStop()&&
7521                                      player[i].targetyaw==player[i].yaw)||
7522                                     (player[i].isLanding()&&
7523                                      player[i].targetframe>0&&
7524                                      !player[i].jumpkeydown)||
7525                                     (player[i].isLandhard()&&
7526                                      player[i].targetframe>0&&
7527                                      !player[i].jumpkeydown&&
7528                                      player[i].crouchkeydown)){
7529                                 player[i].setAnimation(player[i].getRun());
7530                             }
7531                             if(player[i].isCrouch()){
7532                                 player[i].targetanimation=sneakanim;
7533                                 if(player[i].wasCrouch())
7534                                     player[i].target=0;
7535                                 player[i].targetframe=0;
7536                             }
7537                             if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
7538                                 player[i].velocity-=absflatfacing*5*multiplier;
7539                             }
7540                             if(player[i].targetanimation==hanganim){
7541                                 player[i].currentanimation=jumpdownanim;
7542                                 player[i].targetanimation=jumpdownanim;
7543                                 player[i].target=0;
7544                                 player[i].currentframe=0;
7545                                 player[i].targetframe=1;
7546                                 player[i].velocity=0;
7547                                 player[i].velocity.y+=gravity;
7548                                 player[i].coords.y-=1.4;
7549                                 player[i].grabdelay=1;
7550                             }
7551                             if ( !player[i].leftkeydown&&!player[i].rightkeydown)
7552                                 player[i].targetyaw+=180;
7553                             movekey=1;
7554                         }
7555                         if((player[i].jumpkeydown&&!player[i].jumpclimb)||player[i].jumpstart){
7556                             if((((player[i].isLanding()&&player[i].targetframe>=3)||
7557                                             player[i].isRun()||
7558                                             player[i].targetanimation==walkanim||
7559                                             player[i].isCrouch()||
7560                                             player[i].targetanimation==sneakanim)&&
7561                                         player[i].jumppower>1)&&
7562                                     ((player[i].targetanimation!=rabbitrunninganim&&
7563                                       player[i].targetanimation!=wolfrunninganim)||i!=0)){
7564                                 player[i].jumpstart=0;
7565                                 player[i].setAnimation(jumpupanim);
7566                                 player[i].yaw=player[i].targetyaw;
7567                                 player[i].transspeed=20;
7568                                 player[i].FootLand(0,1);
7569                                 player[i].FootLand(1,1);
7570
7571                                 facing=0;
7572                                 facing.z=-1;
7573                                 flatfacing=DoRotation(facing,0,player[i].targetyaw+180,0);
7574
7575                                 if(movekey)player[i].velocity=flatfacing*player[i].speed*45*player[i].scale;
7576                                 if(!movekey)player[i].velocity=0;
7577
7578                                 //Dodge sweep?
7579                                 target=-2;
7580                                 if(numplayers>1)
7581                                     for(int j=0;j<numplayers;j++){
7582                                         if(j!=i&&!player[j].skeleton.free&&player[j].victim){
7583                                             if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&
7584                                                     player[j].victim==&player[i]&&
7585                                                     (player[j].targetanimation==sweepanim)){
7586                                                 if(target>=0)target=-1;
7587                                                 else target=j;
7588                                             }
7589                                         }
7590                                     }
7591                                     if(target>=0)player[i].velocity.y=1;
7592                                     else if(player[i].crouchkeydown||player[i].aitype!=playercontrolled){
7593                                         player[i].velocity.y=7;
7594                                         player[i].crouchtogglekeydown=1;
7595                                     }
7596                                     else player[i].velocity.y=5;
7597
7598                                     if(mousejump&&i==0&&debugmode){
7599                                         if(!player[i].isLanding())player[i].tempdeltav=deltav;
7600                                         if(player[i].tempdeltav<0)player[i].velocity.y-=(float)(player[i].tempdeltav)/multiplier/1000;
7601                                     }
7602
7603                                     player[i].coords.y+=.2;
7604                                     player[i].jumppower-=1;
7605
7606                                     if (!i)
7607                                       emit_sound_at(whooshsound, player[i].coords, 128.);
7608
7609                                     emit_sound_at(jumpsound, player[i].coords, 128.);
7610                             }
7611                             if((player[i].isIdle())&&player[i].jumppower>1){
7612                                 player[i].setAnimation(player[i].getLanding());
7613                                 player[i].targetframe=2;
7614                                 player[i].landhard=0;
7615                                 player[i].jumpstart=1;
7616                                 player[i].tempdeltav=deltav;
7617                             }
7618                             if(player[i].targetanimation==jumpupanim&&
7619                                     (((!floatjump&&
7620                                        !editorenabled)||
7621                                       !debugmode)||
7622                                      player[i].aitype!=playercontrolled)){
7623                                 if(player[i].jumppower>multiplier*6){
7624                                     player[i].velocity.y+=multiplier*6;
7625                                     player[i].jumppower-=multiplier*6;
7626                                 }
7627                                 if(player[i].jumppower<=multiplier*6){
7628                                     player[i].velocity.y+=player[i].jumppower;
7629                                     player[i].jumppower=0;
7630                                 }
7631                             }
7632                             if(((floatjump||editorenabled)&&debugmode)&&i==0)player[i].velocity.y+=multiplier*30;
7633                         }
7634
7635                         if(!movekey){
7636                             if(player[i].isRun()||player[i].targetanimation==walkanim)
7637                                 player[i].setAnimation(player[i].getStop());
7638                             if(player[i].targetanimation==sneakanim){
7639                                 player[i].targetanimation=player[i].getCrouch();
7640                                 if(player[i].currentanimation==sneakanim)
7641                                     player[i].target=0;
7642                                 player[i].targetframe=0;
7643                             }
7644                         }
7645                         if(player[i].targetanimation==walkanim&&
7646                                 (player[i].aitype==attacktypecutoff||
7647                                  player[i].aitype==searchtype||
7648                                  (player[i].aitype==passivetype&&
7649                                   player[i].numwaypoints<=1)))
7650                             player[i].setAnimation(player[i].getStop());
7651                         if(player[i].isRun()&&(player[i].aitype==passivetype))
7652                             player[i].setAnimation(player[i].getStop());
7653                     }
7654                 }
7655                 if(player[i].targetanimation==rollanim)
7656                     player[i].targetyaw=oldtargetyaw;
7657             }
7658
7659             //Rotation
7660             for(int k=0;k<numplayers;k++){
7661                 if(fabs(player[k].yaw-player[k].targetyaw)>180){
7662                     if(player[k].yaw>player[k].targetyaw)
7663                         player[k].yaw-=360;
7664                     else
7665                         player[k].yaw+=360;
7666                 }
7667
7668                 //stop to turn in right direction
7669                 if(fabs(player[k].yaw-player[k].targetyaw)>90&&(player[k].isRun()||player[k].targetanimation==walkanim))
7670                     player[k].setAnimation(player[k].getStop());
7671
7672                 if(player[k].targetanimation==backhandspringanim||player[k].targetanimation==dodgebackanim)
7673                     player[k].targettilt=0;
7674
7675                 if(player[k].targetanimation!=jumpupanim&&
7676                         player[k].targetanimation!=backhandspringanim&&
7677                         player[k].targetanimation!=jumpdownanim&&
7678                         !player[k].isFlip()){
7679                     player[k].targettilt=0;
7680                     if(player[k].jumppower<0&&!player[k].jumpkeydown)
7681                         player[k].jumppower=0;
7682                     player[k].jumppower+=multiplier*7;
7683                     if(player[k].isCrouch())
7684                         player[k].jumppower+=multiplier*7;
7685                     if(player[k].jumppower>5)
7686                         player[k].jumppower=5;
7687                 }
7688
7689                 if(player[k].isRun())
7690                     player[k].targettilt=(player[k].yaw-player[k].targetyaw)/4;
7691
7692                 player[k].tilt=stepTowardf(player[k].tilt,player[k].targettilt,multiplier*150);
7693                 player[k].grabdelay-=multiplier;
7694             }
7695
7696             //do animations
7697             for(int k=0;k<numplayers;k++){
7698                 player[k].DoAnimations();
7699                 player[k].whichpatchx=player[k].coords.x/(terrain.size/subdivision*terrain.scale);
7700                 player[k].whichpatchz=player[k].coords.z/(terrain.size/subdivision*terrain.scale);
7701             }
7702
7703             //do stuff
7704             objects.DoStuff();
7705             
7706             for(int j=numenvsounds-1;j>=0;j--){
7707                 envsoundlife[j]-=multiplier;
7708                 if(envsoundlife[j]<0){
7709                     numenvsounds--;
7710                     envsoundlife[j]=envsoundlife[numenvsounds];
7711                     envsound[j]=envsound[numenvsounds];
7712                 }
7713             }
7714             if(slomo)
7715                 OPENAL_SetFrequency(OPENAL_ALL, slomofreq);
7716             else
7717                 OPENAL_SetFrequency(OPENAL_ALL, 22050);
7718
7719             if(tutoriallevel==1){
7720                 XYZ temp;
7721                 XYZ temp2;
7722                 XYZ temp3;
7723                 XYZ oldtemp;
7724                 XYZ oldtemp2;
7725                 temp.x=1011;
7726                 temp.y=84;
7727                 temp.z=491;
7728                 temp2.x=1025;
7729                 temp2.y=75;
7730                 temp2.z=447;
7731                 temp3.x=1038;
7732                 temp3.y=76;
7733                 temp3.z=453;
7734                 oldtemp=temp;
7735                 oldtemp2=temp2;
7736                 if(tutorialstage>=51)
7737                     if(findDistancefast(&temp,&player[0].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[0].coords)<4){
7738                         OPENAL_StopSound(OPENAL_ALL);  // hack...OpenAL renderer isn't stopping music after tutorial goes to level menu...
7739                         OPENAL_SetFrequency(OPENAL_ALL, 0.001);
7740
7741                         emit_stream_np(stream_menutheme);
7742
7743                         gameon=0;
7744                         mainmenu=5;
7745
7746                         fireSound();
7747
7748                         flash();
7749                     }
7750                 if(tutorialstage<51)
7751                     if(findDistancefast(&temp,&player[0].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[0].coords)<4){
7752                         emit_sound_at(fireendsound, player[0].coords);
7753
7754                         player[0].coords=(oldtemp+oldtemp2)/2;
7755
7756                         flash();
7757                     }
7758                 if(tutorialstage>=14&&tutorialstage<50)
7759                     if(findDistancefast(&temp,&player[1].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[1].coords)<4){
7760                         emit_sound_at(fireendsound, player[1].coords);
7761
7762                         for(int i=0;i<player[1].skeleton.num_joints;i++){
7763                             if(Random()%2==0){
7764                                 if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
7765                                 if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
7766                                 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;
7767                                 if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
7768                                 Sprite::MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
7769                             }
7770                         }
7771
7772                         player[1].coords=(oldtemp+oldtemp2)/2;
7773                         for(int i=0;i<player[1].skeleton.num_joints;i++){
7774                             player[1].skeleton.joints[i].velocity=0;
7775                             if(Random()%2==0){
7776                                 if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
7777                                 if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
7778                                 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;
7779                                 if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
7780                                 Sprite::MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
7781                             }
7782                         }
7783                     }
7784             }
7785
7786
7787             //3d sound
7788             static float gLoc[3];
7789             gLoc[0]=viewer.x;
7790             gLoc[1]=viewer.y;
7791             gLoc[2]=viewer.z;
7792             static float vel[3];
7793             vel[0]=(viewer.x-oldviewer.x)/multiplier;
7794             vel[1]=(viewer.y-oldviewer.y)/multiplier;
7795             vel[2]=(viewer.z-oldviewer.z)/multiplier;
7796
7797             //Set orientation with forward and up vectors
7798             static XYZ upvector;
7799             upvector=0;
7800             upvector.z=-1;
7801
7802             upvector=DoRotation(upvector,-pitch+90,0,0);
7803             upvector=DoRotation(upvector,0,0-yaw,0);
7804
7805             facing=0;
7806             facing.z=-1;
7807
7808             facing=DoRotation(facing,-pitch,0,0);
7809             facing=DoRotation(facing,0,0-yaw,0);
7810
7811
7812             static float ori[6];
7813             ori[0] = -facing.x;
7814             ori[1] = facing.y;
7815             ori[2] = -facing.z;
7816             ori[3] = -upvector.x;
7817             ori[4] = upvector.y;
7818             ori[5] = -upvector.z;
7819
7820             OPENAL_3D_Listener_SetAttributes(&gLoc[0], &vel[0], ori[0], ori[1], ori[2], ori[3], ori[4], ori[5]);
7821             OPENAL_Update();
7822
7823             oldviewer=viewer;
7824                 }
7825         }
7826
7827         if(Input::isKeyPressed(SDLK_F1))
7828                 Screenshot();
7829 }
7830
7831 void Game::TickOnce(){
7832         if(mainmenu)
7833                 yaw+=multiplier*5;
7834         else
7835                 if(directing||indialogue==-1) {
7836                         yaw+=deltah*.7;
7837                         if(!invertmouse)
7838                 pitch+=deltav*.7;
7839                         if(invertmouse)
7840                 pitch-=deltav*.7;
7841                         if(pitch>90)
7842                 pitch=90;
7843                         if(pitch<-70)
7844                 pitch=-70;
7845                 }
7846 }
7847
7848 void Game::TickOnceAfter(){
7849         static XYZ colviewer;
7850         static XYZ coltarget;
7851         static XYZ target;
7852         static XYZ col;
7853         static XYZ facing;
7854         static float changedelay;
7855         static bool alldead;
7856         static float unseendelay;
7857         static float cameraspeed;
7858
7859         if(!mainmenu){
7860         static int oldmusictype=musictype;
7861
7862                 if(environment==snowyenvironment)
7863             leveltheme=stream_snowtheme;
7864                 if(environment==grassyenvironment)
7865             leveltheme=stream_grasstheme;
7866                 if(environment==desertenvironment)
7867             leveltheme=stream_deserttheme;
7868
7869                 realthreat=0;
7870
7871                 musictype=leveltheme;
7872                 for(int i=0;i<numplayers;i++){
7873                         if((player[i].aitype==attacktypecutoff||
7874                         player[i].aitype==getweapontype||
7875                         player[i].aitype==gethelptype||
7876                         player[i].aitype==searchtype)&&
7877                     !player[i].dead/*&&player[i].surprised<=0*/&&
7878                     (player[i].targetanimation!=sneakattackedanim&&
7879                      player[i].targetanimation!=knifesneakattackedanim&&
7880                      player[i].targetanimation!=swordsneakattackedanim)){
7881                                 musictype=stream_fighttheme;
7882                                 realthreat=1;
7883                         }
7884                 }
7885                 if(player[0].dead)
7886             musictype=stream_menutheme;
7887
7888
7889                 if(musictype==stream_fighttheme)
7890                         unseendelay=1;
7891
7892                 if(oldmusictype==stream_fighttheme&&musictype!=stream_fighttheme){
7893                         unseendelay-=multiplier;
7894                         if(unseendelay>0)
7895                                 musictype=stream_fighttheme;
7896                 }
7897
7898
7899                 if(loading==2){
7900                         musictype=stream_menutheme;
7901                         musicvolume[2]=512;
7902                         musicvolume[0]=0;
7903                         musicvolume[1]=0;
7904                         musicvolume[3]=0;
7905                 }
7906
7907                 if(musictoggle)
7908                         if(musictype!=oldmusictype&&musictype==stream_fighttheme)
7909                                 emit_sound_np(alarmsound);
7910                 musicselected=musictype;
7911
7912                 if(musicselected==leveltheme)
7913             musicvolume[0]+=multiplier*450;
7914                 else
7915             musicvolume[0]-=multiplier*450;
7916                 if(musicselected==stream_fighttheme)
7917             musicvolume[1]+=multiplier*450;
7918                 else
7919             musicvolume[1]-=multiplier*450;
7920                 if(musicselected==stream_menutheme)
7921             musicvolume[2]+=multiplier*450;
7922                 else
7923             musicvolume[2]-=multiplier*450;
7924
7925                 for(int i=0;i<3;i++){
7926                         if(musicvolume[i]<0)
7927                 musicvolume[i]=0;
7928                         if(musicvolume[i]>512)
7929                 musicvolume[i]=512;
7930                 }
7931
7932                 if(musicvolume[2]>128&&!loading&&!mainmenu)
7933             musicvolume[2]=128;
7934
7935                 if(musictoggle){
7936                         if(musicvolume[0]>0&&oldmusicvolume[0]<=0)
7937                           emit_stream_np(leveltheme, musicvolume[0]);
7938                         if(musicvolume[1]>0&&oldmusicvolume[1]<=0)
7939                           emit_stream_np(stream_fighttheme, musicvolume[1]);
7940                         if(musicvolume[2]>0&&oldmusicvolume[2]<=0)
7941                           emit_stream_np(stream_menutheme, musicvolume[2]);
7942                         if(musicvolume[0]<=0&&oldmusicvolume[0]>0)
7943                                 pause_sound(leveltheme);
7944                         if(musicvolume[1]<=0&&oldmusicvolume[1]>0)
7945                                 pause_sound(stream_fighttheme);
7946                         if(musicvolume[2]<=0&&oldmusicvolume[2]>0)
7947                                 pause_sound(stream_menutheme);
7948
7949                         if(musicvolume[0]!=oldmusicvolume[0])
7950                                 OPENAL_SetVolume(channels[leveltheme], musicvolume[0]);
7951                         if(musicvolume[1]!=oldmusicvolume[1])
7952                                 OPENAL_SetVolume(channels[stream_fighttheme], musicvolume[1]);
7953                         if(musicvolume[2]!=oldmusicvolume[2])
7954                                 OPENAL_SetVolume(channels[stream_menutheme], musicvolume[2]);
7955
7956                         for(int i=0;i<3;i++)
7957                                 oldmusicvolume[i]=musicvolume[i];
7958                 } else {
7959                         pause_sound(leveltheme);
7960                         pause_sound(stream_fighttheme);
7961                         pause_sound(stream_menutheme);
7962
7963                         for(int i=0;i<4;i++){
7964                                 oldmusicvolume[i]=0;
7965                                 musicvolume[i]=0;
7966                         }
7967                 }
7968
7969                 killhotspot=2;
7970                 for(int i=0;i<numhotspots;i++){
7971                         if(hotspottype[i]>10&&hotspottype[i]<20){
7972                                 if(player[hotspottype[i]-10].dead==0)
7973                                         killhotspot=0;
7974                                 else if(killhotspot==2)
7975                                         killhotspot=1;
7976                         }
7977                 }
7978                 if(killhotspot==2)
7979             killhotspot=0;
7980
7981
7982                 winhotspot=false;
7983                 for(int i=0;i<numhotspots;i++)
7984                         if(hotspottype[i]==-1)
7985                                 if(findDistancefast(&player[0].coords,&hotspot[i])<hotspotsize[i])
7986                                         winhotspot=true;
7987
7988                 int numalarmed=0;
7989                 for(int i=1;i<numplayers;i++)
7990                         if(!player[i].dead&&player[i].aitype==attacktypecutoff&&player[i].surprised<=0)
7991                 numalarmed++;
7992                 if(numalarmed>maxalarmed)
7993             maxalarmed=numalarmed;
7994
7995                 if(changedelay<=0&&!loading&&!editorenabled&&gameon&&!tutoriallevel&&changedelay!=-999&&!won){
7996                         if(player[0].dead&&changedelay<=0){
7997                                 changedelay=1;
7998                                 targetlevel=whichlevel;
7999                         }
8000                         alldead=true;
8001                         for(int i=1;i<numplayers;i++) {
8002                                 if(!player[i].dead&&player[i].howactive<typedead1) {
8003                     alldead=false;
8004                     break;
8005                                 }
8006                         }
8007
8008
8009                         if(alldead&&!player[0].dead&&maptype==mapkilleveryone) {
8010                                 changedelay=1;
8011                                 targetlevel=whichlevel+1;
8012                                 if(targetlevel>numchallengelevels-1)targetlevel=0;
8013                         }
8014                         if(winhotspot||windialogue) {
8015                                 changedelay=0.1;
8016                                 targetlevel=whichlevel+1;
8017                                 if(targetlevel>numchallengelevels-1)targetlevel=0;
8018                         }
8019
8020
8021                         if(killhotspot){
8022                                 changedelay=1;
8023                                 targetlevel=whichlevel+1;
8024                                 if(targetlevel>numchallengelevels-1)targetlevel=0;
8025                         }
8026
8027                         if(changedelay>0&&!player[0].dead&&!won) {
8028                                 //high scores, awards, win
8029                                 if(campaign) {
8030                                         accountactive->winCampaignLevel(whichchoice, bonustotal, leveltime);
8031                                         scoreadded=1;
8032                                 } else {
8033                                         accountactive->winLevel(whichlevel,bonustotal-startbonustotal,leveltime);
8034                                 }
8035                                 won=1;
8036                         }
8037                 }
8038
8039                 if(!winfreeze){
8040
8041                         if(leveltime<1){
8042                                 loading=0;
8043                                 changedelay=.1;
8044                                 alldead=false;
8045                                 winhotspot=false;
8046                                 killhotspot=0;
8047                         }
8048
8049                         if(!editorenabled&&gameon&&!mainmenu) {
8050                                 if(changedelay!=-999)
8051                     changedelay-=multiplier/7;
8052                                 if(player[0].dead)
8053                     targetlevel=whichlevel;
8054                                 if(loading==2&&!campaign){
8055                                         flash();
8056
8057                                         fireSound(firestartsound);
8058
8059                                         if(!player[0].dead&&targetlevel!=whichlevel)
8060                                                 startbonustotal=bonustotal;
8061                                         if(player[0].dead)
8062                         Loadlevel(whichlevel);
8063                                         else
8064                         Loadlevel(targetlevel);
8065
8066                                         fireSound();
8067
8068                                         loading=3;
8069                                 }
8070                                 if(loading==2&&targetlevel==whichlevel){
8071                                         flash();
8072                                         loadtime=0;
8073
8074                                         fireSound(firestartsound);
8075
8076                                         Loadlevel(campaignlevels[accountactive->getCampaignChoicesMade()].mapname.c_str());
8077
8078                                         fireSound();
8079
8080                                         loading=3;
8081                                 }
8082                                 if(changedelay<=-999&&
8083                         whichlevel!=-2&&
8084                         !loading&&
8085                         (player[0].dead||
8086                          (alldead&&maptype==mapkilleveryone)||
8087                          (winhotspot)||
8088                          (killhotspot)))
8089                     loading=1;
8090                                 if((player[0].dead||
8091                             (alldead&&maptype==mapkilleveryone)||
8092                             (winhotspot)||
8093                             (windialogue)||
8094                             (killhotspot))&&
8095                         changedelay<=0) {
8096                     if(whichlevel!=-2&&!loading&&!player[0].dead) {
8097                         winfreeze=true;
8098                         changedelay=-999;
8099                     }
8100                     if(player[0].dead)
8101                         loading=1;
8102                                 }
8103                         }
8104
8105                         if(campaign) {
8106                 // campaignchoosenext determines what to do when the level is complete:
8107                 // 0 = load next level
8108                 // 1 = go back to level select screen
8109                 // 2 = stealthload next level
8110                                 if(mainmenu==0&&winfreeze&&(campaignlevels[actuallevel].choosenext)==1) {
8111                                         if(campaignlevels[actuallevel].nextlevel.empty())
8112                                                 endgame=1;
8113                                 } else if(mainmenu==0&&winfreeze) {
8114                                         stealthloading = (campaignlevels[actuallevel].choosenext==2);
8115
8116                                         if(!stealthloading){
8117                                                 fireSound(firestartsound);
8118
8119                                                 flash();
8120                                         }
8121
8122                                         startbonustotal=0;
8123
8124                                         LoadCampaign();
8125
8126                                         loading=2;
8127                                         loadtime=0;
8128                                         targetlevel=7;
8129                                         if(!firstload)
8130                                                 LoadStuff();
8131                                         whichchoice=0;
8132                                         actuallevel=campaignlevels[actuallevel].nextlevel.front();
8133                                         visibleloading=1;
8134                                         stillloading=1;
8135                                         Loadlevel(campaignlevels[actuallevel].mapname.c_str());
8136                                         campaign=1;
8137                                         mainmenu=0;
8138                                         gameon=1;
8139                                         pause_sound(stream_menutheme);
8140
8141                                         stealthloading=0;
8142                                 }
8143             }
8144
8145             if(loading==3)
8146                 loading=0;
8147
8148         }
8149
8150         oldmusictype=musictype;
8151         }
8152
8153         facing=0;
8154         facing.z=-1;
8155
8156         facing=DoRotation(facing,-pitch,0,0);
8157         facing=DoRotation(facing,0,0-yaw,0);
8158         viewerfacing=facing;
8159
8160         if(!cameramode){
8161                 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;
8162                 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;
8163                 target.y+=.1;
8164                 if(player[0].skeleton.free){
8165                         for(int i=0;i<player[0].skeleton.num_joints;i++){
8166                                 if(player[0].skeleton.joints[i].position.y*player[0].scale+player[0].coords.y>target.y)
8167                                         target.y=player[0].skeleton.joints[i].position.y*player[0].scale+player[0].coords.y;
8168                         }
8169                         target.y+=.1;
8170                 }
8171                 if(player[0].skeleton.free!=2/*&&!autocam*/){
8172                         cameraspeed=20;
8173                         if(findLengthfast(&player[0].velocity)>400){
8174                                 cameraspeed=20+(findLength(&player[0].velocity)-20)*.96;
8175                         }
8176                         if(player[0].skeleton.free==0&&player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim)target.y+=1.4;
8177                         coltarget=target-cameraloc;
8178                         if(findLengthfast(&coltarget)<multiplier*multiplier*400)cameraloc=target;
8179                         else {
8180                                 Normalise(&coltarget);
8181                                 if(player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim&&player[0].currentanimation!=climbanim&&player[0].currentoffset.x==0)cameraloc=cameraloc+coltarget*multiplier*cameraspeed;
8182                                 else cameraloc=cameraloc+coltarget*multiplier*8;
8183                         }
8184                         if(editorenabled)cameraloc=target;
8185                         cameradist+=multiplier*5;
8186                         if(cameradist>2.3)cameradist=2.3;
8187                         viewer=cameraloc-facing*cameradist;
8188                         colviewer=viewer;
8189                         coltarget=cameraloc;
8190                         objects.SphereCheckPossible(&colviewer, findDistance(&colviewer,&coltarget));
8191                         if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
8192                                 for(int j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
8193                                         int i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
8194                                         colviewer=viewer;
8195                                         coltarget=cameraloc;
8196                                         if(objects.model[i].LineCheckPossible(&colviewer,&coltarget,&col,&objects.position[i],&objects.yaw[i])!=-1)viewer=col;
8197                                 }
8198             if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
8199                 for(int j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
8200                     int i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
8201                     colviewer=viewer;
8202                     if(objects.model[i].SphereCheck(&colviewer,.15,&col,&objects.position[i],&objects.yaw[i])!=-1){
8203                         viewer=colviewer;
8204                     }
8205                 }
8206             cameradist=findDistance(&viewer,&target);
8207             viewer.y=max((double)viewer.y,terrain.getHeight(viewer.x,viewer.z)+.6);
8208             if(cameraloc.y<terrain.getHeight(cameraloc.x,cameraloc.z)){
8209                 cameraloc.y=terrain.getHeight(cameraloc.x,cameraloc.z);
8210             }
8211                 }
8212         /*
8213         //what did autocam do?
8214                 if(player[0].skeleton.free!=2&&autocam){
8215                         cameraspeed=20;
8216                         if(findLengthfast(&player[0].velocity)>400){
8217                                 cameraspeed=20+(findLength(&player[0].velocity)-20)*.96;
8218                         }
8219                         if(player[0].skeleton.free==0&&player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim)target.y+=1.4;
8220                         cameradist+=multiplier*5;
8221                         if(cameradist>3.3)cameradist=3.3;
8222                         coltarget=target-cameraloc;
8223                         if(findLengthfast(&coltarget)<multiplier*multiplier*400)cameraloc=target;
8224                         else if(findLengthfast(&coltarget)>1)
8225                         {
8226                                 Normalise(&coltarget);
8227                                 if(player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim&&player[0].currentanimation!=climbanim&&player[0].currentoffset.x==0)cameraloc=cameraloc+coltarget*multiplier*cameraspeed;
8228                                 else cameraloc=cameraloc+coltarget*multiplier*8;
8229                         }
8230                         if(editorenabled)cameraloc=target;
8231                         viewer=cameraloc;
8232                         colviewer=viewer;
8233                         coltarget=cameraloc;
8234                         objects.SphereCheckPossible(&colviewer, findDistance(&colviewer,&coltarget));
8235                         if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
8236                                 for(int j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
8237                                         int i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
8238                                         colviewer=viewer;
8239                                         coltarget=cameraloc;
8240                                         if(objects.model[i].LineCheckPossible(&colviewer,&coltarget,&col,&objects.position[i],&objects.yaw[i])!=-1)viewer=col;
8241                                 }
8242             if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
8243                 for(int j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
8244                     int i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
8245                     colviewer=viewer;
8246                     if(objects.model[i].SphereCheck(&colviewer,.15,&col,&objects.position[i],&objects.yaw[i])!=-1){
8247                         viewer=colviewer;
8248                     }
8249                 }
8250             cameradist=findDistance(&viewer,&target);
8251             viewer.y=max((double)viewer.y,terrain.getHeight(viewer.x,viewer.z)+.6);
8252             if(cameraloc.y<terrain.getHeight(cameraloc.x,cameraloc.z)){
8253                 cameraloc.y=terrain.getHeight(cameraloc.x,cameraloc.z);
8254             }
8255                 }
8256         */
8257                 if(camerashake>.8)camerashake=.8;
8258                 //if(woozy>10)woozy=10;
8259                 //woozy+=multiplier;
8260                 woozy+=multiplier;
8261                 if(player[0].dead)camerashake=0;
8262                 if(player[0].dead)woozy=0;
8263                 camerashake-=multiplier*2;
8264                 blackout-=multiplier*2;
8265                 //if(player[0].isCrouch())woozy-=multiplier*8;
8266                 if(camerashake<0)camerashake=0;
8267                 if(blackout<0)blackout=0;
8268                 //if(woozy<0)woozy=0;
8269                 if(camerashake){
8270                         viewer.x+=(float)(Random()%100)*.0005*camerashake;
8271                         viewer.y+=(float)(Random()%100)*.0005*camerashake;
8272                         viewer.z+=(float)(Random()%100)*.0005*camerashake;
8273                 }
8274         }
8275 }
8276