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