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