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