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