]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Person.cpp
0ca911a0114ae16dc010426f0ca72150036966bd
[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 ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
600                 return PersonType::types[creature].animFightIdle;
601             }
602             if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
603                 if (weapons[weaponids[weaponactive]].getType() == knife) {
604                     return knifefightidleanim;
605                 }
606                 if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1) {
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 (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause) {
617                 return fightsidestep;
618             }
619         }
620     }
621     if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype) {
622         return hurtidleanim;
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 && (weaponactive == -1)) {
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 (aitype != playercontrolled && 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 && aitype != playercontrolled && 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 && aitype != playercontrolled && 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->aitype == playercontrolled || 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->weaponactive != -1) {
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->weaponactive != -1) {
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->weaponactive != -1) {
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->weaponactive != -1) {
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->weaponactive != -1) {
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->weaponactive != -1) {
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 (weaponactive != -1) {
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 (aitype != playercontrolled) {
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 && aitype != playercontrolled && 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 && aitype != playercontrolled) {
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 (weaponactive != -1 && 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 (aitype == playercontrolled) {
2051                 feint = 0;
2052             }
2053         } else {
2054             if (!crouchtogglekeydown && Animation::animations[animTarget].attack == reversed && aitype == playercontrolled && (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 && (weaponactive == -1 || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
2105                 if (weapons[weaponids[0]].getType() == knife) {
2106                     if (weaponactive == -1) {
2107                         weaponactive = 0;
2108                     } else if (weaponactive == 0) {
2109                         weaponactive = -1;
2110                     }
2111
2112                     if (weaponactive == -1) {
2113                         emit_sound_at(knifesheathesound, coords);
2114                     }
2115                     if (weaponactive != -1) {
2116                         emit_sound_at(knifedrawsound, coords, 128);
2117                     }
2118                 }
2119                 drawtogglekeydown = 1;
2120             }
2121             //Footstep sounds
2122             if (!Tutorial::active || id == 0) {
2123                 if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
2124                     int whichsound = -1;
2125                     if (onterrain) {
2126                         if (terrain.getOpacity(coords.x, coords.z) < .2) {
2127                             if (targetFrame().label == 1) {
2128                                 whichsound = footstepsound;
2129                             } else {
2130                                 whichsound = footstepsound2;
2131                             }
2132                             if (targetFrame().label == 1) {
2133                                 FootLand(leftfoot, 1);
2134                             }
2135                             if (targetFrame().label == 2) {
2136                                 FootLand(rightfoot, 1);
2137                             }
2138                             if (targetFrame().label == 3 && isRun()) {
2139                                 FootLand(rightfoot, 1);
2140                                 FootLand(leftfoot, 1);
2141                             }
2142                         }
2143                         if (terrain.getOpacity(coords.x, coords.z) >= .2) {
2144                             if (targetFrame().label == 1) {
2145                                 whichsound = footstepsound3;
2146                             } else {
2147                                 whichsound = footstepsound4;
2148                             }
2149                         }
2150                     }
2151                     if (!onterrain) {
2152                         if (targetFrame().label == 1) {
2153                             whichsound = footstepsound3;
2154                         } else {
2155                             whichsound = footstepsound4;
2156                         }
2157                     }
2158                     if (targetFrame().label == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
2159                         if (Animation::animations[animTarget].attack != neutral) {
2160                             unsigned r = abs(Random() % 3);
2161                             if (r == 0) {
2162                                 whichsound = lowwhooshsound;
2163                             }
2164                             if (r == 1) {
2165                                 whichsound = midwhooshsound;
2166                             }
2167                             if (r == 2) {
2168                                 whichsound = highwhooshsound;
2169                             }
2170                         }
2171                         if (Animation::animations[animTarget].attack == neutral) {
2172                             whichsound = movewhooshsound;
2173                         }
2174                     } else if (targetFrame().label == 4) {
2175                         whichsound = knifeswishsound;
2176                     }
2177                     if (targetFrame().label == 8 && !Tutorial::active) {
2178                         whichsound = landsound2;
2179                     }
2180
2181                     if (whichsound != -1) {
2182                         emit_sound_at(whichsound, coords, 256.);
2183
2184                         if (id == 0) {
2185                             if (whichsound == footstepsound || whichsound == footstepsound2 || whichsound == footstepsound3 || whichsound == footstepsound4) {
2186                                 if (animTarget == wolfrunninganim || animTarget == rabbitrunninganim) {
2187                                     addEnvSound(coords, 15);
2188                                 } else {
2189                                     addEnvSound(coords, 6);
2190                                 }
2191                             }
2192                         }
2193
2194                         if (targetFrame().label == 3) {
2195                             whichsound--;
2196                             emit_sound_at(whichsound, coords, 128.);
2197                         }
2198                     }
2199                 }
2200             }
2201
2202             //Combat sounds
2203             if (!Tutorial::active || id == 0) {
2204                 if (speechdelay <= 0) {
2205                     if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) {
2206                         if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
2207                             int whichsound = -1;
2208                             if (targetFrame().label == 4 && aitype != playercontrolled) {
2209                                 if (Animation::animations[animTarget].attack != neutral) {
2210                                     unsigned r = abs(Random() % 4);
2211                                     whichsound = PersonType::types[creature].soundsAttack[r];
2212                                     speechdelay = .3;
2213                                 }
2214                             }
2215
2216                             if (whichsound != -1) {
2217                                 emit_sound_at(whichsound, coords);
2218                             }
2219                         }
2220                     }
2221                 }
2222             }
2223
2224             if ((!wasLanding() && !wasLandhard()) && animCurrent != getIdle() && (isLanding() || isLandhard())) {
2225                 FootLand(leftfoot, 1);
2226                 FootLand(rightfoot, 1);
2227             }
2228
2229             transspeed = 0;
2230             currentoffset = targetoffset;
2231             frameTarget = frameCurrent;
2232             animCurrent = animTarget;
2233             frameTarget++;
2234
2235             if (animCurrent == removeknifeanim && currentFrame().label == 5) {
2236                 for (unsigned i = 0; i < weapons.size(); i++) {
2237                     if (weapons[i].owner == -1) {
2238                         if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
2239                             if (distsq(&coords, &weapons[i].position) >= 1) {
2240                                 if (weapons[i].getType() != staff) {
2241                                     emit_sound_at(knifedrawsound, coords, 128.);
2242                                 }
2243
2244                                 takeWeapon(i);
2245                             }
2246                         }
2247                     }
2248                 }
2249             }
2250
2251             if (animCurrent == crouchremoveknifeanim && currentFrame().label == 5) {
2252                 for (unsigned i = 0; i < weapons.size(); i++) {
2253                     bool willwork = true;
2254                     if (weapons[i].owner != -1) {
2255                         if (Person::players[weapons[i].owner]->weaponstuck != -1) {
2256                             if (Person::players[weapons[i].owner]->weaponids[Person::players[weapons[i].owner]->weaponstuck] == int(i)) {
2257                                 if (Person::players[weapons[i].owner]->num_weapons > 1) {
2258                                     willwork = 0;
2259                                 }
2260                             }
2261                         }
2262                     }
2263                     if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free)) {
2264                         if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
2265                             if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
2266                                 bool fleshstuck = false;
2267                                 if (weapons[i].owner != -1) {
2268                                     if (victim->weaponstuck != -1) {
2269                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
2270                                             fleshstuck = true;
2271                                         }
2272                                     }
2273                                 }
2274                                 if (fleshstuck) {
2275                                     emit_sound_at(fleshstabremovesound, coords, 128.);
2276                                 } else {
2277                                     if (weapons[i].getType() != staff) {
2278                                         emit_sound_at(knifedrawsound, coords, 128.);
2279                                     }
2280                                 }
2281                                 if (weapons[i].owner != -1) {
2282                                     victim = Person::players[weapons[i].owner];
2283                                     if (victim->num_weapons == 1) {
2284                                         victim->num_weapons = 0;
2285                                     } else {
2286                                         victim->num_weapons = 1;
2287                                     }
2288
2289                                     //victim->weaponactive=-1;
2290                                     victim->skeleton.longdead = 0;
2291                                     victim->skeleton.free = 1;
2292                                     victim->skeleton.broken = 0;
2293
2294                                     for (unsigned j = 0; j < victim->skeleton.joints.size(); j++) {
2295                                         victim->skeleton.joints[j].velchange = 0;
2296                                         victim->skeleton.joints[j].locked = 0;
2297                                     }
2298
2299                                     XYZ relative;
2300                                     relative = 0;
2301                                     relative.y = 10;
2302                                     Normalise(&relative);
2303                                     XYZ footvel, footpoint;
2304                                     footvel = 0;
2305                                     footpoint = weapons[i].position;
2306                                     if (victim->weaponstuck != -1) {
2307                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
2308                                             if (bloodtoggle) {
2309                                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
2310                                             }
2311                                             weapons[i].bloody = 2;
2312                                             weapons[i].blooddrip = 5;
2313                                             victim->weaponstuck = -1;
2314                                         }
2315                                     }
2316                                     if (victim->num_weapons > 0) {
2317                                         if (victim->weaponstuck != 0 && victim->weaponstuck != -1) {
2318                                             victim->weaponstuck = 0;
2319                                         }
2320                                         if (victim->weaponids[0] == int(i)) {
2321                                             victim->weaponids[0] = victim->weaponids[victim->num_weapons];
2322                                         }
2323                                     }
2324
2325                                     victim->jointVel(abdomen) += relative * 6;
2326                                     victim->jointVel(neck) += relative * 6;
2327                                     victim->jointVel(rightshoulder) += relative * 6;
2328                                     victim->jointVel(leftshoulder) += relative * 6;
2329                                 }
2330                                 takeWeapon(i);
2331                             }
2332                         }
2333                     }
2334                 }
2335             }
2336
2337             if (animCurrent == drawleftanim && currentFrame().label == 5) {
2338                 if (weaponactive == -1) {
2339                     weaponactive = 0;
2340                 } else if (weaponactive == 0) {
2341                     weaponactive = -1;
2342                     if (num_weapons == 2) {
2343                         int buffer;
2344                         buffer = weaponids[0];
2345                         weaponids[0] = weaponids[1];
2346                         weaponids[1] = buffer;
2347                     }
2348                 }
2349                 if (weaponactive == -1) {
2350                     emit_sound_at(knifesheathesound, coords, 128.);
2351                 }
2352                 if (weaponactive != -1) {
2353                     emit_sound_at(knifedrawsound, coords, 128.);
2354                 }
2355             }
2356
2357             if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
2358                 XYZ rotatetarget = DoRotation(skeleton.forward, 0, yaw, 0);
2359                 Normalise(&rotatetarget);
2360                 targetyaw = -asin(0 - rotatetarget.x);
2361                 targetyaw *= 360 / 6.28;
2362                 if (rotatetarget.z < 0) {
2363                     targetyaw = 180 - targetyaw;
2364                 }
2365
2366                 if (animTarget == walljumprightkickanim) {
2367                     targetyaw += 40;
2368                 }
2369                 if (animTarget == walljumpleftkickanim) {
2370                     targetyaw -= 40;
2371                 }
2372             }
2373
2374             bool dojumpattack;
2375             dojumpattack = 0;
2376             if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && frameTarget == 3 && (jumpkeydown || attackkeydown || id != 0)) {
2377                 dojumpattack = 1;
2378             }
2379             if (hasvictim) {
2380                 if (distsq(&victim->coords, &/*Person::players[i]->*/ coords) < 5 && victim->aitype == gethelptype && (attackkeydown) && !victim->skeleton.free && victim->isRun() && victim->runninghowlong >= 1) {
2381                     dojumpattack = 1;
2382                 }
2383             }
2384             if (!hostile) {
2385                 dojumpattack = 0;
2386             }
2387             if (dojumpattack) {
2388                 if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && id == 0) {
2389                     animTarget = rabbittackleanim;
2390                     frameTarget = 0;
2391                     emit_sound_at(jumpsound, coords);
2392                 }
2393
2394                 float closestdist;
2395                 closestdist = 0;
2396                 int closestid;
2397                 closestid = -1;
2398                 XYZ targetloc;
2399                 targetloc = velocity;
2400                 Normalise(&targetloc);
2401                 targetloc += coords;
2402                 for (unsigned i = 0; i < Person::players.size(); i++) {
2403                     if (i != id) {
2404                         if (distsq(&targetloc, &Person::players[i]->coords) < closestdist || closestdist == 0) {
2405                             closestdist = distsq(&targetloc, &Person::players[i]->coords);
2406                             closestid = i;
2407                         }
2408                     }
2409                 }
2410                 if (closestid != -1) {
2411                     if (closestdist < 5 && !Person::players[closestid]->dead && Animation::animations[Person::players[closestid]->animTarget].height != lowheight && Person::players[closestid]->animTarget != backhandspringanim) {
2412                         hasvictim = 1;
2413                         victim = Person::players[closestid];
2414                         coords = victim->coords;
2415                         animCurrent = rabbittacklinganim;
2416                         animTarget = rabbittacklinganim;
2417                         frameCurrent = 0;
2418                         frameTarget = 1;
2419                         XYZ rotatetarget;
2420                         if (coords.z != victim->coords.z || coords.x != victim->coords.x) {
2421                             rotatetarget = coords - victim->coords;
2422                             Normalise(&rotatetarget);
2423                             targetyaw = -asin(0 - rotatetarget.x);
2424                             targetyaw *= 360 / 6.28;
2425                             if (rotatetarget.z < 0) {
2426                                 targetyaw = 180 - targetyaw;
2427                             }
2428                         }
2429                         if (animTarget != rabbitrunninganim) {
2430                             emit_sound_at(jumpsound, coords, 128.);
2431                         }
2432                     }
2433                 }
2434             }
2435
2436             //Move impacts
2437             float damagemult = PersonType::types[creature].power * power;
2438             if (hasvictim) {
2439                 damagemult /= victim->damagetolerance / 200;
2440             }
2441             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)) {
2442                 if (animCurrent == spinkickanim && currentFrame().label == 5) {
2443                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
2444                         escapednum = 0;
2445                         if (id == 0) {
2446                             camerashake += .4;
2447                         }
2448                         if (Random() % 2 || PersonType::types[creature].hasClaws) {
2449                             victim->spurt = 1;
2450                             DoBlood(.2, 250);
2451                             if (PersonType::types[creature].hasClaws) {
2452                                 DoBloodBig(0, 250);
2453                             }
2454                         }
2455                         if (!Tutorial::active) {
2456                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
2457                         }
2458                         if (PersonType::types[creature].hasClaws) {
2459                             emit_sound_at(clawslicesound, victim->coords, 128.);
2460                             victim->spurt = 1;
2461                             victim->DoBloodBig(2 / victim->armorhead, 175);
2462                         }
2463                         victim->RagDoll(0);
2464                         XYZ relative;
2465                         relative = victim->coords - coords;
2466                         relative.y = 0;
2467                         Normalise(&relative);
2468                         relative = DoRotation(relative, 0, -90, 0);
2469                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2470                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2471                         }
2472                         victim->jointVel(head) += relative * damagemult * 200;
2473                         victim->Puff(head);
2474                         victim->DoDamage(damagemult * 100 / victim->protectionhead);
2475
2476                         SolidHitBonus(id);
2477                     }
2478                 }
2479
2480                 if (animCurrent == wolfslapanim && currentFrame().label == 5) {
2481                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
2482                         escapednum = 0;
2483                         if (id == 0) {
2484                             camerashake += .4;
2485                         }
2486                         if (Random() % 2 || PersonType::types[creature].hasClaws) {
2487                             victim->spurt = 1;
2488                             if (PersonType::types[creature].hasClaws) {
2489                                 DoBloodBig(0, 235);
2490                             }
2491                         }
2492                         emit_sound_at(whooshhitsound, victim->coords);
2493                         if (PersonType::types[creature].hasClaws) {
2494                             emit_sound_at(clawslicesound, victim->coords, 128.);
2495                             victim->spurt = 1;
2496                             victim->DoBloodBig(2, 175);
2497                         }
2498                         victim->RagDoll(0);
2499                         XYZ relative;
2500                         relative = victim->coords - coords;
2501                         relative.y = 0;
2502                         Normalise(&relative);
2503                         relative.y -= 1;
2504                         Normalise(&relative);
2505                         relative = DoRotation(relative, 0, 90, 0);
2506                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2507                             victim->skeleton.joints[i].velocity += relative * damagemult * 20;
2508                         }
2509                         victim->jointVel(head) += relative * damagemult * 100;
2510                         victim->Puff(head);
2511                         victim->DoDamage(damagemult * 50 / victim->protectionhead);
2512                     }
2513                 }
2514
2515                 if (animCurrent == walljumprightkickanim && currentFrame().label == 5) {
2516                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
2517                         escapednum = 0;
2518                         if (id == 0) {
2519                             camerashake += .4;
2520                         }
2521                         victim->spurt = 1;
2522                         DoBlood(.2, 250);
2523                         if (!Tutorial::active) {
2524                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
2525                         }
2526                         if (PersonType::types[creature].hasClaws) {
2527                             emit_sound_at(clawslicesound, victim->coords, 128.);
2528                             victim->spurt = 1;
2529                             victim->DoBloodBig(2 / victim->armorhead, 175);
2530                         }
2531                         victim->RagDoll(0);
2532                         XYZ relative;
2533                         relative = facing;
2534                         relative.y = 0;
2535                         Normalise(&relative);
2536                         relative = DoRotation(relative, 0, -90, 0);
2537                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2538                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2539                         }
2540                         victim->jointVel(head) += relative * damagemult * 200;
2541                         victim->Puff(head);
2542                         victim->DoDamage(damagemult * 150 / victim->protectionhead);
2543
2544                         if (victim->damage > victim->damagetolerance) {
2545                             award_bonus(id, style);
2546                         } else {
2547                             SolidHitBonus(id);
2548                         }
2549                     }
2550                 }
2551
2552                 if (animCurrent == walljumpleftkickanim && currentFrame().label == 5) {
2553                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
2554                         escapednum = 0;
2555                         if (id == 0) {
2556                             camerashake += .4;
2557                         }
2558                         victim->spurt = 1;
2559                         DoBlood(.2, 250);
2560                         if (!Tutorial::active) {
2561                             emit_sound_at(heavyimpactsound, victim->coords, 160.);
2562                         }
2563                         if (PersonType::types[creature].hasClaws) {
2564                             emit_sound_at(clawslicesound, victim->coords, 128.);
2565                             victim->spurt = 1;
2566                             victim->DoBloodBig(2 / victim->armorhead, 175);
2567                         }
2568                         victim->RagDoll(0);
2569                         XYZ relative;
2570                         relative = facing;
2571                         relative.y = 0;
2572                         Normalise(&relative);
2573                         relative = DoRotation(relative, 0, 90, 0);
2574                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2575                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
2576                         }
2577                         victim->jointVel(head) += relative * damagemult * 200;
2578                         victim->Puff(head);
2579                         victim->DoDamage(damagemult * 150 / victim->protectionhead);
2580
2581                         if (victim->damage > victim->damagetolerance) {
2582                             award_bonus(id, style);
2583                         } else {
2584                             SolidHitBonus(id);
2585                         }
2586                     }
2587                 }
2588
2589                 if (animCurrent == blockhighleftstrikeanim && currentFrame().label == 5) {
2590                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != lowheight) {
2591                         escapednum = 0;
2592                         if (id == 0) {
2593                             camerashake += .4;
2594                         }
2595                         if (Random() % 2) {
2596                             victim->spurt = 1;
2597                             DoBlood(.2, 235);
2598                         }
2599                         emit_sound_at(whooshhitsound, victim->coords);
2600                         victim->RagDoll(0);
2601                         XYZ relative;
2602                         relative = victim->coords - coords;
2603                         relative.y = 0;
2604                         Normalise(&relative);
2605                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2606                             victim->skeleton.joints[i].velocity += relative * damagemult * 30;
2607                         }
2608                         victim->jointVel(head) += relative * damagemult * 100;
2609                         victim->Puff(head);
2610                         victim->DoDamage(damagemult * 50 / victim->protectionhead);
2611                     }
2612                 }
2613
2614                 if (animCurrent == killanim && currentFrame().label == 8) {
2615                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && victim->dead) {
2616                         escapednum = 0;
2617                         if (id == 0) {
2618                             camerashake += .2;
2619                         }
2620                         emit_sound_at(whooshhitsound, victim->coords, 128.);
2621
2622                         victim->skeleton.longdead = 0;
2623                         victim->skeleton.free = 1;
2624                         victim->skeleton.broken = 0;
2625                         victim->skeleton.spinny = 1;
2626
2627                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2628                             victim->skeleton.joints[i].velchange = 0;
2629                             victim->skeleton.joints[i].delay = 0;
2630                             victim->skeleton.joints[i].locked = 0;
2631                             //victim->skeleton.joints[i].velocity=0;
2632                         }
2633
2634                         XYZ relative;
2635                         relative = 0;
2636                         relative.y = 1;
2637                         Normalise(&relative);
2638                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2639                             victim->skeleton.joints[i].velocity.y = relative.y * 10;
2640                             victim->skeleton.joints[i].position.y += relative.y * .3;
2641                             victim->skeleton.joints[i].oldposition.y += relative.y * .3;
2642                             victim->skeleton.joints[i].realoldposition.y += relative.y * .3;
2643                         }
2644                         victim->Puff(abdomen);
2645                         victim->jointVel(abdomen).y = relative.y * 400;
2646                     }
2647                 }
2648
2649                 if (animCurrent == killanim && currentFrame().label == 5) {
2650                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->dead) {
2651                         escapednum = 0;
2652                         if (id == 0) {
2653                             camerashake += .4;
2654                         }
2655                         if (!Tutorial::active) {
2656                             emit_sound_at(heavyimpactsound, coords, 128.);
2657                         }
2658                         XYZ relative;
2659                         relative = victim->coords - coords;
2660                         relative.y = 0;
2661                         Normalise(&relative);
2662                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2663                             victim->skeleton.joints[i].velocity += relative * damagemult * 90;
2664                         }
2665                         victim->Puff(abdomen);
2666                         if (victim->dead != 2 && victim->permanentdamage > victim->damagetolerance - 250 && autoslomo) {
2667                             slomo = 1;
2668                             slomodelay = .2;
2669                         }
2670                         victim->DoDamage(damagemult * 500 / victim->protectionhigh);
2671                         victim->jointVel(abdomen) += relative * damagemult * 300;
2672                     }
2673                 }
2674
2675                 if (animCurrent == dropkickanim && currentFrame().label == 7) {
2676                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 9 && victim->skeleton.free) {
2677                         escapednum = 0;
2678                         if (id == 0) {
2679                             camerashake += .4;
2680                         }
2681                         if (!Tutorial::active) {
2682                             emit_sound_at(thudsound, coords);
2683                         }
2684
2685                         victim->skeleton.longdead = 0;
2686                         victim->skeleton.free = 1;
2687                         victim->skeleton.broken = 0;
2688                         victim->skeleton.spinny = 1;
2689
2690                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2691                             victim->skeleton.joints[i].velchange = 0;
2692                             //victim->skeleton.joints[i].delay=0;
2693                             victim->skeleton.joints[i].locked = 0;
2694                         }
2695                         XYZ relative;
2696                         relative = victim->coords - coords;
2697                         Normalise(&relative);
2698                         relative.y += .3;
2699                         Normalise(&relative);
2700                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2701                             victim->skeleton.joints[i].velocity += relative * damagemult * 20;
2702                         }
2703                         if (!victim->dead) {
2704                             SolidHitBonus(id);
2705                         }
2706
2707                         victim->Puff(abdomen);
2708                         victim->DoDamage(damagemult * 20 / victim->protectionhigh);
2709                         victim->jointVel(abdomen) += relative * damagemult * 200;
2710                         staggerdelay = .5;
2711                         if (!victim->dead) {
2712                             staggerdelay = 1.2;
2713                         }
2714                     }
2715                 }
2716
2717                 if ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().label == 5) {
2718
2719                     if (hasvictim) {
2720                         if (!victim->skeleton.free) {
2721                             hasvictim = 0;
2722                         }
2723                     }
2724
2725                     if (!hasvictim) {
2726                         terrain.MakeDecal(blooddecalfast, (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2), .08, .6, Random() % 360);
2727                         emit_sound_at(knifesheathesound, coords, 128.);
2728                     }
2729
2730                     if (victim && hasvictim) {
2731                         if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2732
2733                             XYZ where, startpoint, endpoint, movepoint, colpoint;
2734                             float rotationpoint;
2735                             int whichtri;
2736                             if (weapons[weaponids[weaponactive]].getType() == knife) {
2737                                 where = (weapons[weaponids[weaponactive]].tippoint * .6 + weapons[weaponids[weaponactive]].position * .4);
2738                                 where -= victim->coords;
2739                                 if (!victim->skeleton.free) {
2740                                     where = DoRotation(where, 0, -victim->yaw, 0);
2741                                 }
2742                                 //where=scale;
2743                                 startpoint = where;
2744                                 startpoint.y += 100;
2745                                 endpoint = where;
2746                                 endpoint.y -= 100;
2747                             }
2748                             if (weapons[weaponids[weaponactive]].getType() == sword) {
2749                                 where = weapons[weaponids[weaponactive]].position;
2750                                 where -= victim->coords;
2751                                 if (!victim->skeleton.free) {
2752                                     where = DoRotation(where, 0, -victim->yaw, 0);
2753                                 }
2754                                 startpoint = where;
2755                                 where = weapons[weaponids[weaponactive]].tippoint;
2756                                 where -= victim->coords;
2757                                 if (!victim->skeleton.free) {
2758                                     where = DoRotation(where, 0, -victim->yaw, 0);
2759                                 }
2760                                 endpoint = where;
2761                             }
2762                             if (weapons[weaponids[weaponactive]].getType() == staff) {
2763                                 where = weapons[weaponids[weaponactive]].position;
2764                                 where -= victim->coords;
2765                                 if (!victim->skeleton.free) {
2766                                     where = DoRotation(where, 0, -victim->yaw, 0);
2767                                 }
2768                                 startpoint = where;
2769                                 where = weapons[weaponids[weaponactive]].tippoint;
2770                                 where -= victim->coords;
2771                                 if (!victim->skeleton.free) {
2772                                     where = DoRotation(where, 0, -victim->yaw, 0);
2773                                 }
2774                                 endpoint = where;
2775                             }
2776                             movepoint = 0;
2777                             rotationpoint = 0;
2778                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
2779
2780                             if (whichtri != -1) {
2781                                 if (victim->dead != 2) {
2782                                     victim->DoDamage(abs((victim->damagetolerance - victim->permanentdamage) * 2));
2783                                     if (!victim->dead) {
2784                                         award_bonus(id, FinishedBonus);
2785                                     }
2786                                 }
2787                                 if (bloodtoggle) {
2788                                     weapons[weaponids[weaponactive]].bloody = 2;
2789                                 }
2790
2791                                 victim->skeleton.longdead = 0;
2792                                 victim->skeleton.free = 1;
2793                                 victim->skeleton.broken = 0;
2794
2795                                 for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2796                                     victim->skeleton.joints[i].velchange = 0;
2797                                     victim->skeleton.joints[i].locked = 0;
2798                                     //victim->skeleton.joints[i].velocity=0;
2799                                 }
2800                                 emit_sound_at(fleshstabsound, coords, 128);
2801                             }
2802                             if (whichtri != -1 || weapons[weaponids[weaponactive]].bloody) {
2803                                 weapons[weaponids[weaponactive]].blooddrip += 5;
2804                                 weapons[weaponids[weaponactive]].blooddripdelay = 0;
2805                             }
2806                             if (whichtri == -1) {
2807                                 hasvictim = 0;
2808                                 emit_sound_at(knifesheathesound, coords, 128.);
2809                             }
2810                         }
2811                     }
2812                 }
2813
2814                 if ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().label == 6) {
2815                     if (!hasvictim) {
2816                         emit_sound_at(knifedrawsound, coords, 128);
2817                     }
2818
2819                     if (victim && hasvictim) {
2820                         XYZ footvel, footpoint;
2821
2822                         emit_sound_at(fleshstabremovesound, coords, 128.);
2823
2824                         footvel = 0;
2825                         footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2826
2827                         if (weapons[weaponids[weaponactive]].getType() == sword) {
2828                             XYZ where, startpoint, endpoint, movepoint;
2829                             float rotationpoint;
2830                             int whichtri;
2831
2832                             where = weapons[weaponids[weaponactive]].position;
2833                             where -= victim->coords;
2834                             if (!victim->skeleton.free) {
2835                                 where = DoRotation(where, 0, -victim->yaw, 0);
2836                             }
2837                             startpoint = where;
2838                             where = weapons[weaponids[weaponactive]].tippoint;
2839                             where -= victim->coords;
2840                             if (!victim->skeleton.free) {
2841                                 where = DoRotation(where, 0, -victim->yaw, 0);
2842                             }
2843                             endpoint = where;
2844
2845                             movepoint = 0;
2846                             rotationpoint = 0;
2847                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
2848                             footpoint += victim->coords;
2849
2850                             if (whichtri == -1) {
2851                                 footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2852                             }
2853                         }
2854                         if (weapons[weaponids[weaponactive]].getType() == staff) {
2855                             XYZ where, startpoint, endpoint, movepoint;
2856                             float rotationpoint;
2857                             int whichtri;
2858
2859                             where = weapons[weaponids[weaponactive]].position;
2860                             where -= victim->coords;
2861                             if (!victim->skeleton.free) {
2862                                 where = DoRotation(where, 0, -victim->yaw, 0);
2863                             }
2864                             startpoint = where;
2865                             where = weapons[weaponids[weaponactive]].tippoint;
2866                             where -= victim->coords;
2867                             if (!victim->skeleton.free) {
2868                                 where = DoRotation(where, 0, -victim->yaw, 0);
2869                             }
2870                             endpoint = where;
2871
2872                             movepoint = 0;
2873                             rotationpoint = 0;
2874                             whichtri = victim->skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &footpoint, &movepoint, &rotationpoint);
2875                             footpoint += victim->coords;
2876
2877                             if (whichtri == -1) {
2878                                 footpoint = (weapons[weaponids[weaponactive]].tippoint * .8 + weapons[weaponids[weaponactive]].position * .2);
2879                             }
2880                         }
2881                         hasvictim = victim->DoBloodBigWhere(2, 220, footpoint);
2882                         if (hasvictim) {
2883                             if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2884                                 victim->skeleton.longdead = 0;
2885                                 victim->skeleton.free = 1;
2886                                 victim->skeleton.broken = 0;
2887
2888                                 for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2889                                     victim->skeleton.joints[i].velchange = 0;
2890                                     victim->skeleton.joints[i].locked = 0;
2891                                     //victim->skeleton.joints[i].velocity=0;
2892                                 }
2893
2894                                 XYZ relative;
2895                                 relative = 0;
2896                                 relative.y = 10;
2897                                 Normalise(&relative);
2898                                 //victim->Puff(abdomen);
2899                                 if (bloodtoggle) {
2900                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
2901                                 }
2902
2903                                 if (victim->bloodloss < victim->damagetolerance) {
2904                                     victim->bloodloss += 1000;
2905                                     victim->bled = 0;
2906                                 }
2907
2908                                 victim->jointVel(abdomen) += relative * damagemult * 20;
2909                             }
2910                         }
2911                     }
2912                     if (!hasvictim && onterrain) {
2913                         weapons[weaponids[weaponactive]].bloody = 0;
2914                         weapons[weaponids[weaponactive]].blooddrip = 0;
2915                     }
2916                 }
2917
2918                 if (animCurrent == upunchanim && currentFrame().label == 5) {
2919                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) {
2920                         escapednum = 0;
2921                         if (id == 0) {
2922                             camerashake += .4;
2923                         }
2924                         if (Random() % 2) {
2925                             victim->spurt = 1;
2926                             DoBlood(.2, 235);
2927                         }
2928                         if (!Tutorial::active) {
2929                             emit_sound_at(heavyimpactsound, victim->coords, 128);
2930                         }
2931
2932                         victim->RagDoll(0);
2933                         XYZ relative;
2934                         relative = victim->coords - coords;
2935                         relative.y = 0;
2936                         Normalise(&relative);
2937                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2938                             victim->skeleton.joints[i].velocity = relative * 30;
2939                         }
2940                         victim->jointVel(head) += relative * damagemult * 150;
2941
2942                         victim->frameTarget = 0;
2943                         victim->animTarget = staggerbackhardanim;
2944                         victim->targetyaw = targetyaw + 180;
2945                         victim->target = 0;
2946                         victim->stunned = 1;
2947
2948                         victim->Puff(head);
2949                         victim->Puff(abdomen);
2950                         victim->DoDamage(damagemult * 60 / victim->protectionhigh);
2951
2952                         SolidHitBonus(id);
2953                     }
2954                 }
2955
2956                 if (animCurrent == winduppunchanim && currentFrame().label == 5) {
2957                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 2) {
2958                         escapednum = 0;
2959                         if (id == 0) {
2960                             camerashake += .4;
2961                         }
2962                         if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && Animation::animations[victim->animTarget].height != lowheight) {
2963                             if (!Tutorial::active) {
2964                                 emit_sound_at(thudsound, victim->coords);
2965                             }
2966                         } else if (victim->damage <= victim->damagetolerance - 60 && normaldotproduct(victim->facing, victim->coords - coords) < (scale * 5) * (scale * 5) * 0 && Animation::animations[victim->animTarget].height == lowheight) {
2967                             if (!Tutorial::active) {
2968                                 emit_sound_at(whooshhitsound, victim->coords);
2969                             }
2970                         } else {
2971                             if (!Tutorial::active) {
2972                                 emit_sound_at(heavyimpactsound, victim->coords);
2973                             }
2974                         }
2975
2976                         if (victim->damage > victim->damagetolerance - 60 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || Animation::animations[victim->animTarget].height == lowheight) {
2977                             victim->RagDoll(0);
2978                         }
2979                         XYZ relative;
2980                         relative = victim->coords - coords;
2981                         relative.y = 0;
2982                         Normalise(&relative);
2983                         relative.y = .3;
2984                         Normalise(&relative);
2985                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
2986                             victim->skeleton.joints[i].velocity = relative * 5;
2987                         }
2988                         victim->jointVel(abdomen) += relative * damagemult * 400;
2989
2990                         victim->frameTarget = 0;
2991                         victim->animTarget = staggerbackhardanim;
2992                         victim->targetyaw = targetyaw + 180;
2993                         victim->target = 0;
2994                         victim->stunned = 1;
2995
2996                         victim->Puff(abdomen);
2997                         victim->DoDamage(damagemult * 60 / victim->protectionhigh);
2998
2999                         SolidHitBonus(id);
3000                     }
3001                 }
3002
3003                 if (animCurrent == blockhighleftanim && currentFrame().label == 5) {
3004                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
3005                         if (victim->id == 0) {
3006                             camerashake += .4;
3007                         }
3008                         emit_sound_at(landsound2, victim->coords);
3009
3010                         Puff(righthand);
3011                     }
3012                 }
3013
3014                 if (animCurrent == swordslashparryanim && currentFrame().label == 5) {
3015                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4) {
3016                         if (victim->id == 0) {
3017                             camerashake += .4;
3018                         }
3019
3020                         if (weaponactive != -1) {
3021                             if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
3022                                 if (weapons[victim->weaponids[0]].getType() == staff) {
3023                                     weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
3024                                 }
3025                                 if (weapons[weaponids[0]].getType() == staff) {
3026                                     weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
3027                                 }
3028
3029                                 emit_sound_at(swordstaffsound, victim->coords);
3030                             } else {
3031                                 emit_sound_at(metalhitsound, victim->coords);
3032                             }
3033                         }
3034
3035                         //Puff(righthand);
3036                     }
3037                 }
3038
3039                 if (animCurrent == knifethrowanim && currentFrame().label == 5) {
3040                     if (weaponactive != -1) {
3041                         escapednum = 0;
3042                         XYZ aim;
3043                         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);
3044                         Normalise(&aim);
3045                         weapons[weaponids[0]].thrown(aim * 50);
3046                         num_weapons--;
3047                         if (num_weapons) {
3048                             weaponids[0] = weaponids[num_weapons];
3049                         }
3050                         weaponactive = -1;
3051                     }
3052                 }
3053
3054                 if (animCurrent == knifeslashstartanim && currentFrame().label == 5) {
3055                     if (hasvictim) {
3056                         if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 && victim->animTarget != dodgebackanim && victim->animTarget != rollanim) {
3057                             escapednum = 0;
3058                             if (!Tutorial::active) {
3059                                 victim->DoBloodBig(1.5 / victim->armorhigh, 225);
3060                             }
3061
3062                             award_bonus(id, Slicebonus);
3063                             if (!Tutorial::active) {
3064                                 emit_sound_at(knifeslicesound, victim->coords);
3065                             }
3066                             //victim->jointVel(abdomen)+=relative*damagemult*200;
3067                             if (Animation::animations[victim->animTarget].attack && (victim->aitype != playercontrolled || victim->animTarget == knifeslashstartanim) && (victim->creature == rabbittype || victim->deathbleeding <= 0)) {
3068                                 if (victim->id != 0 || difficulty == 2) {
3069                                     victim->frameTarget = 0;
3070                                     victim->animTarget = staggerbackhardanim;
3071                                     victim->targetyaw = targetyaw + 180;
3072                                     victim->target = 0;
3073                                 }
3074                             }
3075                             victim->lowreversaldelay = 0;
3076                             victim->highreversaldelay = 0;
3077                             if (aitype != playercontrolled) {
3078                                 weaponmissdelay = .6;
3079                             }
3080
3081                             if (!Tutorial::active) {
3082                                 if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
3083                                     weapons[weaponids[weaponactive]].bloody = 1;
3084                                 }
3085                                 weapons[weaponids[weaponactive]].blooddrip += 3;
3086                             }
3087
3088                             XYZ footvel, footpoint;
3089                             footvel = 0;
3090                             if (skeleton.free) {
3091                                 footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
3092                             } else {
3093                                 footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
3094                             }
3095                             if (Tutorial::active) {
3096                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .6, .3);
3097                             } else {
3098                                 if (bloodtoggle) {
3099                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .6, .3);
3100                                 }
3101                                 footvel = DoRotation(facing, 0, 90, 0) * .8;
3102                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3103                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3104                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
3105                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
3106                             }
3107                             victim->DoDamage(damagemult * 0);
3108                         }
3109                     }
3110                 }
3111                 if (animCurrent == swordslashanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
3112                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim) {
3113                         if (victim->weaponactive == -1 || normaldotproduct(victim->facing, victim->coords - coords) > 0 || (Random() % 2 == 0)) {
3114                             award_bonus(id, Slashbonus);
3115                             escapednum = 0;
3116                             if (!Tutorial::active) {
3117                                 if (normaldotproduct(victim->facing, victim->coords - coords) < 0) {
3118                                     victim->DoBloodBig(2 / victim->armorhigh, 190);
3119                                 } else {
3120                                     victim->DoBloodBig(2 / victim->armorhigh, 185);
3121                                 }
3122                                 victim->deathbleeding = 1;
3123                                 emit_sound_at(swordslicesound, victim->coords);
3124                                 victim->frameTarget = 0;
3125                                 victim->animTarget = staggerbackhardanim;
3126                                 victim->targetyaw = targetyaw + 180;
3127                                 victim->target = 0;
3128                                 if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
3129                                     weapons[weaponids[weaponactive]].bloody = 1;
3130                                 }
3131                                 weapons[weaponids[weaponactive]].blooddrip += 3;
3132
3133                                 float bloodlossamount;
3134                                 bloodlossamount = 200 + abs((float)(Random() % 40)) - 20;
3135                                 victim->bloodloss += bloodlossamount / victim->armorhigh;
3136                                 victim->DoDamage(damagemult * 0);
3137
3138                                 XYZ footvel, footpoint;
3139                                 footvel = 0;
3140                                 if (skeleton.free) {
3141                                     footpoint = (victim->jointPos(abdomen) + victim->jointPos(neck)) / 2 * victim->scale + victim->coords;
3142                                 } else {
3143                                     footpoint = DoRotation((victim->jointPos(abdomen) + victim->jointPos(neck)) / 2, 0, victim->yaw, 0) * victim->scale + victim->coords;
3144                                 }
3145                                 if (bloodtoggle) {
3146                                     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3147                                 }
3148                                 footvel = DoRotation(facing, 0, 90, 0) * .8;
3149                                 footvel.y -= .3;
3150                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3151                                 Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3152                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3153                                 Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3154                             }
3155                         } else {
3156                             if (victim->weaponactive != -1) {
3157                                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
3158                                     if (weapons[victim->weaponids[0]].getType() == staff) {
3159                                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
3160                                     }
3161                                     if (weapons[weaponids[0]].getType() == staff) {
3162                                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
3163                                     }
3164
3165                                     emit_sound_at(swordstaffsound, victim->coords);
3166                                 } else {
3167                                     emit_sound_at(metalhitsound, victim->coords);
3168                                 }
3169                             }
3170
3171                             XYZ aim;
3172                             victim->Puff(righthand);
3173                             victim->target = 0;
3174                             victim->frameTarget = 0;
3175                             victim->animTarget = staggerbackhighanim;
3176                             victim->targetyaw = targetyaw + 180;
3177                             victim->target = 0;
3178                             aim = DoRotation(facing, 0, 90, 0) * 21;
3179                             aim.y += 7;
3180                             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
3181                             victim->num_weapons--;
3182                             if (victim->num_weapons) {
3183                                 victim->weaponids[0] = victim->weaponids[num_weapons];
3184                                 if (victim->weaponstuck == victim->num_weapons) {
3185                                     victim->weaponstuck = 0;
3186                                 }
3187                             }
3188                             victim->weaponactive = -1;
3189                             for (unsigned i = 0; i < Person::players.size(); i++) {
3190                                 Person::players[i]->wentforweapon = 0;
3191                             }
3192                         }
3193                     }
3194                 }
3195
3196                 if (animCurrent == staffhitanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
3197                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
3198                         if (!Tutorial::active) {
3199                             weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 250;
3200                             escapednum = 0;
3201                             if (id == 0) {
3202                                 camerashake += .4;
3203                             }
3204                             if (Random() % 2 || PersonType::types[creature].hasClaws) {
3205                                 victim->spurt = 1;
3206                             }
3207                             emit_sound_at(staffheadsound, victim->coords);
3208                         }
3209                         victim->RagDoll(0);
3210                         XYZ relative;
3211                         relative = victim->coords - coords;
3212                         relative.y = 0;
3213                         Normalise(&relative);
3214                         relative = DoRotation(relative, 0, 90, 0);
3215                         relative.y -= 1;
3216                         Normalise(&relative);
3217                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3218                             victim->skeleton.joints[i].velocity += relative * damagemult * 60;
3219                         }
3220                         victim->jointVel(head) += relative * damagemult * 230;
3221                         victim->jointVel(neck) += relative * damagemult * 230;
3222                         victim->Puff(head);
3223                         if (!Tutorial::active) {
3224                             victim->DoDamage(damagemult * 120 / victim->protectionhigh);
3225
3226                             award_bonus(id, solidhit, 30);
3227                         }
3228                     }
3229                 }
3230
3231                 if (animCurrent == staffspinhitanim && currentFrame().label == 5 && victim->animTarget != rollanim) {
3232                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5 && victim->animTarget != dodgebackanim && victim->animTarget != sweepanim) {
3233                         if (!Tutorial::active) {
3234                             weapons[weaponids[0]].damage += .6 + float(abs(Random() % 100) - 50) / 250;
3235                             escapednum = 0;
3236                             if (id == 0) {
3237                                 camerashake += .4;
3238                             }
3239                             if (Random() % 2 || PersonType::types[creature].hasClaws) {
3240                                 victim->spurt = 1;
3241                             }
3242                             emit_sound_at(staffheadsound, victim->coords);
3243                         }
3244                         victim->RagDoll(0);
3245                         XYZ relative;
3246                         relative = victim->coords - coords;
3247                         relative.y = 0;
3248                         Normalise(&relative);
3249                         relative = DoRotation(relative, 0, -90, 0);
3250                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3251                             victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3252                         }
3253                         victim->jointVel(head) += relative * damagemult * 220;
3254                         victim->jointVel(neck) += relative * damagemult * 220;
3255                         victim->Puff(head);
3256                         if (!Tutorial::active) {
3257                             victim->DoDamage(damagemult * 350 / victim->protectionhead);
3258
3259                             award_bonus(id, solidhit, 60);
3260                         }
3261                     }
3262                 }
3263
3264                 if (animCurrent == staffgroundsmashanim && currentFrame().label == 5) {
3265                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 6.5) {
3266                         escapednum = 0;
3267                         if (!Tutorial::active) {
3268                             if (!victim->dead) {
3269                                 weapons[weaponids[0]].damage += .4 + float(abs(Random() % 100) - 50) / 500;
3270                             }
3271                             if (id == 0) {
3272                                 camerashake += .4;
3273                             }
3274                             if (Random() % 2 || PersonType::types[creature].hasClaws) {
3275                                 victim->spurt = 1;
3276                             }
3277                             emit_sound_at(staffbodysound, victim->coords);
3278                         }
3279                         victim->skeleton.longdead = 0;
3280                         victim->skeleton.free = 1;
3281                         victim->skeleton.broken = 0;
3282
3283                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3284                             victim->skeleton.joints[i].velchange = 0;
3285                             victim->skeleton.joints[i].locked = 0;
3286                             //victim->skeleton.joints[i].velocity=0;
3287                         }
3288
3289                         victim->RagDoll(0);
3290                         XYZ relative;
3291                         relative = 0;
3292                         relative.y = -1;
3293                         Normalise(&relative);
3294                         if (!victim->dead) {
3295                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3296                                 victim->skeleton.joints[i].velocity = relative * damagemult * 40;
3297                             }
3298                             victim->jointVel(abdomen) += relative * damagemult * 40;
3299                         }
3300                         if (victim->dead) {
3301                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3302                                 victim->skeleton.joints[i].velocity = relative * damagemult * abs(Random() % 20);
3303                             }
3304                         }
3305                         victim->Puff(abdomen);
3306                         if (!Tutorial::active) {
3307                             victim->DoDamage(damagemult * 100 / victim->protectionhigh);
3308
3309                             if (!victim->dead) {
3310                                 award_bonus(id, solidhit, 40);
3311                             }
3312                         }
3313                     }
3314                 }
3315
3316                 if (animCurrent == lowkickanim && currentFrame().label == 5) {
3317                     if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3 && Animation::animations[victim->animTarget].height != highheight) {
3318                         escapednum = 0;
3319                         if (id == 0) {
3320                             camerashake += .4;
3321                         }
3322                         XYZ relative;
3323                         relative = victim->coords - coords;
3324                         relative.y = 0;
3325                         Normalise(&relative);
3326
3327                         SolidHitBonus(id);
3328
3329                         if (Animation::animations[victim->animTarget].height == lowheight) {
3330                             if (Random() % 2) {
3331                                 victim->spurt = 1;
3332                                 DoBlood(.2, 250);
3333                             }
3334                             victim->RagDoll(0);
3335                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3336                                 victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3337                             }
3338                             victim->jointVel(head) += relative * damagemult * 200;
3339                             if (!Tutorial::active) {
3340                                 emit_sound_at(heavyimpactsound, victim->coords, 128.);
3341                             }
3342                             victim->Puff(head);
3343                             victim->DoDamage(damagemult * 100 / victim->protectionhead);
3344                             if (victim->howactive == typesleeping) {
3345                                 victim->DoDamage(damagemult * 150 / victim->protectionhead);
3346                             }
3347                             if (PersonType::types[creature].hasClaws) {
3348                                 emit_sound_at(clawslicesound, victim->coords, 128.);
3349                                 victim->spurt = 1;
3350                                 victim->DoBloodBig(2 / victim->armorhead, 175);
3351                             }
3352                         } else {
3353                             if (victim->damage >= victim->damagetolerance) {
3354                                 victim->RagDoll(0);
3355                             }
3356                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3357                                 victim->skeleton.joints[i].velocity += relative * damagemult * 10;
3358                             }
3359                             victim->jointVel(abdomen) += relative * damagemult * 200;
3360                             victim->frameTarget = 0;
3361                             victim->animTarget = staggerbackhighanim;
3362                             victim->targetyaw = targetyaw + 180;
3363                             victim->target = 0;
3364                             if (!Tutorial::active) {
3365                                 emit_sound_at(landsound2, victim->coords, 128.);
3366                             }
3367                             victim->Puff(abdomen);
3368                             victim->DoDamage(damagemult * 30 / victim->protectionhigh);
3369                             if (PersonType::types[creature].hasClaws) {
3370                                 emit_sound_at(clawslicesound, victim->coords, 128.);
3371                                 victim->spurt = 1;
3372                                 victim->DoBloodBig(2 / victim->armorhigh, 170);
3373                             }
3374                         }
3375                     }
3376                 }
3377
3378                 if (animCurrent == sweepanim && currentFrame().label == 5) {
3379                     if ((victim->animTarget != jumpupanim) &&
3380                         (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 3) &&
3381                         (victim != this->shared_from_this())) {
3382                         escapednum = 0;
3383                         if (id == 0) {
3384                             camerashake += .2;
3385                         }
3386                         if (!Tutorial::active) {
3387                             emit_sound_at(landsound2, victim->coords, 128.);
3388                         }
3389                         XYZ relative;
3390                         relative = victim->coords - coords;
3391                         relative.y = 0;
3392                         Normalise(&relative);
3393
3394                         if (Animation::animations[victim->animTarget].height == middleheight || Animation::animations[victim->animCurrent].height == middleheight || victim->damage >= victim->damagetolerance - 40) {
3395                             victim->RagDoll(0);
3396
3397                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3398                                 victim->skeleton.joints[i].velocity += relative * damagemult * 15;
3399                             }
3400                             relative = DoRotation(relative, 0, -90, 0);
3401                             relative.y += .1;
3402                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3403                                 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) {
3404                                     victim->skeleton.joints[i].velocity = relative * 80;
3405                                 }
3406                             }
3407                             victim->Puff(rightankle);
3408                             victim->Puff(leftankle);
3409                             victim->DoDamage(damagemult * 40 / victim->protectionlow);
3410                         } else {
3411                             if (victim->damage >= victim->damagetolerance) {
3412                                 victim->RagDoll(0);
3413                             }
3414                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3415                                 victim->skeleton.joints[i].velocity += relative * damagemult * 10;
3416                             }
3417                             relative = DoRotation(relative, 0, -90, 0);
3418                             for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3419                                 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) {
3420                                     victim->skeleton.joints[i].velocity += relative * damagemult * 80;
3421                                 }
3422                             }
3423                             victim->jointVel(abdomen) += relative * damagemult * 200;
3424                             victim->frameTarget = 0;
3425                             victim->animTarget = staggerbackhighanim;
3426                             victim->targetyaw = targetyaw + 180;
3427                             victim->target = 0;
3428                             if (!Tutorial::active) {
3429                                 emit_sound_at(landsound2, victim->coords, 128.);
3430                             }
3431                             victim->Puff(abdomen);
3432                             victim->DoDamage(damagemult * 30 / victim->protectionlow);
3433                         }
3434
3435                         SolidHitBonus(id);
3436                     }
3437                 }
3438             }
3439             if (Animation::animations[animTarget].attack == reversal && (!victim->feint || (victim->lastattack == victim->lastattack2 && victim->lastattack2 == victim->lastattack3 && Random() % 2) || animTarget == knifefollowanim)) {
3440                 if (animCurrent == spinkickreversalanim && currentFrame().label == 7) {
3441                     escapednum = 0;
3442                     if (id == 0) {
3443                         camerashake += .4;
3444                     }
3445                     if (Random() % 2) {
3446                         victim->spurt = 1;
3447                         DoBlood(.2, 230);
3448                     }
3449                     if (!Tutorial::active) {
3450                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
3451                     }
3452                     if (PersonType::types[creature].hasClaws) {
3453                         emit_sound_at(clawslicesound, victim->coords, 128);
3454                         victim->spurt = 1;
3455                         victim->DoBloodBig(2 / victim->armorhigh, 170);
3456                     }
3457                     victim->RagDoll(0);
3458                     XYZ relative;
3459                     relative = victim->coords - oldcoords;
3460                     relative.y = 0;
3461                     Normalise(&relative);
3462                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3463                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3464                     }
3465                     victim->jointVel(abdomen) += relative * damagemult * 200;
3466                     victim->Puff(abdomen);
3467                     victim->DoDamage(damagemult * 150 / victim->protectionhigh);
3468
3469                     award_bonus(id, Reversal);
3470                 }
3471
3472                 if ((animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim) && Animation::animations[animTarget].frames[frameCurrent].label == 5) {
3473                     if (victim->weaponactive != -1 && victim->num_weapons > 0) {
3474                         if (weapons[victim->weaponids[victim->weaponactive]].owner == int(victim->id)) {
3475                             takeWeapon(victim->weaponids[victim->weaponactive]);
3476                             victim->num_weapons--;
3477                             if (victim->num_weapons > 0) {
3478                                 victim->weaponids[victim->weaponactive] = victim->weaponids[victim->num_weapons];
3479                             }
3480                             victim->weaponactive = -1;
3481                         }
3482                     }
3483                 }
3484
3485                 if (animCurrent == staffhitreversalanim && currentFrame().label == 5) {
3486                     escapednum = 0;
3487                     if (id == 0) {
3488                         camerashake += .4;
3489                     }
3490                     if (Random() % 2) {
3491                         victim->spurt = 1;
3492                         DoBlood(.2, 230);
3493                     }
3494                     emit_sound_at(whooshhitsound, victim->coords, 128.);
3495                     victim->RagDoll(0);
3496                     XYZ relative;
3497                     relative = victim->coords - oldcoords;
3498                     relative.y = 0;
3499                     Normalise(&relative);
3500                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3501                         victim->skeleton.joints[i].velocity += relative * damagemult * 30;
3502                     }
3503                     victim->jointVel(abdomen) += relative * damagemult * 200;
3504                     victim->Puff(head);
3505                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
3506                 }
3507
3508                 if (animCurrent == staffspinhitreversalanim && currentFrame().label == 7) {
3509                     escapednum = 0;
3510                     if (id == 0) {
3511                         camerashake += .4;
3512                     }
3513                     if (Random() % 2) {
3514                         victim->spurt = 1;
3515                         DoBlood(.2, 230);
3516                     }
3517
3518                     award_bonus(id, staffreversebonus);
3519
3520                     if (!Tutorial::active) {
3521                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
3522                     }
3523                     victim->RagDoll(0);
3524                     award_bonus(id, staffreversebonus); // Huh, again?
3525
3526                     XYZ relative;
3527                     relative = victim->coords - oldcoords;
3528                     relative.y = 0;
3529                     Normalise(&relative);
3530                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3531                         victim->skeleton.joints[i].velocity += relative * damagemult * 30;
3532                     }
3533                     victim->jointVel(abdomen) += relative * damagemult * 200;
3534                     victim->Puff(head);
3535                     victim->DoDamage(damagemult * 70 / victim->protectionhigh);
3536                 }
3537
3538                 if (animCurrent == upunchreversalanim && currentFrame().label == 7) {
3539                     escapednum = 0;
3540                     victim->RagDoll(1);
3541                     XYZ relative;
3542                     relative = facing;
3543                     relative.y = 0;
3544                     Normalise(&relative);
3545                     relative.y -= .1;
3546                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3547                         victim->skeleton.joints[i].velocity += relative * damagemult * 70;
3548                     }
3549                     victim->jointVel(lefthand) *= .1;
3550                     victim->jointVel(leftwrist) *= .2;
3551                     victim->jointVel(leftelbow) *= .5;
3552                     victim->jointVel(leftshoulder) *= .7;
3553                     victim->jointVel(righthand) *= .1;
3554                     victim->jointVel(rightwrist) *= .2;
3555                     victim->jointVel(rightelbow) *= .5;
3556                     victim->jointVel(rightshoulder) *= .7;
3557
3558                     victim->Puff(abdomen);
3559                     victim->DoDamage(damagemult * 90 / victim->protectionhigh);
3560
3561                     award_bonus(id, Reversal);
3562
3563                     bool doslice;
3564                     if (weaponactive == -1) {
3565                         doslice = PersonType::types[creature].hasClaws;
3566                     } else {
3567                         doslice = (weapons[weaponids[0]].getType() != staff);
3568                     }
3569                     if (doslice) {
3570                         if (weaponactive == -1) {
3571                             emit_sound_at(clawslicesound, victim->coords, 128.);
3572                             victim->spurt = 1;
3573                             victim->DoBloodBig(2 / victim->armorhigh, 175);
3574                         } else {
3575                             victim->DoBloodBig(2 / victim->armorhigh, 225);
3576                             emit_sound_at(knifeslicesound, victim->coords);
3577                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
3578                                 weapons[weaponids[weaponactive]].bloody = 1;
3579                             }
3580                             weapons[weaponids[weaponactive]].blooddrip += 3;
3581                         }
3582                     }
3583                 }
3584
3585                 if (animCurrent == swordslashreversalanim && currentFrame().label == 7) {
3586                     escapednum = 0;
3587                     victim->RagDoll(1);
3588                     XYZ relative;
3589                     relative = facing;
3590                     relative.y = 0;
3591                     Normalise(&relative);
3592                     relative.y -= .1;
3593                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3594                         victim->skeleton.joints[i].velocity += relative * damagemult * 70;
3595                     }
3596                     victim->jointVel(lefthand) *= .1 - 1;
3597                     victim->jointVel(leftwrist) *= .2 - 1;
3598                     victim->jointVel(leftelbow) *= .5 - 1;
3599                     victim->jointVel(leftshoulder) *= .7 - 1;
3600                     victim->jointVel(righthand) *= .1 - 1;
3601                     victim->jointVel(rightwrist) *= .2 - 1;
3602                     victim->jointVel(rightelbow) *= .5 - 1;
3603                     victim->jointVel(rightshoulder) *= .7 - 1;
3604
3605                     award_bonus(id, swordreversebonus);
3606                 }
3607
3608                 if (hasvictim && animCurrent == knifeslashreversalanim && currentFrame().label == 7) {
3609                     escapednum = 0;
3610                     if (id == 0) {
3611                         camerashake += .4;
3612                     }
3613                     if (Random() % 2) {
3614                         victim->spurt = 1;
3615                         DoBlood(.2, 230);
3616                     }
3617                     if (!Tutorial::active) {
3618                         emit_sound_at(heavyimpactsound, victim->coords, 128.);
3619                     }
3620                     victim->RagDoll(0);
3621                     XYZ relative;
3622                     relative = victim->coords - oldcoords;
3623                     relative.y = 0;
3624                     Normalise(&relative);
3625                     relative = DoRotation(relative, 0, -90, 0);
3626                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3627                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3628                     }
3629                     victim->jointVel(abdomen) += relative * damagemult * 200;
3630                     victim->Puff(abdomen);
3631                     victim->DoDamage(damagemult * 30 / victim->protectionhigh);
3632
3633                     award_bonus(id, Reversal);
3634                 }
3635
3636                 if (hasvictim && animCurrent == sneakattackanim && currentFrame().label == 7) {
3637                     escapednum = 0;
3638                     victim->RagDoll(0);
3639                     victim->skeleton.spinny = 0;
3640                     XYZ relative;
3641                     relative = facing * -1;
3642                     relative.y = -3;
3643                     Normalise(&relative);
3644                     if (victim->id == 0) {
3645                         relative /= 30;
3646                     }
3647                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3648                         victim->skeleton.joints[i].velocity += relative * damagemult * 40;
3649                     }
3650                     victim->damage = victim->damagetolerance;
3651                     victim->permanentdamage = victim->damagetolerance - 1;
3652                     bool doslice;
3653                     if (weaponactive == -1) {
3654                         doslice = PersonType::types[creature].hasClaws;
3655                     } else {
3656                         doslice = (weapons[weaponids[0]].getType() != staff);
3657                     }
3658                     if (doslice) {
3659                         if (weaponactive == -1) {
3660                             emit_sound_at(clawslicesound, victim->coords, 128.);
3661                             victim->spurt = 1;
3662                             victim->DoBloodBig(2, 175);
3663                         } else {
3664                             victim->DoBloodBig(200, 225);
3665                             emit_sound_at(knifeslicesound, victim->coords);
3666                             if (bloodtoggle) {
3667                                 weapons[weaponids[weaponactive]].bloody = 2;
3668                             }
3669                             weapons[weaponids[weaponactive]].blooddrip += 5;
3670                         }
3671                     }
3672                     award_bonus(id, spinecrusher);
3673                 }
3674
3675                 if (hasvictim && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().label == 5) {
3676                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
3677                         escapednum = 0;
3678                         if (animTarget == knifefollowanim) {
3679                             victim->DoBloodBig(200, 210);
3680                         }
3681                         if (animTarget == knifesneakattackanim) {
3682                             XYZ footvel, footpoint;
3683                             footvel = 0;
3684                             footpoint = weapons[weaponids[0]].tippoint;
3685                             if (bloodtoggle) {
3686                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3687                             }
3688                             footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
3689                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3690                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3691                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3692                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3693                             victim->DoBloodBig(200, 195);
3694                             award_bonus(id, tracheotomy);
3695                         }
3696                         if (animTarget == knifefollowanim) {
3697                             award_bonus(id, Stabbonus);
3698                             XYZ footvel, footpoint;
3699                             footvel = 0;
3700                             footpoint = weapons[weaponids[0]].tippoint;
3701                             if (bloodtoggle) {
3702                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3703                             }
3704                             footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3705                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3706                             Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3707                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .2, 1);
3708                             Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .2, 1);
3709                         }
3710                         victim->bloodloss += 10000;
3711                         victim->velocity = 0;
3712                         emit_sound_at(fleshstabsound, victim->coords);
3713                         if (bloodtoggle) {
3714                             weapons[weaponids[weaponactive]].bloody = 2;
3715                         }
3716                         weapons[weaponids[weaponactive]].blooddrip += 5;
3717                     }
3718                 }
3719
3720                 if (hasvictim && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().label == 6) {
3721                     escapednum = 0;
3722                     victim->velocity = 0;
3723                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3724                         victim->skeleton.joints[i].velocity = 0;
3725                     }
3726                     if (animTarget == knifefollowanim) {
3727                         victim->RagDoll(0);
3728                         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3729                             victim->skeleton.joints[i].velocity = 0;
3730                         }
3731                     }
3732                     if (weaponactive != -1 && Animation::animations[victim->animTarget].attack != reversal) {
3733                         emit_sound_at(fleshstabremovesound, victim->coords);
3734                         if (bloodtoggle) {
3735                             weapons[weaponids[weaponactive]].bloody = 2;
3736                         }
3737                         weapons[weaponids[weaponactive]].blooddrip += 5;
3738
3739                         XYZ footvel, footpoint;
3740                         footvel = 0;
3741                         footpoint = weapons[weaponids[0]].tippoint;
3742                         if (bloodtoggle) {
3743                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3744                         }
3745                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3746                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3747                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3748                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3749                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3750                     }
3751                 }
3752
3753                 if (hasvictim && (animCurrent == swordsneakattackanim) && currentFrame().label == 5) {
3754                     if (weaponactive != -1 && victim->bloodloss < victim->damagetolerance) {
3755                         award_bonus(id, backstab);
3756
3757                         escapednum = 0;
3758
3759                         XYZ footvel, footpoint;
3760                         footvel = 0;
3761                         footpoint = (weapons[weaponids[0]].tippoint + weapons[weaponids[0]].position) / 2;
3762                         if (bloodtoggle) {
3763                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3764                         }
3765                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position);
3766                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3767                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3768                         Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 5, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
3769                         Sprite::MakeSprite(bloodflamesprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .3, 1);
3770                         victim->DoBloodBig(200, 180);
3771                         victim->DoBloodBig(200, 215);
3772                         victim->bloodloss += 10000;
3773                         victim->velocity = 0;
3774                         emit_sound_at(fleshstabsound, victim->coords);
3775                         if (bloodtoggle) {
3776                             weapons[weaponids[weaponactive]].bloody = 2;
3777                         }
3778                         weapons[weaponids[weaponactive]].blooddrip += 5;
3779                     }
3780                 }
3781
3782                 if (hasvictim && animCurrent == swordsneakattackanim && currentFrame().label == 6) {
3783                     escapednum = 0;
3784                     victim->velocity = 0;
3785                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3786                         victim->skeleton.joints[i].velocity = 0;
3787                     }
3788                     if (weaponactive != -1) {
3789                         emit_sound_at(fleshstabremovesound, victim->coords);
3790                         if (bloodtoggle) {
3791                             weapons[weaponids[weaponactive]].bloody = 2;
3792                         }
3793                         weapons[weaponids[weaponactive]].blooddrip += 5;
3794
3795                         XYZ footvel, footpoint;
3796                         footvel = 0;
3797                         footpoint = weapons[weaponids[0]].tippoint;
3798                         if (bloodtoggle) {
3799                             Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .9, .3);
3800                         }
3801                         footvel = (weapons[weaponids[0]].tippoint - weapons[weaponids[0]].position) * -1;
3802                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 7, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3803                         Sprite::MakeSprite(bloodsprite, footpoint, DoRotation(footvel * 3, (float)(Random() % 20), (float)(Random() % 20), 0), 1, 1, 1, .05, .9);
3804                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 5, 1, 1, 1, .3, 1);
3805                         Sprite::MakeSprite(bloodflamesprite, footpoint, footvel * 2, 1, 1, 1, .3, 1);
3806                     }
3807                 }
3808
3809                 if (animCurrent == sweepreversalanim && currentFrame().label == 7) {
3810                     escapednum = 0;
3811                     if (id == 0) {
3812                         camerashake += .4;
3813                     }
3814                     if (Random() % 2) {
3815                         victim->spurt = 1;
3816                         DoBlood(.2, 240);
3817                     }
3818                     if (weaponactive == -1) {
3819                         if (!Tutorial::active) {
3820                             emit_sound_at(heavyimpactsound, victim->coords, 128.);
3821                         }
3822                     }
3823                     bool doslice;
3824                     if (weaponactive == -1) {
3825                         doslice = PersonType::types[creature].hasClaws;
3826                     } else {
3827                         doslice = (weapons[weaponids[0]].getType() != staff);
3828                     }
3829                     if (doslice) {
3830                         if (weaponactive == -1) {
3831                             emit_sound_at(clawslicesound, victim->coords, 128.);
3832                             victim->spurt = 1;
3833                             victim->DoBloodBig(2 / victim->armorhead, 175);
3834                         } else {
3835                             victim->DoBloodBig(2 / victim->armorhead, 225);
3836                             emit_sound_at(knifeslicesound, victim->coords);
3837                             if (bloodtoggle && !weapons[weaponids[weaponactive]].bloody) {
3838                                 weapons[weaponids[weaponactive]].bloody = 1;
3839                             }
3840                             weapons[weaponids[weaponactive]].blooddrip += 3;
3841                         }
3842                     }
3843
3844                     award_bonus(id, Reversal);
3845
3846                     victim->Puff(neck);
3847
3848                     XYZ relative;
3849                     relative = facing * -1;
3850                     relative.y = 0;
3851                     Normalise(&relative);
3852                     relative = DoRotation(relative, 0, 90, 0);
3853                     relative.y = .5;
3854                     Normalise(&relative);
3855                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3856                         victim->skeleton.joints[i].velocity += relative * damagemult * 20;
3857                     }
3858                     victim->jointVel(head) += relative * damagemult * 200;
3859                     if (victim->damage < victim->damagetolerance - 100) {
3860                         victim->velocity = relative * 200;
3861                     }
3862                     victim->DoDamage(damagemult * 100 / victim->protectionhead);
3863                     victim->velocity = 0;
3864                 }
3865
3866                 if (animCurrent == sweepreversalanim && ((currentFrame().label == 9 && victim->damage < victim->damagetolerance) || (currentFrame().label == 7 && victim->damage > victim->damagetolerance))) {
3867                     escapednum = 0;
3868                     victim->RagDoll(0);
3869                     XYZ relative;
3870                     relative = facing * -1;
3871                     relative.y = 0;
3872                     Normalise(&relative);
3873                     relative = DoRotation(relative, 0, 90, 0);
3874                     relative.y = .5;
3875                     Normalise(&relative);
3876                     for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
3877                         victim->skeleton.joints[i].velocity += relative * damagemult * 20;
3878                     }
3879                     victim->jointVel(head) += relative * damagemult * 200;
3880                 }
3881
3882                 if (hasvictim && (animTarget == spinkickreversalanim || animTarget == sweepreversalanim || animTarget == rabbitkickreversalanim || animTarget == upunchreversalanim || animTarget == jumpreversalanim || animTarget == swordslashreversalanim || animTarget == knifeslashreversalanim || animTarget == rabbittacklereversal || animTarget == wolftacklereversal || animTarget == staffhitreversalanim || animTarget == staffspinhitreversalanim)) {
3883                     if (victim->damage > victim->damagetolerance && bonus != reverseko) {
3884                         award_bonus(id, reverseko);
3885                     }
3886                 }
3887             }
3888
3889             //Animation end
3890             if (frameTarget >= int(Animation::animations[animCurrent].frames.size())) {
3891                 frameTarget = 0;
3892                 if (wasStop()) {
3893                     animTarget = getIdle();
3894                     FootLand(leftfoot, 1);
3895                     FootLand(rightfoot, 1);
3896                 }
3897                 if (animCurrent == rabbittackleanim || animCurrent == rabbittacklinganim) {
3898                     animTarget = rollanim;
3899                     frameTarget = 3;
3900                     emit_sound_at(movewhooshsound, coords, 128.);
3901                 }
3902                 if (animCurrent == staggerbackhighanim) {
3903                     animTarget = getIdle();
3904                 }
3905                 if (animCurrent == staggerbackhardanim) {
3906                     animTarget = getIdle();
3907                 }
3908                 if (animCurrent == removeknifeanim) {
3909                     animTarget = getIdle();
3910                 }
3911                 if (animCurrent == crouchremoveknifeanim) {
3912                     animTarget = getCrouch();
3913                 }
3914                 if (animCurrent == backhandspringanim) {
3915                     animTarget = getIdle();
3916                 }
3917                 if (animCurrent == dodgebackanim) {
3918                     animTarget = getIdle();
3919                 }
3920                 if (animCurrent == drawleftanim) {
3921                     animTarget = getIdle();
3922                 }
3923                 if (animCurrent == drawrightanim || animCurrent == crouchdrawrightanim) {
3924                     animTarget = getIdle();
3925                     if (animCurrent == crouchdrawrightanim) {
3926                         animTarget = getCrouch();
3927                     }
3928                     if (weaponactive == -1) {
3929                         weaponactive = 0;
3930                     } else if (weaponactive == 0) {
3931                         weaponactive = -1;
3932                         if (num_weapons == 2) {
3933                             int buffer;
3934                             buffer = weaponids[0];
3935                             weaponids[0] = weaponids[1];
3936                             weaponids[1] = buffer;
3937                         }
3938                     }
3939
3940                     if (weaponactive == -1) {
3941                         emit_sound_at(knifesheathesound, coords, 128.);
3942                     }
3943                     if (weaponactive != -1) {
3944                         emit_sound_at(knifedrawsound, coords, 128.);
3945                     }
3946                 }
3947                 if (animCurrent == rollanim) {
3948                     animTarget = getCrouch();
3949                     FootLand(leftfoot, 1);
3950                     FootLand(rightfoot, 1);
3951                 }
3952                 if (isFlip()) {
3953                     if (animTarget == walljumprightkickanim) {
3954                         targetrot = -190;
3955                     }
3956                     if (animTarget == walljumpleftkickanim) {
3957                         targetrot = 190;
3958                     }
3959                     animTarget = jumpdownanim;
3960                 }
3961                 if (animCurrent == climbanim) {
3962                     animTarget = getCrouch();
3963                     frameTarget = 1;
3964                     coords += facing * .1;
3965                     if (!isnormal(coords.x)) {
3966                         coords = oldcoords;
3967                     }
3968                     oldcoords = coords;
3969                     targetoffset = 0;
3970                     currentoffset = 0;
3971                     grabdelay = 1;
3972                     velocity = 0;
3973                     collided = 0;
3974                     avoidcollided = 0;
3975                 }
3976                 if (animTarget == rabbitkickreversalanim) {
3977                     animTarget = getCrouch();
3978                     lastfeint = 0;
3979                 }
3980                 if (animTarget == jumpreversalanim) {
3981                     animTarget = getCrouch();
3982                     lastfeint = 0;
3983                 }
3984                 if (animTarget == walljumprightanim || animTarget == walljumpbackanim || animTarget == walljumpfrontanim) {
3985                     if (attackkeydown && animTarget != walljumpfrontanim) {
3986                         int closest = -1;
3987                         float closestdist = -1;
3988                         float distance;
3989                         if (Person::players.size() > 1) {
3990                             for (unsigned i = 0; i < Person::players.size(); i++) {
3991                                 if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
3992                                     distance = distsq(&Person::players[i]->coords, &coords);
3993                                     if (closestdist == -1 || distance < closestdist) {
3994                                         closestdist = distance;
3995                                         closest = i;
3996                                     }
3997                                 }
3998                             }
3999                         }
4000                         if (closestdist > 0 && closest >= 0 && closestdist < 16) {
4001                             victim = Person::players[closest];
4002                             animTarget = walljumprightkickanim;
4003                             frameTarget = 0;
4004                             XYZ rotatetarget = victim->coords - coords;
4005                             Normalise(&rotatetarget);
4006                             yaw = -asin(0 - rotatetarget.x);
4007                             yaw *= 360 / 6.28;
4008                             if (rotatetarget.z < 0) {
4009                                 yaw = 180 - yaw;
4010                             }
4011                             targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
4012                             velocity = (victim->coords - coords) * 4;
4013                             velocity.y += 2;
4014                             transspeed = 40;
4015                         }
4016                     }
4017                     if (animTarget == walljumpbackanim) {
4018                         animTarget = backflipanim;
4019                         frameTarget = 3;
4020                         velocity = facing * -8;
4021                         velocity.y = 4;
4022                         if (id == 0) {
4023                             resume_stream(whooshsound);
4024                         }
4025                     }
4026                     if (animTarget == walljumprightanim) {
4027                         animTarget = rightflipanim;
4028                         frameTarget = 4;
4029                         targetyaw -= 90;
4030                         yaw -= 90;
4031                         velocity = DoRotation(facing, 0, 30, 0) * -8;
4032                         velocity.y = 4;
4033                     }
4034                     if (animTarget == walljumpfrontanim) {
4035                         animTarget = frontflipanim;
4036                         frameTarget = 2;
4037                         //targetyaw-=180;
4038                         ////yaw-=180;
4039                         velocity = facing * 8;
4040                         velocity.y = 4;
4041                     }
4042                     if (id == 0) {
4043                         resume_stream(whooshsound);
4044                     }
4045                 }
4046                 if (animTarget == walljumpleftanim) {
4047                     if (attackkeydown) {
4048                         int closest = -1;
4049                         float closestdist = -1;
4050                         float distance;
4051                         if (Person::players.size() > 1) {
4052                             for (unsigned i = 0; i < Person::players.size(); i++) {
4053                                 if (id != i && Person::players[i]->coords.y < coords.y && !Person::players[i]->skeleton.free) {
4054                                     distance = distsq(&Person::players[i]->coords, &coords);
4055                                     if (closestdist == -1 || distance < closestdist) {
4056                                         closestdist = distance;
4057                                         closest = i;
4058                                     }
4059                                 }
4060                             }
4061                         }
4062                         if (closestdist > 0 && closest >= 0 && closestdist < 16) {
4063                             victim = Person::players[closest];
4064                             animTarget = walljumpleftkickanim;
4065                             frameTarget = 0;
4066                             XYZ rotatetarget = victim->coords - coords;
4067                             Normalise(&rotatetarget);
4068                             yaw = -asin(0 - rotatetarget.x);
4069                             yaw *= 360 / 6.28;
4070                             if (rotatetarget.z < 0) {
4071                                 yaw = 180 - yaw;
4072                             }
4073                             targettilt2 = -asin(rotatetarget.y) * 360 / 6.28;
4074                             velocity = (victim->coords - coords) * 4;
4075                             velocity.y += 2;
4076                             transspeed = 40;
4077                         }
4078                     }
4079                     if (animTarget != walljumpleftkickanim) {
4080                         animTarget = leftflipanim;
4081                         frameTarget = 4;
4082                         targetyaw += 90;
4083                         yaw += 90;
4084                         velocity = DoRotation(facing, 0, -30, 0) * -8;
4085                         velocity.y = 4;
4086                     }
4087                     if (id == 0) {
4088                         resume_stream(whooshsound);
4089                     }
4090                 }
4091                 if (animTarget == sneakattackanim) {
4092                     animCurrent = getCrouch();
4093                     animTarget = getCrouch();
4094                     frameTarget = 1;
4095                     frameCurrent = 0;
4096                     targetyaw += 180;
4097                     yaw += 180;
4098                     targettilt2 *= -1;
4099                     tilt2 *= -1;
4100                     transspeed = 1000000;
4101                     targetheadyaw += 180;
4102                     coords -= facing * .7;
4103                     if (onterrain) {
4104                         coords.y = terrain.getHeight(coords.x, coords.z);
4105                     }
4106
4107                     lastfeint = 0;
4108                 }
4109                 if (animTarget == knifesneakattackanim || animTarget == swordsneakattackanim) {
4110                     animTarget = getIdle();
4111                     frameTarget = 0;
4112                     if (onterrain) {
4113                         coords.y = terrain.getHeight(coords.x, coords.z);
4114                     }
4115
4116                     lastfeint = 0;
4117                 }
4118                 if (animCurrent == knifefollowanim) {
4119                     animTarget = getIdle();
4120                     lastfeint = 0;
4121                 }
4122                 if (Animation::animations[animTarget].attack == reversal && animCurrent != sneakattackanim && animCurrent != knifesneakattackanim && animCurrent != swordsneakattackanim && animCurrent != knifefollowanim) {
4123                     float ycoords = oldcoords.y;
4124                     animTarget = getStop();
4125                     targetyaw += 180;
4126                     yaw += 180;
4127                     targettilt2 *= -1;
4128                     tilt2 *= -1;
4129                     transspeed = 1000000;
4130                     targetheadyaw += 180;
4131                     if (!isnormal(coords.x)) {
4132                         coords = oldcoords;
4133                     }
4134                     if (animCurrent == spinkickreversalanim || animCurrent == swordslashreversalanim) {
4135                         oldcoords = coords + facing * .5;
4136                     } else if (animCurrent == sweepreversalanim) {
4137                         oldcoords = coords + facing * 1.1;
4138                     } else if (animCurrent == upunchreversalanim) {
4139                         oldcoords = coords + facing * 1.5;
4140                         targetyaw += 180;
4141                         yaw += 180;
4142                         targetheadyaw += 180;
4143                         targettilt2 *= -1;
4144                         tilt2 *= -1;
4145                     } else if (animCurrent == knifeslashreversalanim) {
4146                         oldcoords = coords + facing * .5;
4147                         targetyaw += 90;
4148                         yaw += 90;
4149                         targetheadyaw += 90;
4150                         targettilt2 = 0;
4151                         tilt2 = 0;
4152                     } else if (animCurrent == staffspinhitreversalanim) {
4153                         targetyaw += 180;
4154                         yaw += 180;
4155                         targetheadyaw += 180;
4156                         targettilt2 = 0;
4157                         tilt2 = 0;
4158                     }
4159                     if (onterrain) {
4160                         oldcoords.y = terrain.getHeight(oldcoords.x, oldcoords.z);
4161                     } else {
4162                         oldcoords.y = ycoords;
4163                     }
4164                     currentoffset = coords - oldcoords;
4165                     targetoffset = 0;
4166                     coords = oldcoords;
4167
4168                     lastfeint = 0;
4169                 }
4170                 if (animCurrent == knifesneakattackedanim || animCurrent == swordsneakattackedanim) {
4171                     velocity = 0;
4172                     velocity.y = -5;
4173                     RagDoll(0);
4174                 }
4175                 if (Animation::animations[animTarget].attack == reversed) {
4176                     escapednum++;
4177                     if (animTarget == sweepreversedanim) {
4178                         targetyaw += 90;
4179                     }
4180                     animTarget = backhandspringanim;
4181                     frameTarget = 2;
4182                     emit_sound_at(landsound, coords, 128);
4183
4184                     if (animCurrent == upunchreversedanim || animCurrent == swordslashreversedanim) {
4185                         animTarget = rollanim;
4186                         frameTarget = 5;
4187                         oldcoords = coords;
4188                         coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
4189                         coords.y = oldcoords.y;
4190                     }
4191                     if (animCurrent == knifeslashreversedanim) {
4192                         animTarget = rollanim;
4193                         frameTarget = 0;
4194                         targetyaw += 90;
4195                         yaw += 90;
4196                         oldcoords = coords;
4197                         coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
4198                         coords.y = oldcoords.y;
4199                     }
4200                 }
4201                 if (wasFlip()) {
4202                     animTarget = jumpdownanim;
4203                 }
4204                 if (wasLanding()) {
4205                     animTarget = getIdle();
4206                 }
4207                 if (wasLandhard()) {
4208                     animTarget = getIdle();
4209                 }
4210                 if (animCurrent == spinkickanim || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == lowkickanim) {
4211                     animTarget = getIdle();
4212                     oldcoords = coords;
4213                     coords += (DoRotation(jointPos(leftfoot), 0, yaw, 0) + DoRotation(jointPos(rightfoot), 0, yaw, 0)) / 2 * scale;
4214                     coords.y = oldcoords.y;
4215                     //coords+=DoRotation(Animation::animations[animCurrent].offset,0,yaw,0)*scale;
4216                     targetoffset.y = coords.y;
4217                     if (onterrain) {
4218                         targetoffset.y = terrain.getHeight(coords.x, coords.z);
4219                     }
4220                     currentoffset = DoRotation(Animation::animations[animCurrent].offset * -1, 0, yaw, 0) * scale;
4221                     currentoffset.y -= (coords.y - targetoffset.y);
4222                     coords.y = targetoffset.y;
4223                     targetoffset = 0;
4224                     normalsupdatedelay = 0;
4225                 }
4226                 if (animCurrent == upunchanim) {
4227                     animTarget = getStop();
4228                     normalsupdatedelay = 0;
4229                     lastfeint = 0;
4230                 }
4231                 if (animCurrent == rabbitkickanim && animTarget != backflipanim) {
4232                     targetyaw = yaw;
4233                     bool hasstaff;
4234                     hasstaff = 0;
4235                     if (num_weapons > 0) {
4236                         if (weapons[0].getType() == staff) {
4237                             hasstaff = 1;
4238                         }
4239                     }
4240                     if (!hasstaff) {
4241                         DoDamage(35);
4242                     }
4243                     RagDoll(0);
4244                     lastfeint = 0;
4245                     rabbitkickragdoll = 1;
4246                 }
4247                 if (animCurrent == rabbitkickreversedanim) {
4248                     if (!feint) {
4249                         velocity = 0;
4250                         velocity.y = -10;
4251                         //DoDamage(100);
4252                         RagDoll(0);
4253                         skeleton.spinny = 0;
4254                         SolidHitBonus(!id); // FIXME: tricky id
4255                     }
4256                     if (feint) {
4257                         escapednum++;
4258                         animTarget = rollanim;
4259                         coords += facing;
4260                         if (id == 0) {
4261                             pause_sound(whooshsound);
4262                         }
4263                     }
4264                     lastfeint = 0;
4265                 }
4266                 if (animCurrent == rabbittackledbackanim || animCurrent == rabbittackledfrontanim) {
4267                     velocity = 0;
4268                     velocity.y = -10;
4269                     RagDoll(0);
4270                     skeleton.spinny = 0;
4271                 }
4272                 if (animCurrent == jumpreversedanim) {
4273                     if (!feint) {
4274                         velocity = 0;
4275                         velocity.y = -10;
4276                         //DoDamage(100);
4277                         RagDoll(0);
4278                         skeleton.spinny = 0;
4279                         SolidHitBonus(!id); // FIXME: tricky id
4280                     }
4281                     if (feint) {
4282                         escapednum++;
4283                         animTarget = rollanim;
4284                         coords += facing * 2;
4285                         if (id == 0) {
4286                             pause_sound(whooshsound);
4287                         }
4288                     }
4289                     lastfeint = 0;
4290                 }
4291
4292                 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) {
4293                     animTarget = getupfromfrontanim;
4294                     lastfeint = 0;
4295                 } else if (Animation::animations[animCurrent].attack == normalattack) {
4296                     animTarget = getIdle();
4297                     lastfeint = 0;
4298                 }
4299                 if (animCurrent == blockhighleftanim && aitype != playercontrolled) {
4300                     animTarget = blockhighleftstrikeanim;
4301                 }
4302                 if (animCurrent == knifeslashstartanim || animCurrent == knifethrowanim || animCurrent == swordslashanim || animCurrent == staffhitanim || animCurrent == staffgroundsmashanim || animCurrent == staffspinhitanim) {
4303                     animTarget = getIdle();
4304                     lastfeint = 0;
4305                 }
4306                 if (animCurrent == spinkickanim && victim->skeleton.free) {
4307                     if (creature == rabbittype) {
4308                         animTarget = fightidleanim;
4309                     }
4310                 }
4311             }
4312             target = 0;
4313
4314             if (isIdle() && !wasIdle()) {
4315                 normalsupdatedelay = 0;
4316             }
4317
4318             if (animCurrent == jumpupanim && velocity.y < 0 && !isFlip()) {
4319                 animTarget = jumpdownanim;
4320             }
4321         }
4322         if (!skeleton.free) {
4323             oldtarget = target;
4324             if (!transspeed && Animation::animations[animTarget].attack != 2 && Animation::animations[animTarget].attack != 3) {
4325                 if (!isRun() || !wasRun()) {
4326                     if (targetFrame().speed > currentFrame().speed) {
4327                         target += multiplier * targetFrame().speed * speed * 2;
4328                     }
4329                     if (targetFrame().speed <= currentFrame().speed) {
4330                         target += multiplier * currentFrame().speed * speed * 2;
4331                     }
4332                 }
4333                 if (isRun() && wasRun()) {
4334                     float tempspeed;
4335                     tempspeed = velspeed;
4336                     if (tempspeed < 10 * speedmult) {
4337                         tempspeed = 10 * speedmult;
4338                     }
4339                     /* FIXME - mixed of target and current here, is that intended? */
4340                     target += multiplier * Animation::animations[animTarget].frames[frameCurrent].speed * speed * 1.7 * tempspeed / (speed * 45 * scale);
4341                 }
4342             } else if (transspeed) {
4343                 target += multiplier * transspeed * speed * 2;
4344             } else {
4345                 if (!isRun() || !wasRun()) {
4346                     if (targetFrame().speed > currentFrame().speed) {
4347                         target += multiplier * targetFrame().speed * 2;
4348                     }
4349                     if (targetFrame().speed <= currentFrame().speed) {
4350                         target += multiplier * currentFrame().speed * 2;
4351                     }
4352                 }
4353             }
4354
4355             if (animCurrent != animTarget) {
4356                 target = (target + oldtarget) / 2;
4357             }
4358
4359             if (target > 1) {
4360                 frameCurrent = frameTarget;
4361                 target = 1;
4362             }
4363
4364             if (frameCurrent >= int(Animation::animations[animCurrent].frames.size())) {
4365                 frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
4366             }
4367
4368             oldrot = rot;
4369             rot = targetrot * target;
4370             yaw += rot - oldrot;
4371             if (target == 1) {
4372                 rot = 0;
4373                 oldrot = 0;
4374                 targetrot = 0;
4375             }
4376
4377             if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
4378                 //Old rotates
4379                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4380                     skeleton.joints[i].position = currentFrame().joints[i].position;
4381                 }
4382
4383                 skeleton.FindForwards();
4384
4385                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4386                     if (skeleton.muscles[i].visible) {
4387                         skeleton.FindRotationMuscle(i, animTarget);
4388                     }
4389                 }
4390                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4391                     if (skeleton.muscles[i].visible) {
4392                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100)) {
4393                             skeleton.muscles[i].oldrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
4394                         }
4395                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100)) {
4396                             skeleton.muscles[i].oldrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
4397                         }
4398                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100)) {
4399                             skeleton.muscles[i].oldrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
4400                         }
4401                     }
4402                 }
4403
4404                 //New rotates
4405                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4406                     skeleton.joints[i].position = targetFrame().joints[i].position;
4407                 }
4408
4409                 skeleton.FindForwards();
4410
4411                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4412                     if (skeleton.muscles[i].visible) {
4413                         skeleton.FindRotationMuscle(i, animTarget);
4414                     }
4415                 }
4416                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4417                     if (skeleton.muscles[i].visible) {
4418                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100)) {
4419                             skeleton.muscles[i].newrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
4420                         }
4421                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100)) {
4422                             skeleton.muscles[i].newrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
4423                         }
4424                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100)) {
4425                             skeleton.muscles[i].newrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
4426                         }
4427                         if (skeleton.muscles[i].newrotate3 > skeleton.muscles[i].oldrotate3 + 180) {
4428                             skeleton.muscles[i].newrotate3 -= 360;
4429                         }
4430                         if (skeleton.muscles[i].newrotate3 < skeleton.muscles[i].oldrotate3 - 180) {
4431                             skeleton.muscles[i].newrotate3 += 360;
4432                         }
4433                         if (skeleton.muscles[i].newrotate2 > skeleton.muscles[i].oldrotate2 + 180) {
4434                             skeleton.muscles[i].newrotate2 -= 360;
4435                         }
4436                         if (skeleton.muscles[i].newrotate2 < skeleton.muscles[i].oldrotate2 - 180) {
4437                             skeleton.muscles[i].newrotate2 += 360;
4438                         }
4439                         if (skeleton.muscles[i].newrotate1 > skeleton.muscles[i].oldrotate1 + 180) {
4440                             skeleton.muscles[i].newrotate1 -= 360;
4441                         }
4442                         if (skeleton.muscles[i].newrotate1 < skeleton.muscles[i].oldrotate1 - 180) {
4443                             skeleton.muscles[i].newrotate1 += 360;
4444                         }
4445                     }
4446                 }
4447             }
4448
4449             oldanimCurrent = animCurrent;
4450             oldanimTarget = animTarget;
4451             oldframeTarget = frameTarget;
4452             oldframeCurrent = frameCurrent;
4453
4454             for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4455                 skeleton.joints[i].velocity = (currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * target - skeleton.joints[i].position) / multiplier;
4456                 skeleton.joints[i].position = currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * target;
4457             }
4458             offset = currentoffset * (1 - target) + targetoffset * target;
4459             for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4460                 if (skeleton.muscles[i].visible) {
4461                     skeleton.muscles[i].rotate1 = skeleton.muscles[i].oldrotate1 * (1 - target) + skeleton.muscles[i].newrotate1 * target;
4462                     skeleton.muscles[i].rotate2 = skeleton.muscles[i].oldrotate2 * (1 - target) + skeleton.muscles[i].newrotate2 * target;
4463                     skeleton.muscles[i].rotate3 = skeleton.muscles[i].oldrotate3 * (1 - target) + skeleton.muscles[i].newrotate3 * target;
4464                 }
4465             }
4466         }
4467
4468         if (isLanding() && landhard) {
4469             if (id == 0) {
4470                 camerashake += .4;
4471             }
4472             animTarget = getLandhard();
4473             frameTarget = 0;
4474             target = 0;
4475             landhard = 0;
4476             transspeed = 15;
4477         }
4478     }
4479 }
4480
4481 /* EFFECT
4482  * MONSTER
4483  * TODO
4484  */
4485 void Person::DoStuff()
4486 {
4487     static XYZ terrainnormal;
4488     static XYZ flatfacing;
4489     static XYZ flatvelocity;
4490     static float flatvelspeed;
4491     static int bloodsize;
4492     static int startx, starty, endx, endy;
4493     static GLubyte color;
4494     static XYZ bloodvel;
4495
4496     onfiredelay -= multiplier;
4497     if (onfiredelay < 0 && onfire) {
4498         if (Random() % 2 == 0) {
4499             crouchkeydown = 1;
4500         }
4501         onfiredelay = 0.3;
4502     }
4503
4504     crouchkeydowntime += multiplier;
4505     if (!crouchkeydown) {
4506         crouchkeydowntime = 0;
4507     }
4508     jumpkeydowntime += multiplier;
4509     if (!jumpkeydown && skeleton.free) {
4510         jumpkeydowntime = 0;
4511     }
4512
4513     if (hostile || damage > 0 || bloodloss > 0) {
4514         immobile = 0;
4515     }
4516
4517     if (isIdle() || isRun()) {
4518         targetoffset = 0;
4519     }
4520
4521     if (num_weapons == 1 && weaponactive != -1) {
4522         weaponstuck = -1;
4523     }
4524
4525     if (id == 0) {
4526         blooddimamount -= multiplier * .3;
4527     }
4528     speechdelay -= multiplier;
4529     texupdatedelay -= multiplier;
4530     interestdelay -= multiplier;
4531     flamedelay -= multiplier;
4532     parriedrecently -= multiplier;
4533     if (!victim) {
4534         victim = this->shared_from_this();
4535         hasvictim = 0;
4536     }
4537
4538     if (id == 0) {
4539         speed = 1.1 * speedmult;
4540     } else {
4541         speed = 1.0 * speedmult;
4542     }
4543     if (!skeleton.free) {
4544         rabbitkickragdoll = 0;
4545     }
4546
4547     speed *= speedmult;
4548
4549     if (id != 0 && (creature == rabbittype || difficulty != 2)) {
4550         superruntoggle = 0;
4551     }
4552     if (id != 0 && creature == wolftype && difficulty == 2) {
4553         superruntoggle = 0;
4554         if (aitype != passivetype) {
4555             superruntoggle = 1;
4556             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) {
4557                 superruntoggle = 0;
4558             }
4559         }
4560         if (scale < 0.2) {
4561             superruntoggle = 0;
4562         }
4563         if (animTarget == wolfrunninganim && !superruntoggle) {
4564             animTarget = getRun();
4565             frameTarget = 0;
4566         }
4567     }
4568     if (weaponactive == -1 && num_weapons > 0) {
4569         if (weapons[weaponids[0]].getType() == staff) {
4570             weaponactive = 0;
4571         }
4572     }
4573
4574     if (onfire) {
4575         burnt += multiplier;
4576         deathbleeding = 1;
4577         if (burnt > .6) {
4578             burnt = .6;
4579         }
4580         OPENAL_SetVolume(channels[stream_firesound], 256 + 256 * findLength(&velocity) / 3);
4581
4582         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
4583             float gLoc[3];
4584             gLoc[0] = coords.x;
4585             gLoc[1] = coords.y;
4586             gLoc[2] = coords.z;
4587
4588             if (id == 0) {
4589                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc);
4590                 OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
4591             }
4592         }
4593     }
4594     while (flamedelay < 0 && onfire) {
4595         flamedelay += .006;
4596         int howmany = fabs(Random() % (skeleton.joints.size()));
4597         if (skeleton.free) {
4598             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4599             flatfacing = skeleton.joints[howmany].position * scale + coords;
4600         } else {
4601             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4602             flatvelocity = (coords - oldcoords) / multiplier / 2;
4603         }
4604         Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
4605     }
4606
4607     while (flamedelay < 0 && !onfire && Tutorial::active && id != 0) {
4608         flamedelay += .05;
4609         int howmany = fabs(Random() % (skeleton.joints.size()));
4610         if (skeleton.free) {
4611             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4612             flatfacing = skeleton.joints[howmany].position * scale + coords;
4613         } else {
4614             flatvelocity = (coords - oldcoords) / multiplier / 2;
4615             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4616         }
4617         Sprite::MakeSprite(breathsprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, .3);
4618     }
4619
4620     if (bleeding > 0) {
4621         bleeding -= multiplier * .3;
4622         if (bloodtoggle == 2) {
4623             skeleton.drawmodel.textureptr.bind();
4624             if ((bleeding <= 0) && (detail != 2)) {
4625                 DoMipmaps();
4626             }
4627         }
4628     }
4629
4630     if (neckspurtamount > 0) {
4631         neckspurtamount -= multiplier;
4632         neckspurtdelay -= multiplier * 3;
4633         neckspurtparticledelay -= multiplier * 3;
4634         if (neckspurtparticledelay < 0 && neckspurtdelay > 2) {
4635             spurt = 0;
4636             bloodvel = 0;
4637             if (skeleton.free) {
4638                 bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0);
4639                 bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4640                 Sprite::MakeSprite(bloodsprite, (jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5) * scale + coords, bloodvel, 1, 1, 1, .05, .9);
4641             } else {
4642                 bloodvel.z = 5 * neckspurtamount;
4643                 bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4644                 bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0) * scale;
4645                 Sprite::MakeSprite(bloodsprite, DoRotation(jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, .9);
4646             }
4647             neckspurtparticledelay = .05;
4648         }
4649         if (neckspurtdelay < 0) {
4650             neckspurtdelay = 3;
4651         }
4652     }
4653
4654     if (deathbleeding > 0 && dead != 2) {
4655         if (deathbleeding < 5) {
4656             bleeddelay -= deathbleeding * multiplier / 4;
4657         } else {
4658             bleeddelay -= 5 * multiplier / 4;
4659         }
4660         if (bleeddelay < 0 && bloodtoggle) {
4661             bleeddelay = 1;
4662             XYZ bloodvel;
4663             if (bloodtoggle) {
4664                 bloodvel = 0;
4665                 if (skeleton.free) {
4666                     bloodvel += DoRotation(jointVel(abdomen), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
4667                     Sprite::MakeSprite(bloodsprite, jointPos(abdomen) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
4668                 } else {
4669                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
4670                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(abdomen) + jointPos(abdomen)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
4671                 }
4672             }
4673         }
4674         bloodloss += deathbleeding * multiplier * 80;
4675         deathbleeding -= multiplier * 1.6;
4676         if (deathbleeding < 0) {
4677             deathbleeding = 0;
4678         }
4679         if (bloodloss > damagetolerance && Animation::animations[animTarget].attack == neutral) {
4680             if (weaponactive != -1) {
4681                 weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
4682                 weapons[weaponids[0]].velocity.x += .01;
4683                 num_weapons--;
4684                 if (num_weapons) {
4685                     weaponids[0] = weaponids[num_weapons];
4686                     if (weaponstuck == num_weapons) {
4687                         weaponstuck = 0;
4688                     }
4689                 }
4690                 weaponactive = -1;
4691                 for (unsigned i = 0; i < Person::players.size(); i++) {
4692                     Person::players[i]->wentforweapon = 0;
4693                 }
4694
4695                 if (id == 0) {
4696                     Game::flash(.5, 0);
4697                 }
4698             }
4699
4700             if (!dead && creature == wolftype) {
4701                 award_bonus(0, Wolfbonus);
4702             }
4703             dead = 2;
4704             if (animTarget == knifefollowedanim && !skeleton.free) {
4705                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4706                     skeleton.joints[i].velocity = 0;
4707                     skeleton.joints[i].velocity.y = -2;
4708                 }
4709             }
4710             if (id != 0 && unconscioustime > .1) {
4711                 numafterkill++;
4712             }
4713
4714             RagDoll(0);
4715         }
4716     }
4717
4718     if (texupdatedelay < 0 && bleeding > 0 && bloodtoggle == 2 && distsq(&viewer, &coords) < 9) {
4719         texupdatedelay = .12;
4720
4721         bloodsize = 5 - realtexdetail;
4722
4723         startx = 0;
4724         starty = 0;
4725         startx = bleedy; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4726         starty = bleedx; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4727         endx = startx + bloodsize;
4728         endy = starty + bloodsize;
4729
4730         if (startx < 0) {
4731             startx = 0;
4732             bleeding = 0;
4733         }
4734         if (starty < 0) {
4735             starty = 0;
4736             bleeding = 0;
4737         }
4738         if (endx > skeleton.skinsize - 1) {
4739             endx = skeleton.skinsize - 1;
4740             bleeding = 0;
4741         }
4742         if (endy > skeleton.skinsize - 1) {
4743             endy = skeleton.skinsize - 1;
4744             bleeding = 0;
4745         }
4746         if (endx < startx) {
4747             endx = startx;
4748         }
4749         if (endy < starty) {
4750             endy = starty;
4751         }
4752
4753         for (int i = startx; i < endx; i++) {
4754             for (int j = starty; j < endy; j++) {
4755                 if (Random() % 2 == 0) {
4756                     color = Random() % 85 + 170;
4757                     if (skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] > color / 2) {
4758                         skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] = color / 2;
4759                     }
4760                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 1] = 0;
4761                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 2] = 0;
4762                 }
4763             }
4764         }
4765         if (detail > 1) {
4766             skeleton.drawmodel.textureptr.bind();
4767             DoMipmaps();
4768         }
4769
4770         if (skeleton.free) {
4771             bleedx += 4 * direction / realtexdetail;
4772             if (detail == 2) {
4773                 bleedy += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4774             } else {
4775                 bleedy += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4776             }
4777         } else {
4778             bleedy -= 4 / realtexdetail;
4779             if (detail == 2) {
4780                 bleedx += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4781             } else {
4782                 bleedx += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4783             }
4784         }
4785     }
4786
4787     if (abs(righthandmorphness - targetrighthandmorphness) < multiplier * 4) {
4788         righthandmorphness = targetrighthandmorphness;
4789         righthandmorphstart = righthandmorphend;
4790     } else if (righthandmorphness > targetrighthandmorphness) {
4791         righthandmorphness -= multiplier * 4;
4792     } else if (righthandmorphness < targetrighthandmorphness) {
4793         righthandmorphness += multiplier * 4;
4794     }
4795
4796     if (abs(lefthandmorphness - targetlefthandmorphness) < multiplier * 4) {
4797         lefthandmorphness = targetlefthandmorphness;
4798         lefthandmorphstart = lefthandmorphend;
4799     } else if (lefthandmorphness > targetlefthandmorphness) {
4800         lefthandmorphness -= multiplier * 4;
4801     } else if (lefthandmorphness < targetlefthandmorphness) {
4802         lefthandmorphness += multiplier * 4;
4803     }
4804
4805     if (creature == rabbittype || targettailmorphness == 5 || targettailmorphness == 0) {
4806         if (abs(tailmorphness - targettailmorphness) < multiplier * 10) {
4807             tailmorphness = targettailmorphness;
4808             tailmorphstart = tailmorphend;
4809         } else if (tailmorphness > targettailmorphness) {
4810             tailmorphness -= multiplier * 10;
4811         } else if (tailmorphness < targettailmorphness) {
4812             tailmorphness += multiplier * 10;
4813         }
4814     }
4815
4816     if (creature == wolftype) {
4817         if (abs(tailmorphness - targettailmorphness) < multiplier * 4) {
4818             tailmorphness = targettailmorphness;
4819             tailmorphstart = tailmorphend;
4820         } else if (tailmorphness > targettailmorphness) {
4821             tailmorphness -= multiplier * 2;
4822         } else if (tailmorphness < targettailmorphness) {
4823             tailmorphness += multiplier * 2;
4824         }
4825     }
4826
4827     if (headmorphend == 3 || headmorphstart == 3) {
4828         if (abs(headmorphness - targetheadmorphness) < multiplier * 7) {
4829             headmorphness = targetheadmorphness;
4830             headmorphstart = headmorphend;
4831         } else if (headmorphness > targetheadmorphness) {
4832             headmorphness -= multiplier * 7;
4833         } else if (headmorphness < targetheadmorphness) {
4834             headmorphness += multiplier * 7;
4835         }
4836     } else if (headmorphend == 5 || headmorphstart == 5) {
4837         if (abs(headmorphness - targetheadmorphness) < multiplier * 10) {
4838             headmorphness = targetheadmorphness;
4839             headmorphstart = headmorphend;
4840         } else if (headmorphness > targetheadmorphness) {
4841             headmorphness -= multiplier * 10;
4842         } else if (headmorphness < targetheadmorphness) {
4843             headmorphness += multiplier * 10;
4844         }
4845     } else {
4846         if (abs(headmorphness - targetheadmorphness) < multiplier * 4) {
4847             headmorphness = targetheadmorphness;
4848             headmorphstart = headmorphend;
4849         } else if (headmorphness > targetheadmorphness) {
4850             headmorphness -= multiplier * 4;
4851         } else if (headmorphness < targetheadmorphness) {
4852             headmorphness += multiplier * 4;
4853         }
4854     }
4855
4856     if (abs(chestmorphness - targetchestmorphness) < multiplier) {
4857         chestmorphness = targetchestmorphness;
4858         chestmorphstart = chestmorphend;
4859     } else if (chestmorphness > targetchestmorphness) {
4860         chestmorphness -= multiplier;
4861     } else if (chestmorphness < targetchestmorphness) {
4862         chestmorphness += multiplier;
4863     }
4864
4865     if (dead != 2 && howactive <= typesleeping) {
4866         if (chestmorphstart == 0 && chestmorphend == 0) {
4867             chestmorphness = 0;
4868             targetchestmorphness = 1;
4869             chestmorphend = 3;
4870         }
4871         if (chestmorphstart != 0 && chestmorphend != 0) {
4872             chestmorphness = 0;
4873             targetchestmorphness = 1;
4874             chestmorphend = 0;
4875             if (environment == snowyenvironment) {
4876                 XYZ footpoint;
4877                 XYZ footvel;
4878                 if (skeleton.free) {
4879                     footvel = skeleton.specialforward[0] * -1;
4880                     footpoint = ((jointPos(head) + jointPos(neck)) / 2) * scale + coords;
4881                 } else {
4882                     footvel = DoRotation(skeleton.specialforward[0], 0, yaw, 0) * -1;
4883                     footpoint = DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords;
4884                 }
4885                 if (animTarget == sleepanim) {
4886                     footvel = DoRotation(footvel, 0, 90, 0);
4887                 }
4888                 Sprite::MakeSprite(breathsprite, footpoint + footvel * .2, footvel * .4, 1, 1, 1, .4, .3);
4889             }
4890         }
4891
4892         if (!dead && howactive < typesleeping) {
4893             blinkdelay -= multiplier * 2;
4894             if (headmorphstart == 0 && headmorphend == 0 && blinkdelay <= 0) {
4895                 headmorphness = 0;
4896                 targetheadmorphness = 1;
4897                 headmorphend = 3;
4898                 blinkdelay = (float)(abs(Random() % 40)) / 5;
4899             }
4900             if (headmorphstart == 3 && headmorphend == 3) {
4901                 headmorphness = 0;
4902                 targetheadmorphness = 1;
4903                 headmorphend = 0;
4904             }
4905         }
4906         if (!dead) {
4907             twitchdelay -= multiplier * 1.5;
4908             if (animTarget != hurtidleanim) {
4909                 if (headmorphstart == 0 && headmorphend == 0 && twitchdelay <= 0) {
4910                     headmorphness = 0;
4911                     targetheadmorphness = 1;
4912                     headmorphend = 5;
4913                     twitchdelay = (float)(abs(Random() % 40)) / 5;
4914                 }
4915                 if (headmorphstart == 5 && headmorphend == 5) {
4916                     headmorphness = 0;
4917                     targetheadmorphness = 1;
4918                     headmorphend = 0;
4919                 }
4920             }
4921             if ((isIdle() || isCrouch()) && animTarget != hurtidleanim) {
4922                 twitchdelay3 -= multiplier * 1;
4923                 if (Random() % 2 == 0) {
4924                     if (righthandmorphstart == 0 && righthandmorphend == 0 && twitchdelay3 <= 0) {
4925                         righthandmorphness = 0;
4926                         targetrighthandmorphness = 1;
4927                         righthandmorphend = 1;
4928                         if (Random() % 2 == 0) {
4929                             twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4930                         }
4931                     }
4932                     if (righthandmorphstart == 1 && righthandmorphend == 1) {
4933                         righthandmorphness = 0;
4934                         targetrighthandmorphness = 1;
4935                         righthandmorphend = 0;
4936                     }
4937                 }
4938                 if (Random() % 2 == 0) {
4939                     if (lefthandmorphstart == 0 && lefthandmorphend == 0 && twitchdelay3 <= 0) {
4940                         lefthandmorphness = 0;
4941                         targetlefthandmorphness = 1;
4942                         lefthandmorphend = 1;
4943                         twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4944                     }
4945                     if (lefthandmorphstart == 1 && lefthandmorphend == 1) {
4946                         lefthandmorphness = 0;
4947                         targetlefthandmorphness = 1;
4948                         lefthandmorphend = 0;
4949                     }
4950                 }
4951             }
4952         }
4953         if (!dead) {
4954             if (creature == rabbittype) {
4955                 if (howactive < typesleeping) {
4956                     twitchdelay2 -= multiplier * 1.5;
4957                 } else {
4958                     twitchdelay2 -= multiplier * 0.5;
4959                 }
4960                 if (howactive <= typesleeping) {
4961                     if (tailmorphstart == 0 && tailmorphend == 0 && twitchdelay2 <= 0) {
4962                         tailmorphness = 0;
4963                         targettailmorphness = 1;
4964                         tailmorphend = 1;
4965                         twitchdelay2 = (float)(abs(Random() % 40)) / 5;
4966                     }
4967                     if (tailmorphstart == 1 && tailmorphend == 1) {
4968                         tailmorphness = 0;
4969                         targettailmorphness = 1;
4970                         tailmorphend = 2;
4971                     }
4972                     if (tailmorphstart == 2 && tailmorphend == 2) {
4973                         tailmorphness = 0;
4974                         targettailmorphness = 1;
4975                         tailmorphend = 0;
4976                     }
4977                 }
4978             }
4979         }
4980     }
4981     if (creature == wolftype) {
4982         twitchdelay2 -= multiplier * 1.5;
4983         if (tailmorphend != 0) {
4984             if ((isRun() || animTarget == jumpupanim || animTarget == jumpdownanim || animTarget == backflipanim) && !skeleton.free) {
4985                 tailmorphness = 0;
4986                 targettailmorphness = 1;
4987                 tailmorphend = 0;
4988                 twitchdelay2 = .1;
4989             }
4990         }
4991         if (tailmorphend != 5) {
4992             if (animTarget == flipanim || animTarget == frontflipanim || animTarget == rollanim || skeleton.free) {
4993                 tailmorphness = 0;
4994                 targettailmorphness = 1;
4995                 tailmorphend = 5;
4996                 twitchdelay2 = .1;
4997             }
4998         }
4999         if (twitchdelay2 <= 0) {
5000             if (((tailmorphstart == 0 && tailmorphend == 0) || (tailmorphstart == 5 && tailmorphend == 5))) {
5001                 tailmorphness = 0;
5002                 targettailmorphness = 1;
5003                 tailmorphend = 1;
5004             }
5005             if (tailmorphstart == 1 && tailmorphend == 1) {
5006                 tailmorphness = 0;
5007                 targettailmorphness = 1;
5008                 tailmorphend = 2;
5009             }
5010             if (tailmorphstart == 2 && tailmorphend == 2) {
5011                 tailmorphness = 0;
5012                 targettailmorphness = 1;
5013                 tailmorphend = 3;
5014             }
5015             if (tailmorphstart == 3 && tailmorphend == 3) {
5016                 tailmorphness = 0;
5017                 targettailmorphness = 1;
5018                 tailmorphend = 4;
5019             }
5020             if (tailmorphstart == 4 && tailmorphend == 4) {
5021                 tailmorphness = 0;
5022                 targettailmorphness = 1;
5023                 tailmorphend = 1;
5024             }
5025         }
5026     }
5027
5028     if (dead != 1) {
5029         unconscioustime = 0;
5030     }
5031
5032     if (dead == 1 || howactive == typesleeping) {
5033         unconscioustime += multiplier;
5034         //If unconscious, close eyes and mouth
5035         if (righthandmorphend != 0) {
5036             righthandmorphness = 0;
5037         }
5038         righthandmorphend = 0;
5039         targetrighthandmorphness = 1;
5040
5041         if (lefthandmorphend != 0) {
5042             lefthandmorphness = 0;
5043         }
5044         lefthandmorphend = 0;
5045         targetlefthandmorphness = 1;
5046
5047         if (headmorphend != 3 && headmorphend != 5) {
5048             headmorphness = 0;
5049         }
5050         headmorphend = 3;
5051         targetheadmorphness = 1;
5052     }
5053
5054     if (howactive > typesleeping) {
5055         XYZ headpoint;
5056         headpoint = coords;
5057         if (bloodtoggle && !bled) {
5058             terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
5059             for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5060                 unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5061                 XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5062                 float size = .8;
5063                 float opacity = .6;
5064                 float yaw = 0;
5065                 Object::objects[j]->model.MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
5066             }
5067         }
5068         bled = 1;
5069     }
5070
5071     if (dead == 2 || howactive > typesleeping) {
5072         //If dead, open mouth and hands
5073         if (righthandmorphend != 0) {
5074             righthandmorphness = 0;
5075         }
5076         righthandmorphend = 0;
5077         targetrighthandmorphness = 1;
5078
5079         if (lefthandmorphend != 0) {
5080             lefthandmorphness = 0;
5081         }
5082         lefthandmorphend = 0;
5083         targetlefthandmorphness = 1;
5084
5085         if (headmorphend != 2) {
5086             headmorphness = 0;
5087         }
5088         headmorphend = 2;
5089         targetheadmorphness = 1;
5090     }
5091
5092     if (stunned > 0 && !dead && headmorphend != 2) {
5093         if (headmorphend != 4) {
5094             headmorphness = 0;
5095         }
5096         headmorphend = 4;
5097         targetheadmorphness = 1;
5098     }
5099
5100     if (damage > damagetolerance && !dead) {
5101
5102         dead = 1;
5103         unconscioustime = 0;
5104
5105         if (creature == wolftype) {
5106             award_bonus(0, Wolfbonus);
5107         }
5108
5109         RagDoll(0);
5110
5111         if (weaponactive != -1) {
5112             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
5113             weapons[weaponids[0]].velocity.x += .01;
5114             num_weapons--;
5115             if (num_weapons) {
5116                 weaponids[0] = weaponids[num_weapons];
5117                 if (weaponstuck == num_weapons) {
5118                     weaponstuck = 0;
5119                 }
5120             }
5121             weaponactive = -1;
5122             for (unsigned i = 0; i < Person::players.size(); i++) {
5123                 Person::players[i]->wentforweapon = 0;
5124             }
5125         }
5126
5127         if ((id == 0 || distsq(&coords, &viewer) < 50) && autoslomo) {
5128             slomo = 1;
5129             slomodelay = .2;
5130         }
5131
5132         damage += 20;
5133     }
5134
5135     if (!dead) {
5136         damage -= multiplier * 13;
5137         permanentdamage -= multiplier * 4;
5138         if (isIdle() || isCrouch()) {
5139             permanentdamage -= multiplier * 4;
5140         }
5141     }
5142     if (damage < 0) {
5143         damage = 0;
5144     }
5145     if (permanentdamage < 0) {
5146         permanentdamage = 0;
5147     }
5148     if (superpermanentdamage < 0) {
5149         superpermanentdamage = 0;
5150     }
5151     if (permanentdamage < superpermanentdamage) {
5152         permanentdamage = superpermanentdamage;
5153     }
5154     if (damage < permanentdamage) {
5155         damage = permanentdamage;
5156     }
5157     if (dead == 1 && damage < damagetolerance) {
5158         dead = 0;
5159         skeleton.free = 1;
5160         damage -= 20;
5161         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5162             skeleton.joints[i].velocity = 0;
5163         }
5164     }
5165     if (permanentdamage > damagetolerance && dead != 2) {
5166         DoBlood(1, 255);
5167
5168         if (weaponactive != -1) {
5169             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
5170             weapons[weaponids[0]].velocity.x += .01;
5171             num_weapons--;
5172             if (num_weapons) {
5173                 weaponids[0] = weaponids[num_weapons];
5174                 if (weaponstuck == num_weapons) {
5175                     weaponstuck = 0;
5176                 }
5177             }
5178             weaponactive = -1;
5179             for (unsigned i = 0; i < Person::players.size(); i++) {
5180                 Person::players[i]->wentforweapon = 0;
5181             }
5182         }
5183
5184         bled = 0;
5185
5186         if (!dead && creature == wolftype) {
5187             award_bonus(0, Wolfbonus);
5188         }
5189
5190         if (unconscioustime < .1 && (bonus != spinecrusher || bonustime > 1) && (bonus != FinishedBonus || bonustime > 1) && bloodloss < damagetolerance) {
5191             award_bonus(id, touchofdeath);
5192         }
5193         if (id != 0 && unconscioustime > .1) {
5194             numafterkill++;
5195         }
5196
5197         dead = 2;
5198
5199         skeleton.free = 1;
5200
5201         emit_sound_at(breaksound, coords);
5202     }
5203
5204     if (skeleton.free == 1) {
5205         if (id == 0) {
5206             pause_sound(whooshsound);
5207         }
5208
5209         if (!dead) {
5210             //If knocked over, open hands and close mouth
5211             if (righthandmorphend != 0) {
5212                 righthandmorphness = 0;
5213             }
5214             righthandmorphend = 0;
5215             targetrighthandmorphness = 1;
5216
5217             if (lefthandmorphend != 0) {
5218                 lefthandmorphness = 0;
5219             }
5220             lefthandmorphend = 0;
5221             targetlefthandmorphness = 1;
5222
5223             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5) {
5224                 if (headmorphend != 0) {
5225                     headmorphness = 0;
5226                 }
5227                 headmorphend = 0;
5228                 targetheadmorphness = 1;
5229             }
5230         }
5231
5232         skeleton.DoGravity(&scale);
5233         float damageamount;
5234         damageamount = skeleton.DoConstraints(&coords, &scale) * 5;
5235         if (damage > damagetolerance - damageamount && !dead && (bonus != spinecrusher || bonustime > 1) && (bonus != style || bonustime > 1) && (bonus != cannon || bonustime > 1)) {
5236             award_bonus(id, deepimpact);
5237         }
5238         DoDamage(damageamount / ((protectionhigh + protectionhead + protectionlow) / 3));
5239
5240         XYZ average;
5241         average = 0;
5242         if (!skeleton.joints.empty()) {
5243             for (unsigned j = 0; j < skeleton.joints.size(); j++) {
5244                 average += skeleton.joints[j].position;
5245             }
5246             average /= skeleton.joints.size();
5247             coords += average * scale;
5248             for (unsigned j = 0; j < skeleton.joints.size(); j++) {
5249                 skeleton.joints[j].position -= average;
5250             }
5251             average /= multiplier;
5252         }
5253
5254         velocity = 0;
5255         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5256             velocity += skeleton.joints[i].velocity * scale;
5257         }
5258         velocity /= skeleton.joints.size();
5259
5260         if (!isnormal(velocity.x) && velocity.x) {
5261             velocity = 0;
5262         }
5263
5264         if (findLength(&average) < 10 && dead && skeleton.free) {
5265             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
5266             if (skeleton.longdead > 2000) {
5267                 if (skeleton.longdead > 6000) {
5268                     if (id == 0) {
5269                         pause_sound(whooshsound);
5270                     }
5271                     skeleton.free = 3;
5272                     DrawSkeleton();
5273                     skeleton.free = 2;
5274                 }
5275                 if (dead == 2 && bloodloss < damagetolerance) {
5276                     XYZ headpoint;
5277                     headpoint = (jointPos(head) + jointPos(neck)) / 2 * scale + coords;
5278                     DoBlood(1, 255);
5279                     if (bloodtoggle && !bled) {
5280                         terrain.MakeDecal(blooddecal, headpoint, .2 * 1.2, .5, 0);
5281                         for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5282                             unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5283                             XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5284                             float size = .2 * 1.2;
5285                             float opacity = .6;
5286                             float yaw = 0;
5287                             Object::objects[j]->model.MakeDecal(blooddecal, &point, &size, &opacity, &yaw);
5288                         }
5289                     }
5290                     bled = 1;
5291                 }
5292                 if (dead == 2 && bloodloss >= damagetolerance) {
5293                     XYZ headpoint;
5294                     headpoint = (jointPos(abdomen) + jointPos(neck)) / 2 * scale + coords;
5295                     if (bleeding <= 0) {
5296                         DoBlood(1, 255);
5297                     }
5298                     if (bloodtoggle && !bled) {
5299                         terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
5300                         for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5301                             unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5302                             XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5303                             float size = .8;
5304                             float opacity = .6;
5305                             float yaw = 0;
5306                             Object::objects[j]->model.MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
5307                         }
5308                     }
5309                     bled = 1;
5310                 }
5311             }
5312         }
5313
5314         if (!dead && crouchkeydown && skeleton.freetime > .5 && id == 0 && skeleton.free) {
5315             bool canrecover = 1;
5316             XYZ startpoint, endpoint, colpoint, colviewer, coltarget;
5317             startpoint = coords;
5318             endpoint = coords;
5319             endpoint.y -= .7;
5320             if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1) {
5321                 canrecover = 0;
5322             }
5323             if (velocity.y < -30) {
5324                 canrecover = 0;
5325             }
5326             for (unsigned int i = 0; i < Object::objects.size(); i++) {
5327                 if (Object::objects[i]->type != treeleavestype && Object::objects[i]->type != bushtype && Object::objects[i]->type != firetype) {
5328                     colviewer = startpoint;
5329                     coltarget = endpoint;
5330                     if (Object::objects[i]->model.LineCheck(&colviewer, &coltarget, &colpoint, &Object::objects[i]->position, &Object::objects[i]->yaw) != -1) {
5331                         canrecover = 0;
5332                     }
5333                 }
5334             }
5335             if (canrecover) {
5336                 skeleton.free = 0;
5337                 XYZ middle;
5338                 middle = 0;
5339
5340                 terrainnormal = jointPos(groin) - jointPos(abdomen);
5341                 if (joint(groin).locked && joint(abdomen).locked) {
5342                     terrainnormal = jointPos(groin) - jointPos(abdomen);
5343                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
5344                 }
5345                 if (joint(abdomen).locked && joint(neck).locked) {
5346                     terrainnormal = jointPos(abdomen) - jointPos(neck);
5347                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
5348                 }
5349                 if (joint(groin).locked && joint(neck).locked) {
5350                     terrainnormal = jointPos(groin) - jointPos(neck);
5351                     middle = (jointPos(groin) + jointPos(neck)) / 2;
5352                 }
5353                 Normalise(&terrainnormal);
5354
5355                 targetyaw = -asin(0 - terrainnormal.x);
5356                 targetyaw *= 360 / 6.28;
5357                 if (terrainnormal.z < 0) {
5358                     targetyaw = 180 - targetyaw;
5359                 }
5360                 yaw = targetyaw;
5361
5362                 frameTarget = 0;
5363                 animTarget = flipanim;
5364                 crouchtogglekeydown = 1;
5365                 target = 0;
5366                 tilt2 = 0;
5367                 targettilt2 = 0;
5368
5369                 animCurrent = tempanim;
5370                 frameCurrent = 0;
5371                 target = 0;
5372
5373                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5374                     tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
5375                     tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
5376                 }
5377             }
5378         }
5379
5380         if (findLength(&average) < 10 && !dead && skeleton.free) {
5381             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
5382             if (skeleton.longdead > (damage + 500) * 1.5) {
5383                 if (id == 0) {
5384                     pause_sound(whooshsound);
5385                 }
5386                 skeleton.free = 0;
5387                 velocity = 0;
5388                 XYZ middle;
5389                 middle = 0;
5390
5391                 terrainnormal = jointPos(groin) - jointPos(abdomen);
5392                 if (joint(groin).locked && joint(abdomen).locked) {
5393                     terrainnormal = jointPos(groin) - jointPos(abdomen);
5394                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
5395                 }
5396                 if (joint(abdomen).locked && joint(neck).locked) {
5397                     terrainnormal = jointPos(abdomen) - jointPos(neck);
5398                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
5399                 }
5400                 if (joint(groin).locked && joint(neck).locked) {
5401                     terrainnormal = jointPos(groin) - jointPos(neck);
5402                     middle = (jointPos(groin) + jointPos(neck)) / 2;
5403                 }
5404                 Normalise(&terrainnormal);
5405
5406                 targetyaw = -asin(0 - terrainnormal.x);
5407                 targetyaw *= 360 / 6.28;
5408                 if (terrainnormal.z < 0) {
5409                     targetyaw = 180 - targetyaw;
5410                 }
5411                 yaw = targetyaw;
5412
5413                 targettilt2 = asin(terrainnormal.y) * 180 / 3.14 * -1;
5414
5415                 if (skeleton.forward.y < 0) {
5416                     animTarget = getupfrombackanim;
5417                     frameTarget = 0;
5418                     targettilt2 = 0;
5419                 }
5420                 if (skeleton.forward.y > -.3) {
5421                     animTarget = getupfromfrontanim;
5422                     yaw += 180;
5423                     targetyaw += 180;
5424                     targettilt2 *= -1;
5425                     frameTarget = 0;
5426                     targettilt2 = 0;
5427                 }
5428
5429                 if ((Random() % 8 == 0 && id != 0 && creature == rabbittype) || (Random() % 2 == 0 && id != 0 && creature == wolftype) || (id == 0 && crouchkeydown && (forwardkeydown || backkeydown || leftkeydown || rightkeydown))) {
5430                     animTarget = rollanim;
5431                     targetyaw = lookyaw;
5432                     if (id == 0) {
5433                         if (rightkeydown) {
5434                             targetyaw -= 90;
5435                             if (forwardkeydown) {
5436                                 targetyaw += 45;
5437                             }
5438                             if (backkeydown) {
5439                                 targetyaw -= 45;
5440                             }
5441                         }
5442                         if (leftkeydown) {
5443                             targetyaw += 90;
5444                             if (forwardkeydown) {
5445                                 targetyaw -= 45;
5446                             }
5447                             if (backkeydown) {
5448                                 targetyaw += 45;
5449                             }
5450                         }
5451                         if (backkeydown) {
5452                             if (!leftkeydown && !rightkeydown) {
5453                                 targetyaw += 180;
5454                             }
5455                         }
5456                         targetyaw += 180;
5457                     }
5458                 }
5459
5460                 if (abs(targettilt2) > 50) {
5461                     targettilt2 = 0;
5462                 }
5463                 animCurrent = tempanim;
5464                 frameCurrent = 0;
5465                 target = 0;
5466                 tilt2 = targettilt2;
5467
5468                 if (middle.y > 0 && animTarget != rollanim) {
5469                     targetoffset.y = middle.y + 1;
5470                 }
5471
5472                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5473                     tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
5474                     tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
5475                 }
5476             }
5477         }
5478
5479         bool hasstaff;
5480         hasstaff = 0;
5481         if (num_weapons > 0) {
5482             if (weapons[0].getType() == staff) {
5483                 hasstaff = 1;
5484             }
5485         }
5486         if (!skeleton.freefall && freefall && ((jumpkeydown && jumpkeydowntime < .2) || (hasstaff && rabbitkickragdoll)) && !dead) {
5487             if (velocity.y > -30) {
5488                 XYZ tempvelocity;
5489                 tempvelocity = velocity;
5490                 Normalise(&tempvelocity);
5491                 targetyaw = -asin(0 - tempvelocity.x);
5492                 targetyaw *= 360 / 6.28;
5493                 if (velocity.z < 0) {
5494                     targetyaw = 180 - targetyaw;
5495                 }
5496                 //targetyaw+=180;
5497
5498                 skeleton.free = 0;
5499                 if (dotproduct(&skeleton.forward, &tempvelocity) < 0) {
5500                     animTarget = rollanim;
5501                     frameTarget = 2;
5502                 } else {
5503                     animTarget = backhandspringanim;
5504                     targetyaw += 180;
5505                     frameTarget = 6;
5506                 }
5507                 target = 0;
5508
5509                 emit_sound_at(movewhooshsound, coords, 128.);
5510
5511                 animCurrent = animTarget;
5512                 frameCurrent = frameTarget - 1;
5513                 target = 0;
5514
5515                 velocity = 0;
5516
5517                 yaw = targetyaw;
5518                 tilt = 0;
5519                 targettilt = 0;
5520                 tilt2 = 0;
5521                 targettilt2 = 0;
5522             }
5523         }
5524         if (skeleton.freefall == 0) {
5525             freefall = 0;
5526         }
5527     }
5528
5529     if (aitype != passivetype || skeleton.free == 1) {
5530         if (findLengthfast(&velocity) > .1) {
5531             for (unsigned int i = 0; i < Object::objects.size(); i++) {
5532                 if (Object::objects[i]->type == firetype) {
5533                     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) {
5534                         if (onfire) {
5535                             if (!Object::objects[i]->onfire) {
5536                                 emit_sound_at(firestartsound, Object::objects[i]->position);
5537                             }
5538                             Object::objects[i]->onfire = 1;
5539                         }
5540                         if (!onfire) {
5541                             if (Object::objects[i]->onfire) {
5542                                 CatchFire();
5543                             }
5544                         }
5545                     }
5546                 }
5547                 if (Object::objects[i]->type == bushtype) {
5548                     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) {
5549                         if (onfire) {
5550                             if (!Object::objects[i]->onfire) {
5551                                 emit_sound_at(firestartsound, Object::objects[i]->position);
5552                             }
5553                             Object::objects[i]->onfire = 1;
5554                         }
5555
5556                         if (!onfire) {
5557                             if (Object::objects[i]->onfire) {
5558                                 CatchFire();
5559                             }
5560                         }
5561                         if (Object::objects[i]->messedwith <= 0) {
5562                             XYZ tempvel;
5563                             XYZ pos;
5564
5565                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
5566
5567                             if (id == 0) {
5568                                 addEnvSound(coords, 4 * findLength(&velocity));
5569                             }
5570
5571                             int howmany = 0;
5572                             if (environment == grassyenvironment) {
5573                                 howmany = findLength(&velocity) * 4;
5574                             }
5575                             if (environment == snowyenvironment) {
5576                                 howmany = findLength(&velocity) * 2;
5577                             }
5578                             if (detail == 2) {
5579                                 if (environment != desertenvironment) {
5580                                     for (int j = 0; j < howmany; j++) {
5581                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5582                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5583                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5584                                         pos = coords;
5585                                         pos.y += 1;
5586                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5587                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5588                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5589                                         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);
5590                                         Sprite::setLastSpriteSpecial(1);
5591                                     }
5592                                 }
5593                             }
5594                             howmany = findLength(&velocity) * 4;
5595                             if (detail == 2) {
5596                                 if (environment == snowyenvironment) {
5597                                     for (int j = 0; j < howmany; j++) {
5598                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5599                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5600                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5601                                         pos = coords;
5602                                         pos.y += 1;
5603                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5604                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5605                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5606                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5607                                         Sprite::setLastSpriteSpecial(2);
5608                                     }
5609                                 }
5610                             }
5611                         }
5612                         Object::objects[i]->rotx += velocity.x * multiplier * 6;
5613                         Object::objects[i]->roty += velocity.z * multiplier * 6;
5614                         Object::objects[i]->messedwith = .5;
5615                     }
5616                 }
5617                 XYZ tempcoord;
5618                 if (Object::objects[i]->type == treeleavestype && environment != desertenvironment) {
5619                     if (Object::objects[i]->pitch == 0) {
5620                         tempcoord = coords;
5621                     } else {
5622                         tempcoord = coords - Object::objects[i]->position;
5623                         tempcoord = DoRotation(tempcoord, 0, -Object::objects[i]->yaw, 0);
5624                         tempcoord = DoRotation(tempcoord, -Object::objects[i]->pitch, 0, 0);
5625                         tempcoord += Object::objects[i]->position;
5626                     }
5627                     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) {
5628                         if (Object::objects[i]->messedwith <= 0) {
5629                             XYZ tempvel;
5630                             XYZ pos;
5631
5632                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
5633
5634                             if (id == 0) {
5635                                 addEnvSound(coords, 4 * findLength(&velocity));
5636                             }
5637
5638                             int howmany = 0;
5639                             if (environment == grassyenvironment) {
5640                                 howmany = findLength(&velocity) * 4;
5641                             }
5642                             if (environment == snowyenvironment) {
5643                                 howmany = findLength(&velocity) * 2;
5644                             }
5645                             if (detail == 2) {
5646                                 if (environment != desertenvironment) {
5647                                     for (int j = 0; j < howmany; j++) {
5648                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5649                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5650                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5651                                         pos = coords;
5652                                         pos += velocity * .1;
5653                                         pos.y += 1;
5654                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5655                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5656                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5657                                         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);
5658                                         Sprite::setLastSpriteSpecial(1);
5659                                     }
5660                                 }
5661                             }
5662                             howmany = findLength(&velocity) * 4;
5663                             if (detail == 2) {
5664                                 if (environment == snowyenvironment) {
5665                                     for (int j = 0; j < howmany; j++) {
5666                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5667                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5668                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5669                                         pos = coords;
5670                                         pos += velocity * .1;
5671                                         pos.y += 1;
5672                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5673                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5674                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5675                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5676                                         Sprite::setLastSpriteSpecial(2);
5677                                     }
5678                                 }
5679                             }
5680                         }
5681                         Object::objects[i]->messedwith = .5;
5682                     }
5683                 }
5684             }
5685         }
5686     }
5687
5688     if (!skeleton.free) {
5689         bool play;
5690         play = 0;
5691         if ((stunned > 0 || surprised > 0) && Person::players.size() > 2 && aitype != passivetype) {
5692             play = 1;
5693         }
5694         if (hasvictim) {
5695             if (aitype != passivetype && victim->skeleton.free && !victim->dead) {
5696                 play = 1;
5697             }
5698         }
5699         if (Tutorial::active && id != 0) {
5700             play = 0;
5701         }
5702         if (play && aitype != playercontrolled) {
5703             int whichsound = -1;
5704             if (speechdelay <= 0) {
5705                 unsigned int i = abs(Random() % 4);
5706                 if (i < 2) {
5707                     whichsound = PersonType::types[creature].soundsTalk[i];
5708                 }
5709             }
5710             speechdelay = .3;
5711
5712             if (whichsound != -1) {
5713                 emit_sound_at(whichsound, coords);
5714             }
5715         }
5716
5717         if (animTarget == staggerbackhighanim) {
5718             staggerdelay = 1;
5719         }
5720         if (animTarget == staggerbackhardanim) {
5721             staggerdelay = 1;
5722         }
5723         staggerdelay -= multiplier;
5724         if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) {
5725             hasvictim = 1;
5726         }
5727         if (velocity.y < -30 && animTarget == jumpdownanim) {
5728             RagDoll(0);
5729         }
5730         if (animCurrent != getIdle() && wasIdle() && animTarget != getIdle() && isIdle()) {
5731             animTarget = getIdle();
5732             frameTarget = 0;
5733             target = 0;
5734         }
5735         weaponmissdelay -= multiplier;
5736         highreversaldelay -= multiplier;
5737         lowreversaldelay -= multiplier;
5738         lastcollide -= multiplier;
5739         skiddelay -= multiplier;
5740         if (!isnormal(velocity.x) && velocity.x) {
5741             velocity = 0;
5742         }
5743         if (!isnormal(targettilt) && targettilt) {
5744             targettilt = 0;
5745         }
5746         if (!isnormal(targettilt2) && targettilt2) {
5747             targettilt2 = 0;
5748         }
5749         if (!isnormal(targetyaw) && targetyaw) {
5750             targetyaw = 0;
5751         }
5752
5753         if (animTarget == bounceidleanim || animTarget == wolfidle || animTarget == walkanim || animTarget == drawrightanim || animTarget == crouchdrawrightanim || animTarget == drawleftanim || animTarget == fightidleanim || animTarget == fightsidestep || animTarget == hanganim || isCrouch() || animTarget == backhandspringanim) {
5754             //open hands and close mouth
5755             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5756                 righthandmorphness = 0;
5757                 righthandmorphend = 0;
5758                 targetrighthandmorphness = 1;
5759             }
5760
5761             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5762                 lefthandmorphness = 0;
5763                 lefthandmorphend = 0;
5764                 targetlefthandmorphness = 1;
5765             }
5766
5767             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5 && headmorphend != 0 && headmorphness == targetheadmorphness) {
5768                 headmorphness = 0;
5769                 headmorphend = 0;
5770                 targetheadmorphness = 1;
5771             }
5772         }
5773
5774         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) {
5775             //open hands and mouth
5776             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5777                 righthandmorphness = 0;
5778                 righthandmorphend = 0;
5779                 targetrighthandmorphness = 1;
5780             }
5781
5782             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5783                 lefthandmorphness = 0;
5784                 lefthandmorphend = 0;
5785                 targetlefthandmorphness = 1;
5786             }
5787
5788             if (headmorphend != 1 && headmorphness == targetheadmorphness) {
5789                 headmorphness = 0;
5790                 headmorphend = 1;
5791                 targetheadmorphness = 1;
5792             }
5793         }
5794
5795         if (animTarget == jumpupanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == swordfightidlebothanim || animTarget == blockhighleftanim) {
5796             //close hands and mouth
5797             if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
5798                 righthandmorphness = 0;
5799                 righthandmorphend = 1;
5800                 targetrighthandmorphness = 1;
5801             }
5802
5803             if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
5804                 lefthandmorphness = 0;
5805                 lefthandmorphend = 1;
5806                 targetlefthandmorphness = 1;
5807             }
5808
5809             if (headmorphend != 0 && headmorphness == targetheadmorphness) {
5810                 headmorphness = 0;
5811                 headmorphend = 0;
5812                 targetheadmorphness = 1;
5813             }
5814         }
5815
5816         if (animTarget == spinkickanim ||
5817             animTarget == staffspinhitreversalanim ||
5818             animTarget == staffspinhitreversedanim ||
5819             animTarget == staffhitreversalanim ||
5820             animTarget == staffhitreversedanim ||
5821             animTarget == hurtidleanim ||
5822             animTarget == winduppunchanim ||
5823             animTarget == swordslashreversalanim ||
5824             animTarget == swordslashreversedanim ||
5825             animTarget == knifeslashreversalanim ||
5826             animTarget == knifeslashreversedanim ||
5827             animTarget == knifethrowanim ||
5828             animTarget == knifefollowanim ||
5829             animTarget == knifefollowedanim ||
5830             animTarget == killanim ||
5831             animTarget == dropkickanim ||
5832             animTarget == upunchanim ||
5833             animTarget == knifeslashstartanim ||
5834             animTarget == swordslashanim ||
5835             animTarget == staffhitanim ||
5836             animTarget == staffspinhitanim ||
5837             animTarget == staffgroundsmashanim ||
5838             animTarget == spinkickreversalanim ||
5839             animTarget == sweepreversalanim ||
5840             animTarget == lowkickanim ||
5841             animTarget == sweepreversedanim ||
5842             animTarget == rabbitkickreversalanim ||
5843             animTarget == rabbitkickreversedanim ||
5844             animTarget == jumpreversalanim ||
5845             animTarget == jumpreversedanim) {
5846             //close hands and yell
5847             if (righthandmorphend != 1 &&
5848                 righthandmorphness == targetrighthandmorphness) {
5849                 righthandmorphness = 0;
5850                 righthandmorphend = 1;
5851                 targetrighthandmorphness = 1;
5852             }
5853
5854             if (lefthandmorphend != 1 &&
5855                 lefthandmorphness == targetlefthandmorphness) {
5856                 lefthandmorphness = 0;
5857                 lefthandmorphend = 1;
5858                 targetlefthandmorphness = 1;
5859             }
5860
5861             if (headmorphend != 2 && headmorphness == targetheadmorphness) {
5862                 headmorphness = 1;
5863                 headmorphend = 2;
5864                 targetheadmorphness = 1;
5865             }
5866         }
5867
5868         bool behind;
5869         behind = 0;
5870         if (hasvictim) {
5871             if ((victim != this->shared_from_this()) && !victim->dead && (victim->aitype != passivetype) &&
5872                 (victim->aitype != searchtype) && (aitype != passivetype) &&
5873                 (aitype != searchtype) && (victim->id < Person::players.size())) {
5874                 behind = (normaldotproduct(facing, coords - victim->coords) > 0);
5875             }
5876         }
5877
5878         if (!dead && animTarget != hurtidleanim) {
5879             if (behind || animTarget == killanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == spinkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversedanim) {
5880                 if (headmorphend != 4 || headmorphness == targetheadmorphness) {
5881                     headmorphend = 4;
5882                     //headmorphness=1;
5883                     targetheadmorphness = 1;
5884                 }
5885             }
5886         }
5887
5888         if (weaponactive != -1) {
5889             if (weapons[weaponids[weaponactive]].getType() != staff) {
5890                 righthandmorphstart = 1;
5891                 righthandmorphend = 1;
5892             }
5893             if (weapons[weaponids[weaponactive]].getType() == staff) {
5894                 righthandmorphstart = 2;
5895                 righthandmorphend = 2;
5896             }
5897             targetrighthandmorphness = 1;
5898         }
5899
5900         terrainnormal = terrain.getNormal(coords.x, coords.z);
5901
5902         if (Animation::animations[animTarget].attack != reversal) {
5903             if (!isnormal(coords.x)) {
5904                 coords = oldcoords;
5905             }
5906             oldcoords = coords;
5907         }
5908
5909         flatfacing = 0;
5910         flatfacing.z = 1;
5911
5912         flatfacing = DoRotation(flatfacing, 0, yaw, 0);
5913         facing = flatfacing;
5914         ReflectVector(&facing, terrainnormal);
5915         Normalise(&facing);
5916
5917         if (isRun() ||
5918             animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim) {
5919             if (onterrain) {
5920                 targettilt2 = -facing.y * 20;
5921             } else {
5922                 targettilt2 = 0;
5923             }
5924         }
5925         onterrain = 0;
5926         if (!isRun() && !Animation::animations[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim) {
5927             targettilt2 = 0;
5928         }
5929         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
5930             flatvelocity = velocity;
5931             flatvelocity.y = 0;
5932             flatvelspeed = findLength(&flatvelocity);
5933             targettilt = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(DoRotation(flatfacing, 0, -90, 0), flatvelocity);
5934             targettilt2 = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(flatfacing, flatvelocity);
5935             if (velocity.y < 0) {
5936                 targettilt2 *= -1;
5937             }
5938             if (velocity.y < 0) {
5939                 targettilt *= -1;
5940             }
5941             if (targettilt > 25) {
5942                 targettilt = 25;
5943             }
5944             if (targettilt < -25) {
5945                 targettilt = -25;
5946             }
5947         }
5948
5949         if (targettilt2 > 45) {
5950             targettilt2 = 45;
5951         }
5952         if (targettilt2 < -45) {
5953             targettilt2 = -45;
5954         }
5955         if (abs(tilt2 - targettilt2) < multiplier * 400) {
5956             tilt2 = targettilt2;
5957         } else if (tilt2 > targettilt2) {
5958             tilt2 -= multiplier * 400;
5959         } else if (tilt2 < targettilt2) {
5960             tilt2 += multiplier * 400;
5961         }
5962         if (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
5963             if (tilt2 > 25) {
5964                 tilt2 = 25;
5965             }
5966             if (tilt2 < -25) {
5967                 tilt2 = -25;
5968             }
5969         }
5970
5971         if (!isnormal(targettilt) && targettilt) {
5972             targettilt = 0;
5973         }
5974         if (!isnormal(targettilt2) && targettilt2) {
5975             targettilt2 = 0;
5976         }
5977
5978         //Running velocity
5979         if (animTarget == rabbittackleanim) {
5980             velocity += facing * multiplier * speed * 700 * scale;
5981             velspeed = findLength(&velocity);
5982             if (velspeed > speed * 65 * scale) {
5983                 velocity /= velspeed;
5984                 velspeed = speed * 65 * 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             velocity = flatfacing * velspeed;
5991         }
5992         if (animTarget != rabbitrunninganim && animTarget != wolfrunninganim) {
5993             if (isRun() || animTarget == rabbitkickanim) {
5994                 velocity += facing * multiplier * speed * 700 * scale;
5995                 velspeed = findLength(&velocity);
5996                 if (velspeed > speed * 45 * scale) {
5997                     velocity /= velspeed;
5998                     velspeed = speed * 45 * scale;
5999                     velocity *= velspeed;
6000                 }
6001                 velocity.y += gravity * multiplier * 20;
6002                 ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6003                 velspeed = findLength(&velocity);
6004                 if (velspeed < speed * 30 * scale) {
6005                     velspeed = speed * 30 * scale;
6006                 }
6007                 velocity = flatfacing * velspeed;
6008             }
6009         } else if (isRun()) {
6010             velocity += facing * multiplier * speed * 700 * scale;
6011             velspeed = findLength(&velocity);
6012             if (velspeed > speed * PersonType::types[creature].maxRunSpeed * scale) {
6013                 velocity /= velspeed;
6014                 velspeed = speed * PersonType::types[creature].maxRunSpeed * 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 == rollanim && targetFrame().label != 6) {
6024             velocity += facing * multiplier * speed * 700 * scale;
6025             velspeed = findLength(&velocity);
6026             if (velspeed > speed * 45 * scale) {
6027                 velocity /= velspeed;
6028                 velspeed = speed * 45 * 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 == sneakanim || animTarget == walkanim) {
6038             velocity += facing * multiplier * speed * 700 * scale;
6039             velspeed = findLength(&velocity);
6040             if (velspeed > speed * 12 * scale) {
6041                 velocity /= velspeed;
6042                 velspeed = speed * 12 * 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 == fightidleanim || animTarget == knifefightidleanim) && (animCurrent == bounceidleanim || animCurrent == hurtidleanim)) {
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;
6063         }
6064
6065         if ((animTarget == bounceidleanim || animCurrent == hurtidleanim) && (animCurrent == fightidleanim || animCurrent == knifefightidleanim)) {
6066             velocity -= facing * multiplier * speed * 700 * scale;
6067             velspeed = findLength(&velocity);
6068             if (velspeed > speed * 2 * scale) {
6069                 velocity /= velspeed;
6070                 velspeed = speed * 2 * 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 = flatfacing * velspeed * -1;
6077         }
6078
6079         if (animTarget == fightsidestep) {
6080             velocity += DoRotation(facing * multiplier * speed * 700 * scale, 0, -90, 0);
6081             velspeed = findLength(&velocity);
6082             if (velspeed > speed * 12 * scale) {
6083                 velocity /= velspeed;
6084                 velspeed = speed * 12 * scale;
6085                 velocity *= velspeed;
6086             }
6087             velocity.y += gravity * multiplier * 20;
6088             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6089             velspeed = findLength(&velocity);
6090             velocity = DoRotation(flatfacing * velspeed, 0, -90, 0);
6091         }
6092
6093         if (animTarget == staggerbackhighanim) {
6094             coords -= facing * multiplier * speed * 16 * scale;
6095             velocity = 0;
6096         }
6097         if (animTarget == staggerbackhardanim && Animation::animations[staggerbackhardanim].frames[frameTarget].label != 6) {
6098             coords -= facing * multiplier * speed * 20 * scale;
6099             velocity = 0;
6100         }
6101
6102         if (animTarget == backhandspringanim) {
6103             //coords-=facing*multiplier*50*scale;
6104             velocity += facing * multiplier * speed * 700 * scale * -1;
6105             velspeed = findLength(&velocity);
6106             if (velspeed > speed * 50 * scale) {
6107                 velocity /= velspeed;
6108                 velspeed = speed * 50 * 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         if (animTarget == dodgebackanim) {
6117             //coords-=facing*multiplier*50*scale;
6118             velocity += facing * multiplier * speed * 700 * scale * -1;
6119             velspeed = findLength(&velocity);
6120             if (velspeed > speed * 60 * scale) {
6121                 velocity /= velspeed;
6122                 velspeed = speed * 60 * scale;
6123                 velocity *= velspeed;
6124             }
6125             velocity.y += gravity * multiplier * 20;
6126             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6127             velspeed = findLength(&velocity);
6128             velocity = flatfacing * velspeed * -1;
6129         }
6130
6131         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
6132             velspeed = findLength(&velocity);
6133         }
6134
6135         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
6136             velocity.y += gravity * multiplier;
6137         }
6138
6139         if (animTarget != climbanim && animTarget != hanganim && !isWallJump()) {
6140             coords += velocity * multiplier;
6141         }
6142
6143         if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
6144             if (isFlip() && targetFrame().label == 7) {
6145                 RagDoll(0);
6146             }
6147
6148             if (animTarget == jumpupanim) {
6149                 jumppower = -4;
6150                 animTarget = getIdle();
6151             }
6152             target = 0;
6153             frameTarget = 0;
6154             onterrain = 1;
6155
6156             if (id == 0) {
6157                 pause_sound(whooshsound);
6158                 OPENAL_SetVolume(channels[whooshsound], 0);
6159             }
6160
6161             if (animTarget == jumpdownanim || isFlip()) {
6162                 if (isFlip()) {
6163                     jumppower = -4;
6164                 }
6165                 animTarget = getLanding();
6166                 emit_sound_at(landsound, coords, 128.);
6167
6168                 if (id == 0) {
6169                     addEnvSound(coords);
6170                 }
6171             }
6172         }
6173
6174         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && animTarget != climbanim && animTarget != hanganim && !isWallJump()) {
6175             coords.y += gravity * multiplier * 2;
6176         }
6177         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && coords.y < terrain.getHeight(coords.x, coords.z)) {
6178             coords.y = terrain.getHeight(coords.x, coords.z);
6179             onterrain = 1;
6180         }
6181
6182         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)) {
6183             velspeed = findLength(&velocity);
6184             velocity.y = 0;
6185             if (velspeed < multiplier * 300 * scale) {
6186                 velocity = 0;
6187             } else {
6188                 velocity -= velocity / velspeed * multiplier * 300 * scale;
6189             }
6190             if (velspeed > 5 && (isLanding() || isLandhard())) {
6191                 skiddingdelay += multiplier;
6192                 if (skiddelay <= 0) {
6193                     FootLand(leftfoot, .5);
6194                     FootLand(rightfoot, .5);
6195                     skiddelay = .02;
6196                 }
6197             } else {
6198                 skiddingdelay = 0;
6199             }
6200         }
6201
6202         if (isLandhard()) {
6203             velspeed = findLength(&velocity);
6204             velocity = 0;
6205             if (velspeed > 5 && (isLanding() || isLandhard())) {
6206                 skiddingdelay += multiplier;
6207                 if (skiddelay <= 0) {
6208                     FootLand(leftfoot, .5);
6209                     FootLand(rightfoot, .5);
6210                     skiddelay = .02;
6211                 }
6212             } else {
6213                 skiddingdelay = 0;
6214             }
6215         }
6216
6217         if (skiddingdelay < 0) {
6218             skiddingdelay += multiplier;
6219         }
6220         if (skiddingdelay > .02 && !forwardkeydown && !backkeydown && !leftkeydown && !rightkeydown && !jumpkeydown && isLanding() && !landhard) {
6221             skiddingdelay = -1;
6222             if (!onterrain || environment == grassyenvironment) {
6223                 emit_sound_at(skidsound, coords, 128 * velspeed / 10);
6224             } else {
6225                 emit_sound_at(snowskidsound, coords, 128 * velspeed / 10);
6226             }
6227         }
6228
6229         if (Animation::animations[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
6230             terrainnormal = victim->coords - coords;
6231             Normalise(&terrainnormal);
6232             targetyaw = -asin(0 - terrainnormal.x);
6233             targetyaw *= 360 / 6.28;
6234             if (terrainnormal.z < 0) {
6235                 targetyaw = 180 - targetyaw;
6236             }
6237             targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
6238         }
6239
6240         if (Animation::animations[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
6241             targetyaw = victim->targetyaw;
6242         }
6243         if (animTarget == rabbittacklinganim) {
6244             coords = victim->coords;
6245         }
6246     }
6247     skeleton.oldfree = skeleton.free;
6248
6249     XYZ midterrain;
6250     midterrain = 0;
6251     midterrain.x = terrain.size * terrain.scale / 2;
6252     midterrain.z = terrain.size * terrain.scale / 2;
6253     if (distsqflat(&coords, &midterrain) > (terrain.size * terrain.scale / 2 - viewdistance) * (terrain.size * terrain.scale / 2 - viewdistance)) {
6254         XYZ tempposit;
6255         tempposit = coords - midterrain;
6256         tempposit.y = 0;
6257         Normalise(&tempposit);
6258         tempposit *= (terrain.size * terrain.scale / 2 - viewdistance);
6259         coords.x = tempposit.x + midterrain.x;
6260         coords.z = tempposit.z + midterrain.z;
6261     }
6262 }
6263
6264 /* EFFECT
6265  * inverse kinematics helper function
6266  */
6267 void IKHelper(Person* p, float interp)
6268 {
6269     XYZ point, change, change2;
6270     float heightleft, heightright;
6271
6272     // TODO: implement localToWorld and worldToLocal
6273     //       but keep in mind it won't be the same math if player is ragdolled or something
6274     //       - localToWorldStanding / worldToLocalStanding (or crouching or...?)
6275     //       then comb through code for places where to use it
6276
6277     // point = localToWorld(jointPos(leftfoot))
6278     point = DoRotation(p->jointPos(leftfoot), 0, p->yaw, 0) * p->scale + p->coords;
6279     // adjust height of foot
6280     heightleft = terrain.getHeight(point.x, point.z) + .04;
6281     point.y = heightleft;
6282     change = p->jointPos(leftankle) - p->jointPos(leftfoot);
6283     change2 = p->jointPos(leftknee) - p->jointPos(leftfoot);
6284     // jointPos(leftfoot) = interpolate(worldToLocal(point), jointPos(leftfoot), interp)
6285     p->jointPos(leftfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(leftfoot) * (1 - interp);
6286     // move ankle along with foot
6287     p->jointPos(leftankle) = p->jointPos(leftfoot) + change;
6288     // average knee pos between old and new pos
6289     p->jointPos(leftknee) = (p->jointPos(leftfoot) + change2) / 2 + (p->jointPos(leftknee)) / 2;
6290
6291     // do same as above for right leg
6292     point = DoRotation(p->jointPos(rightfoot), 0, p->yaw, 0) * p->scale + p->coords;
6293     heightright = terrain.getHeight(point.x, point.z) + .04;
6294     point.y = heightright;
6295     change = p->jointPos(rightankle) - p->jointPos(rightfoot);
6296     change2 = p->jointPos(rightknee) - p->jointPos(rightfoot);
6297     p->jointPos(rightfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(rightfoot) * (1 - interp);
6298     p->jointPos(rightankle) = p->jointPos(rightfoot) + change;
6299     p->jointPos(rightknee) = (p->jointPos(rightfoot) + change2) / 2 + (p->jointPos(rightknee)) / 2;
6300
6301     // fix up skeleton now that we've moved body parts?
6302     p->skeleton.DoConstraints(&p->coords, &p->scale);
6303 }
6304
6305 /* EFFECT
6306  * MONSTER
6307  * TODO: ???
6308  */
6309 int Person::DrawSkeleton()
6310 {
6311     int oldplayerdetail;
6312     if ((frustum.SphereInFrustum(coords.x, coords.y + scale * 3, coords.z, scale * 8) && distsq(&viewer, &coords) < viewdistance * viewdistance) || skeleton.free == 3) {
6313         if (onterrain && (isIdle() || isCrouch() || wasIdle() || wasCrouch()) && !skeleton.free) {
6314             calcrot = 1;
6315         }
6316
6317         if (headless) {
6318             headmorphness = 0;
6319             headmorphstart = 6;
6320             headmorphend = 6;
6321         }
6322
6323         glAlphaFunc(GL_GREATER, 0.0001);
6324         XYZ terrainlight;
6325         float terrainheight;
6326         float distance;
6327         if (!isnormal(yaw)) {
6328             yaw = 0;
6329         }
6330         if (!isnormal(tilt)) {
6331             tilt = 0;
6332         }
6333         if (!isnormal(tilt2)) {
6334             tilt2 = 0;
6335         }
6336         oldplayerdetail = playerdetail;
6337         playerdetail = 0;
6338         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 32 && detail == 2) {
6339             playerdetail = 1;
6340         }
6341         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 128 && detail == 1) {
6342             playerdetail = 1;
6343         }
6344         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 256 && (detail != 1 && detail != 2)) {
6345             playerdetail = 1;
6346         }
6347         if (id == 0) {
6348             playerdetail = 1;
6349         }
6350         if (playerdetail != oldplayerdetail) {
6351             updatedelay = 0;
6352             normalsupdatedelay = 0;
6353         }
6354         static float updatedelaychange;
6355         static float morphness;
6356         static float framemult;
6357         if (calcrot) {
6358             skeleton.FindForwards();
6359             if (howactive == typesittingwall) {
6360                 skeleton.specialforward[1] = 0;
6361                 skeleton.specialforward[1].z = 1;
6362             }
6363         }
6364         static XYZ mid;
6365         static float M[16];
6366         static int k;
6367         static int weaponattachmuscle;
6368         static int weaponrotatemuscle;
6369         static XYZ weaponpoint;
6370         static int start, endthing;
6371         if ((dead != 2 || skeleton.free != 2) && updatedelay <= 0) {
6372             if (!isSleeping() && !isSitting()) {
6373                 // TODO: give these meaningful names
6374                 const bool cond1 = (isIdle() || isCrouch() || isLanding() || isLandhard() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim);
6375                 const bool cond2 = (wasIdle() || wasCrouch() || wasLanding() || wasLandhard() || animCurrent == drawrightanim || animCurrent == drawleftanim || animCurrent == crouchdrawrightanim);
6376
6377                 if (onterrain && (cond1 && cond2) && !skeleton.free) {
6378                     IKHelper(this, 1);
6379                     if (creature == wolftype) {
6380                         IKHelper(this, 1);
6381                     }
6382                 }
6383
6384                 if (onterrain && (cond1 && !cond2) && !skeleton.free) {
6385                     IKHelper(this, target);
6386                     if (creature == wolftype) {
6387                         IKHelper(this, target);
6388                     }
6389                 }
6390
6391                 if (onterrain && (!cond1 && cond2) && !skeleton.free) {
6392                     IKHelper(this, 1 - target);
6393                     if (creature == wolftype) {
6394                         IKHelper(this, 1 - target);
6395                     }
6396                 }
6397             }
6398
6399             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())) {
6400                 DoHead();
6401             } else {
6402                 targetheadyaw = -targetyaw;
6403                 targetheadpitch = 0;
6404                 if (Animation::animations[animTarget].attack == 3) {
6405                     targetheadyaw += 180;
6406                 }
6407             }
6408             for (int i = 0; i < skeleton.drawmodel.vertexNum; i++) {
6409                 skeleton.drawmodel.vertex[i] = 0;
6410                 skeleton.drawmodel.vertex[i].y = 999;
6411             }
6412             for (int i = 0; i < skeleton.drawmodellow.vertexNum; i++) {
6413                 skeleton.drawmodellow.vertex[i] = 0;
6414                 skeleton.drawmodellow.vertex[i].y = 999;
6415             }
6416             for (int i = 0; i < skeleton.drawmodelclothes.vertexNum; i++) {
6417                 skeleton.drawmodelclothes.vertex[i] = 0;
6418                 skeleton.drawmodelclothes.vertex[i].y = 999;
6419             }
6420             for (unsigned int i = 0; i < skeleton.muscles.size(); i++) {
6421                 // convenience renames
6422                 const int p1 = skeleton.muscles[i].parent1->label;
6423                 const int p2 = skeleton.muscles[i].parent2->label;
6424
6425                 if ((skeleton.muscles[i].vertices.size() > 0 && playerdetail) || (skeleton.muscles[i].verticeslow.size() > 0 && !playerdetail)) {
6426                     morphness = 0;
6427                     start = 0;
6428                     endthing = 0;
6429
6430                     if (p1 == righthand || p2 == righthand) {
6431                         morphness = righthandmorphness;
6432                         start = righthandmorphstart;
6433                         endthing = righthandmorphend;
6434                     }
6435                     if (p1 == lefthand || p2 == lefthand) {
6436                         morphness = lefthandmorphness;
6437                         start = lefthandmorphstart;
6438                         endthing = lefthandmorphend;
6439                     }
6440                     if (p1 == head || p2 == head) {
6441                         morphness = headmorphness;
6442                         start = headmorphstart;
6443                         endthing = headmorphend;
6444                     }
6445                     if ((p1 == neck && p2 == abdomen) || (p2 == neck && p1 == abdomen)) {
6446                         morphness = chestmorphness;
6447                         start = chestmorphstart;
6448                         endthing = chestmorphend;
6449                     }
6450                     if ((p1 == groin && p2 == abdomen) || (p2 == groin && p1 == abdomen)) {
6451                         morphness = tailmorphness;
6452                         start = tailmorphstart;
6453                         endthing = tailmorphend;
6454                     }
6455                     if (calcrot) {
6456                         skeleton.FindRotationMuscle(i, animTarget);
6457                     }
6458                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
6459                     glMatrixMode(GL_MODELVIEW);
6460                     glPushMatrix();
6461                     glLoadIdentity();
6462                     if (!skeleton.free) {
6463                         glRotatef(tilt2, 1, 0, 0);
6464                     }
6465                     if (!skeleton.free) {
6466                         glRotatef(tilt, 0, 0, 1);
6467                     }
6468
6469                     glTranslatef(mid.x, mid.y, mid.z);
6470
6471                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
6472                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
6473
6474                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
6475                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
6476
6477                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
6478                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
6479
6480                     if (playerdetail || skeleton.free == 3) {
6481                         for (unsigned j = 0; j < skeleton.muscles[i].vertices.size(); j++) {
6482                             XYZ& v0 = skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]];
6483                             XYZ& v1 = skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]];
6484                             glMatrixMode(GL_MODELVIEW);
6485                             glPushMatrix();
6486                             if (p1 == abdomen || p2 == abdomen) {
6487                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(1).x,
6488                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(1).y,
6489                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(1).z);
6490                             }
6491                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6492                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(2).x,
6493                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(2).y,
6494                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(2).z);
6495                             }
6496                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6497                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(3).x,
6498                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(3).y,
6499                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(3).z);
6500                             }
6501                             if (p1 == head || p2 == head) {
6502                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(0).x,
6503                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(0).y,
6504                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(0).z);
6505                             }
6506                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
6507                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
6508                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y = M[13] * scale;
6509                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z = M[14] * scale;
6510                             glPopMatrix();
6511                         }
6512                     }
6513                     if (!playerdetail || skeleton.free == 3) {
6514                         for (unsigned j = 0; j < skeleton.muscles[i].verticeslow.size(); j++) {
6515                             XYZ& v0 = skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]];
6516                             glMatrixMode(GL_MODELVIEW);
6517                             glPushMatrix();
6518                             if (p1 == abdomen || p2 == abdomen) {
6519                                 glTranslatef(v0.x * getProportionXYZ(1).x,
6520                                              v0.y * getProportionXYZ(1).y,
6521                                              v0.z * getProportionXYZ(1).z);
6522                             }
6523                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6524                                 glTranslatef(v0.x * getProportionXYZ(2).x,
6525                                              v0.y * getProportionXYZ(2).y,
6526                                              v0.z * getProportionXYZ(2).z);
6527                             }
6528                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6529                                 glTranslatef(v0.x * getProportionXYZ(3).x,
6530                                              v0.y * getProportionXYZ(3).y,
6531                                              v0.z * getProportionXYZ(3).z);
6532                             }
6533                             if (p1 == head || p2 == head) {
6534                                 glTranslatef(v0.x * getProportionXYZ(0).x,
6535                                              v0.y * getProportionXYZ(0).y,
6536                                              v0.z * getProportionXYZ(0).z);
6537                             }
6538
6539                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
6540                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x = M[12] * scale;
6541                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y = M[13] * scale;
6542                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z = M[14] * scale;
6543                             glPopMatrix();
6544                         }
6545                     }
6546                     glPopMatrix();
6547                 }
6548                 if (skeleton.clothes && skeleton.muscles[i].verticesclothes.size() > 0) {
6549                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
6550
6551                     glMatrixMode(GL_MODELVIEW);
6552                     glPushMatrix();
6553                     glLoadIdentity();
6554                     if (!skeleton.free) {
6555                         glRotatef(tilt2, 1, 0, 0);
6556                     }
6557                     if (!skeleton.free) {
6558                         glRotatef(tilt, 0, 0, 1);
6559                     }
6560                     glTranslatef(mid.x, mid.y, mid.z);
6561                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
6562                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
6563
6564                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
6565                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
6566
6567                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
6568                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
6569
6570                     for (unsigned j = 0; j < skeleton.muscles[i].verticesclothes.size(); j++) {
6571                         XYZ& v0 = skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]];
6572                         glMatrixMode(GL_MODELVIEW);
6573                         glPushMatrix();
6574                         if (p1 == abdomen || p2 == abdomen) {
6575                             glTranslatef(v0.x * getProportionXYZ(1).x,
6576                                          v0.y * getProportionXYZ(1).y,
6577                                          v0.z * getProportionXYZ(1).z);
6578                         }
6579                         if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6580                             glTranslatef(v0.x * getProportionXYZ(2).x,
6581                                          v0.y * getProportionXYZ(2).y,
6582                                          v0.z * getProportionXYZ(2).z);
6583                         }
6584                         if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6585                             glTranslatef(v0.x * getProportionXYZ(3).x,
6586                                          v0.y * getProportionXYZ(3).y,
6587                                          v0.z * getProportionXYZ(3).z);
6588                         }
6589                         if (p1 == head || p2 == head) {
6590                             glTranslatef(v0.x * getProportionXYZ(0).x,
6591                                          v0.y * getProportionXYZ(0).y,
6592                                          v0.z * getProportionXYZ(0).z);
6593                         }
6594                         glGetFloatv(GL_MODELVIEW_MATRIX, M);
6595                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
6596                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y = M[13] * scale;
6597                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z = M[14] * scale;
6598                         glPopMatrix();
6599                     }
6600                     glPopMatrix();
6601                 }
6602                 updatedelay = 1 + (float)(Random() % 100) / 1000;
6603             }
6604             if (skeleton.free != 2 && (skeleton.free == 1 || skeleton.free == 3 || id == 0 || (normalsupdatedelay <= 0) || animTarget == getupfromfrontanim || animTarget == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == getupfrombackanim)) {
6605                 normalsupdatedelay = 1;
6606                 if (playerdetail || skeleton.free == 3) {
6607                     skeleton.drawmodel.CalculateNormals(0);
6608                 }
6609                 if (!playerdetail || skeleton.free == 3) {
6610                     skeleton.drawmodellow.CalculateNormals(0);
6611                 }
6612                 if (skeleton.clothes) {
6613                     skeleton.drawmodelclothes.CalculateNormals(0);
6614                 }
6615             } else {
6616                 if (playerdetail || skeleton.free == 3) {
6617                     skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
6618                 }
6619                 if (!playerdetail || skeleton.free == 3) {
6620                     skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
6621                 }
6622                 if (skeleton.clothes) {
6623                     skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
6624                 }
6625             }
6626         }
6627         framemult = .01;
6628         updatedelaychange = -framemult * 4 * (45 - findDistance(&viewer, &coords) * 1);
6629         if (updatedelaychange > -realmultiplier * 30) {
6630             updatedelaychange = -realmultiplier * 30;
6631         }
6632         if (updatedelaychange > -framemult * 4) {
6633             updatedelaychange = -framemult * 4;
6634         }
6635         if (skeleton.free == 1) {
6636             updatedelaychange *= 6;
6637         }
6638         if (id == 0) {
6639             updatedelaychange *= 8;
6640         }
6641         updatedelay += updatedelaychange;
6642
6643         glMatrixMode(GL_MODELVIEW);
6644         glPushMatrix();
6645         glTranslatef(coords.x, coords.y - .02, coords.z);
6646         if (!skeleton.free) {
6647             glTranslatef(offset.x * scale, offset.y * scale, offset.z * scale);
6648             glRotatef(yaw, 0, 1, 0);
6649         }
6650         if (showpoints) {
6651             glPointSize(5);
6652             glColor4f(.4, 1, .4, 1);
6653             glDisable(GL_LIGHTING);
6654             glDisable(GL_TEXTURE_2D);
6655             glBegin(GL_POINTS);
6656             if (playerdetail) {
6657                 for (int i = 0; i < skeleton.drawmodel.vertexNum; i++) {
6658                     XYZ& v0 = skeleton.drawmodel.vertex[i];
6659                     glVertex3f(v0.x, v0.y, v0.z);
6660                 }
6661             }
6662             glEnd();
6663             glBegin(GL_LINES);
6664
6665             if (playerdetail) {
6666                 for (unsigned int i = 0; i < skeleton.drawmodel.Triangles.size(); i++) {
6667                     const XYZ& v0 = skeleton.drawmodel.getTriangleVertex(i, 0);
6668                     const XYZ& v1 = skeleton.drawmodel.getTriangleVertex(i, 1);
6669                     const XYZ& v2 = skeleton.drawmodel.getTriangleVertex(i, 2);
6670                     glVertex3f(v0.x, v0.y, v0.z);
6671                     glVertex3f(v1.x, v1.y, v1.z);
6672                     glVertex3f(v1.x, v1.y, v1.z);
6673                     glVertex3f(v2.x, v2.y, v2.z);
6674                     glVertex3f(v2.x, v2.y, v2.z);
6675                     glVertex3f(v0.x, v0.y, v0.z);
6676                 }
6677             }
6678
6679             glEnd();
6680         }
6681
6682         terrainlight = terrain.getLighting(coords.x, coords.z);
6683         distance = distsq(&viewer, &coords);
6684         distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
6685         if (distance > 1) {
6686             distance = 1;
6687         }
6688         if (distance > 0) {
6689             terrainheight = (coords.y - terrain.getHeight(coords.x, coords.z)) / 3 + 1;
6690             if (terrainheight < 1) {
6691                 terrainheight = 1;
6692             }
6693             if (terrainheight > 1.7) {
6694                 terrainheight = 1.7;
6695             }
6696
6697             glColor4f((1 - (1 - terrainlight.x) / terrainheight) - burnt, (1 - (1 - terrainlight.y) / terrainheight) - burnt, (1 - (1 - terrainlight.z) / terrainheight) - burnt, distance);
6698             glDisable(GL_BLEND);
6699             glAlphaFunc(GL_GREATER, 0.0001);
6700             glEnable(GL_TEXTURE_2D);
6701             if (cellophane) {
6702                 glDisable(GL_TEXTURE_2D);
6703                 glColor4f(.7, .35, 0, .5);
6704                 glDepthMask(0);
6705                 glEnable(GL_LIGHTING);
6706                 glEnable(GL_BLEND);
6707             }
6708             if (Tutorial::active && id != 0) {
6709                 glColor4f(.7, .7, .7, 0.6);
6710                 glDepthMask(0);
6711                 glEnable(GL_LIGHTING);
6712                 glEnable(GL_BLEND);
6713                 if (canattack && cananger) {
6714                     if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
6715                         glDisable(GL_TEXTURE_2D);
6716                         glColor4f(1, 0, 0, 0.8);
6717                     }
6718                 }
6719                 glMatrixMode(GL_TEXTURE);
6720                 glPushMatrix();
6721                 glTranslatef(0, -smoketex, 0);
6722                 glTranslatef(-smoketex, 0, 0);
6723             }
6724             if (playerdetail) {
6725                 if (!showpoints) {
6726                     if (Tutorial::active && (id != 0)) {
6727                         skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6728                     } else {
6729                         skeleton.drawmodel.draw();
6730                     }
6731                 }
6732             }
6733             if (!playerdetail) {
6734                 if (Tutorial::active && (id != 0)) {
6735                     skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6736                 } else {
6737                     skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6738                 }
6739             }
6740
6741             if (!(Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed)) {
6742                 if (Tutorial::active && id != 0) {
6743                     glPopMatrix();
6744                     glMatrixMode(GL_MODELVIEW);
6745                     glEnable(GL_TEXTURE_2D);
6746                     glColor4f(.7, .7, .7, 0.6);
6747                     glDepthMask(0);
6748                     glEnable(GL_LIGHTING);
6749                     glEnable(GL_BLEND);
6750                     if (canattack && cananger) {
6751                         if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
6752                             glDisable(GL_TEXTURE_2D);
6753                             glColor4f(1, 0, 0, 0.8);
6754                         }
6755                     }
6756                     glMatrixMode(GL_TEXTURE);
6757                     glPushMatrix();
6758                     glTranslatef(0, -smoketex * .6, 0);
6759                     glTranslatef(smoketex * .6, 0, 0);
6760                     if (playerdetail) {
6761                         if (!showpoints) {
6762                             if (Tutorial::active && (id != 0)) {
6763                                 skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6764                             } else {
6765                                 skeleton.drawmodel.draw();
6766                             }
6767                         }
6768                     }
6769                     if (!playerdetail) {
6770                         if (Tutorial::active && (id != 0)) {
6771                             skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6772                         } else {
6773                             skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6774                         }
6775                     }
6776                 }
6777             }
6778
6779             if (Tutorial::active && id != 0) {
6780                 glPopMatrix();
6781                 glMatrixMode(GL_MODELVIEW);
6782                 glEnable(GL_TEXTURE_2D);
6783             }
6784             if (skeleton.clothes) {
6785                 glDepthMask(0);
6786                 glEnable(GL_BLEND);
6787                 if (!immediate) {
6788                     skeleton.drawmodelclothes.draw();
6789                 }
6790                 if (immediate) {
6791                     skeleton.drawmodelclothes.drawimmediate();
6792                 }
6793                 glDepthMask(1);
6794             }
6795         }
6796         glPopMatrix();
6797
6798         if (num_weapons > 0) {
6799             for (k = 0; k < num_weapons; k++) {
6800                 int i = weaponids[k];
6801                 if (weaponactive == k) {
6802                     if (weapons[i].getType() != staff) {
6803                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6804                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
6805                                 weaponattachmuscle = j;
6806                             }
6807                         }
6808                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6809                             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) {
6810                                 weaponrotatemuscle = j;
6811                             }
6812                         }
6813                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6814                         if (creature == wolftype) {
6815                             weaponpoint = (jointPos(rightwrist) * .7 + jointPos(righthand) * .3);
6816                         }
6817                     }
6818                     if (weapons[i].getType() == staff) {
6819                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6820                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
6821                                 weaponattachmuscle = j;
6822                             }
6823                         }
6824                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6825                             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) {
6826                                 weaponrotatemuscle = j;
6827                             }
6828                         }
6829                         //weaponpoint=jointPos(rightwrist);
6830                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6831                         //weaponpoint+=skeleton.specialforward[1]*.1+(jointPos(rightwrist)-jointPos(rightelbow));
6832                         XYZ tempnormthing, vec1, vec2;
6833                         vec1 = (jointPos(rightwrist) - jointPos(rightelbow));
6834                         vec2 = (jointPos(rightwrist) - jointPos(rightshoulder));
6835                         CrossProduct(&vec1, &vec2, &tempnormthing);
6836                         Normalise(&tempnormthing);
6837                         if (animTarget != staffhitanim && animCurrent != staffhitanim && animTarget != staffgroundsmashanim && animCurrent != staffgroundsmashanim && animTarget != staffspinhitanim && animCurrent != staffspinhitanim) {
6838                             weaponpoint += tempnormthing * .1 - skeleton.specialforward[1] * .3 + (jointPos(rightwrist) - jointPos(rightelbow));
6839                         }
6840                     }
6841                 }
6842                 if (weaponactive != k && weaponstuck != k) {
6843                     if (weapons[i].getType() == knife) {
6844                         weaponpoint = jointPos(abdomen) + (jointPos(righthip) - jointPos(lefthip)) * .1 + (jointPos(rightshoulder) - jointPos(leftshoulder)) * .35;
6845                     }
6846                     if (weapons[i].getType() == sword) {
6847                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6848                     }
6849                     if (weapons[i].getType() == staff) {
6850                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6851                     }
6852                     for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6853                         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) {
6854                             weaponrotatemuscle = j;
6855                         }
6856                     }
6857                 }
6858                 if (weaponstuck == k) {
6859                     if (weaponstuckwhere == 0) {
6860                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 - skeleton.forward * .8;
6861                     } else {
6862                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 + skeleton.forward * .8;
6863                     }
6864                     for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6865                         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) {
6866                             weaponrotatemuscle = j;
6867                         }
6868                     }
6869                 }
6870                 if (skeleton.free) {
6871                     weapons[i].position = weaponpoint * scale + coords;
6872                     weapons[i].bigrotation = 0;
6873                     weapons[i].bigtilt = 0;
6874                     weapons[i].bigtilt2 = 0;
6875                 } else {
6876                     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;
6877                     weapons[i].bigrotation = yaw;
6878                     weapons[i].bigtilt = tilt;
6879                     weapons[i].bigtilt2 = tilt2;
6880                 }
6881                 weapons[i].rotation1 = skeleton.muscles[weaponrotatemuscle].lastrotate1;
6882                 weapons[i].rotation2 = skeleton.muscles[weaponrotatemuscle].lastrotate2;
6883                 weapons[i].rotation3 = skeleton.muscles[weaponrotatemuscle].lastrotate3;
6884                 if (weaponactive == k) {
6885                     if (weapons[i].getType() == knife) {
6886                         weapons[i].smallrotation = 180;
6887                         weapons[i].smallrotation2 = 0;
6888                         if (isCrouch() || wasCrouch()) {
6889                             weapons[i].smallrotation2 = 20;
6890                         }
6891                         if (animTarget == hurtidleanim) {
6892                             weapons[i].smallrotation2 = 50;
6893                         }
6894                         if ((animCurrent == crouchstabanim && animTarget == crouchstabanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
6895                             XYZ temppoint1, temppoint2;
6896                             float distance;
6897
6898                             temppoint1 = jointPos(righthand);
6899                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6900                             distance = findDistance(&temppoint1, &temppoint2);
6901                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6902                             weapons[i].rotation2 *= 360 / 6.28;
6903                             temppoint1.y = 0;
6904                             temppoint2.y = 0;
6905                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6906                             weapons[i].rotation1 *= 360 / 6.28;
6907                             weapons[i].rotation3 = 0;
6908                             weapons[i].smallrotation = -90;
6909                             weapons[i].smallrotation2 = 0;
6910                             if (temppoint1.x > temppoint2.x) {
6911                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6912                             }
6913                         }
6914                         if ((animCurrent == knifeslashreversalanim && animTarget == knifeslashreversalanim) || (animCurrent == knifeslashreversedanim && animTarget == knifeslashreversedanim)) {
6915                             XYZ temppoint1, temppoint2;
6916                             float distance;
6917
6918                             temppoint1 = jointPos(righthand);
6919                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6920                             distance = findDistance(&temppoint1, &temppoint2);
6921                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6922                             weapons[i].rotation2 *= 360 / 6.28;
6923                             temppoint1.y = 0;
6924                             temppoint2.y = 0;
6925                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6926                             weapons[i].rotation1 *= 360 / 6.28;
6927                             weapons[i].rotation3 = 0;
6928                             weapons[i].smallrotation = 90;
6929                             weapons[i].smallrotation2 = 0;
6930                             if (temppoint1.x > temppoint2.x) {
6931                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6932                             }
6933                         }
6934                         if (animTarget == knifethrowanim) {
6935                             weapons[i].smallrotation = 90;
6936                             //weapons[i].smallrotation2=-90;
6937                             weapons[i].smallrotation2 = 0;
6938                             weapons[i].rotation1 = 0;
6939                             weapons[i].rotation2 = 0;
6940                             weapons[i].rotation3 = 0;
6941                         }
6942                         if (animTarget == knifesneakattackanim && frameTarget < 5) {
6943                             weapons[i].smallrotation = -90;
6944                             weapons[i].rotation1 = 0;
6945                             weapons[i].rotation2 = 0;
6946                             weapons[i].rotation3 = 0;
6947                         }
6948                     }
6949                     if (weapons[i].getType() == sword) {
6950                         weapons[i].smallrotation = 0;
6951                         weapons[i].smallrotation2 = 0;
6952                         if (animTarget == knifethrowanim) {
6953                             weapons[i].smallrotation = -90;
6954                             weapons[i].smallrotation2 = 0;
6955                             weapons[i].rotation1 = 0;
6956                             weapons[i].rotation2 = 0;
6957                             weapons[i].rotation3 = 0;
6958                         }
6959                         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)) {
6960                             XYZ temppoint1, temppoint2;
6961                             float distance;
6962
6963                             temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
6964                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6965                             distance = findDistance(&temppoint1, &temppoint2);
6966                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6967                             weapons[i].rotation2 *= 360 / 6.28;
6968                             temppoint1.y = 0;
6969                             temppoint2.y = 0;
6970                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6971                             weapons[i].rotation1 *= 360 / 6.28;
6972                             weapons[i].rotation3 = 0;
6973                             weapons[i].smallrotation = 90;
6974                             weapons[i].smallrotation2 = 0;
6975                             if (temppoint1.x > temppoint2.x) {
6976                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6977                             }
6978                         }
6979                     }
6980                     if (weapons[i].getType() == staff) {
6981                         weapons[i].smallrotation = 100;
6982                         weapons[i].smallrotation2 = 0;
6983                         if ((animTarget == staffhitanim && animCurrent == staffhitanim) || (animTarget == staffhitreversedanim && animCurrent == staffhitreversedanim) || (animTarget == staffspinhitreversedanim && animCurrent == staffspinhitreversedanim) || (animTarget == staffgroundsmashanim && animCurrent == staffgroundsmashanim) || (animTarget == staffspinhitanim && animCurrent == staffspinhitanim)) {
6984                             XYZ temppoint1, temppoint2;
6985                             float distance;
6986
6987                             temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
6988                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6989                             distance = findDistance(&temppoint1, &temppoint2);
6990                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6991                             weapons[i].rotation2 *= 360 / 6.28;
6992                             temppoint1.y = 0;
6993                             temppoint2.y = 0;
6994                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6995                             weapons[i].rotation1 *= 360 / 6.28;
6996                             weapons[i].rotation3 = 0;
6997                             weapons[i].smallrotation = 90;
6998                             weapons[i].smallrotation2 = 0;
6999                             if (temppoint1.x > temppoint2.x) {
7000                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
7001                             }
7002                         }
7003                     }
7004                 }
7005                 if (weaponactive != k && weaponstuck != k) {
7006                     if (weapons[i].getType() == knife) {
7007                         weapons[i].smallrotation = -70;
7008                         weapons[i].smallrotation2 = 10;
7009                     }
7010                     if (weapons[i].getType() == sword) {
7011                         weapons[i].smallrotation = -100;
7012                         weapons[i].smallrotation2 = -8;
7013                     }
7014                     if (weapons[i].getType() == staff) {
7015                         weapons[i].smallrotation = -100;
7016                         weapons[i].smallrotation2 = -8;
7017                     }
7018                 }
7019                 if (weaponstuck == k) {
7020                     if (weaponstuckwhere == 0) {
7021                         weapons[i].smallrotation = 180;
7022                     } else {
7023                         weapons[i].smallrotation = 0;
7024                     }
7025                     weapons[i].smallrotation2 = 10;
7026                 }
7027             }
7028         }
7029     }
7030
7031     calcrot = 0;
7032     if (skeleton.free) {
7033         calcrot = 1;
7034     }
7035     if (Animation::animations[animTarget].attack || isRun() || animTarget == staggerbackhardanim || isFlip() || animTarget == climbanim || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim || animTarget == backhandspringanim || isWallJump()) {
7036         calcrot = 1;
7037     }
7038     if (animCurrent != animTarget) {
7039         calcrot = 1;
7040     }
7041     if (skeleton.free == 2) {
7042         calcrot = 0;
7043     }
7044
7045     return 0;
7046 }
7047
7048 /* FUNCTION?
7049  */
7050 int Person::SphereCheck(XYZ* p1, float radius, XYZ* p, XYZ* move, float* rotate, Model* model)
7051 {
7052     static float distance;
7053     static float olddistance;
7054     static int intersecting;
7055     static int firstintersecting;
7056     static XYZ point;
7057     static XYZ oldp1;
7058     static XYZ start, end;
7059     static float slopethreshold = -.4;
7060
7061     firstintersecting = -1;
7062
7063     oldp1 = *p1;
7064     *p1 = *p1 - *move;
7065     if (distsq(p1, &model->boundingspherecenter) > radius * radius + model->boundingsphereradius * model->boundingsphereradius) {
7066         return -1;
7067     }
7068     if (*rotate) {
7069         *p1 = DoRotation(*p1, 0, -*rotate, 0);
7070     }
7071     for (int i = 0; i < 4; i++) {
7072         for (unsigned int j = 0; j < model->Triangles.size(); j++) {
7073             if (model->Triangles[j].facenormal.y <= slopethreshold) {
7074                 intersecting = 0;
7075                 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)));
7076                 if (distance < radius) {
7077                     point = *p1 - model->Triangles[j].facenormal * distance;
7078                     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]])) {
7079                         intersecting = 1;
7080                     }
7081                     if (!intersecting) {
7082                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
7083                                                                 &model->vertex[model->Triangles[j].vertex[1]],
7084                                                                 p1, &radius);
7085                     }
7086                     if (!intersecting) {
7087                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
7088                                                                 &model->vertex[model->Triangles[j].vertex[2]],
7089                                                                 p1, &radius);
7090                     }
7091                     if (!intersecting) {
7092                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
7093                                                                 &model->vertex[model->Triangles[j].vertex[2]],
7094                                                                 p1, &radius);
7095                     }
7096                     end = *p1 - point;
7097                     if (dotproduct(&model->Triangles[j].facenormal, &end) > 0 && intersecting) {
7098                         start = *p1;
7099                         end = *p1;
7100                         end.y -= radius;
7101                         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)) {
7102                             p1->y = point.y + radius;
7103                             if ((animTarget == jumpdownanim || isFlip())) {
7104                                 if (isFlip() && (frameTarget < 5 || targetFrame().label == 7 || targetFrame().label == 4)) {
7105                                     RagDoll(0);
7106                                 }
7107
7108                                 if (animTarget == jumpupanim) {
7109                                     jumppower = -4;
7110                                     animTarget = getIdle();
7111                                 }
7112                                 target = 0;
7113                                 frameTarget = 0;
7114                                 onterrain = 1;
7115
7116                                 if (id == 0) {
7117                                     pause_sound(whooshsound);
7118                                     OPENAL_SetVolume(channels[whooshsound], 0);
7119                                 }
7120
7121                                 if ((animTarget == jumpdownanim || isFlip()) && !wasLanding() && !wasLandhard()) {
7122                                     if (isFlip()) {
7123                                         jumppower = -4;
7124                                     }
7125                                     animTarget = getLanding();
7126                                     emit_sound_at(landsound, coords, 128.);
7127
7128                                     if (id == 0) {
7129                                         addEnvSound(coords);
7130                                     }
7131                                 }
7132                             }
7133                         }
7134                     }
7135                 }
7136                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
7137                     olddistance = distance;
7138                     firstintersecting = j;
7139                     *p = point;
7140                 }
7141             }
7142         }
7143         for (unsigned int j = 0; j < model->Triangles.size(); j++) {
7144             if (model->Triangles[j].facenormal.y > slopethreshold) {
7145                 intersecting = 0;
7146                 start = *p1;
7147                 start.y -= radius / 4;
7148                 XYZ& v0 = model->vertex[model->Triangles[j].vertex[0]];
7149                 XYZ& v1 = model->vertex[model->Triangles[j].vertex[1]];
7150                 XYZ& v2 = model->vertex[model->Triangles[j].vertex[2]];
7151                 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)));
7152                 if (distance < radius * .5) {
7153                     point = start - model->Triangles[j].facenormal * distance;
7154                     if (PointInTriangle(&point, model->Triangles[j].facenormal, &v0, &v1, &v2)) {
7155                         intersecting = 1;
7156                     }
7157                     if (!intersecting) {
7158                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, p1->x, p1->y, p1->z, radius / 2);
7159                     }
7160                     if (!intersecting) {
7161                         intersecting = sphere_line_intersection(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
7162                     }
7163                     if (!intersecting) {
7164                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
7165                     }
7166                     end = *p1 - point;
7167                     if (dotproduct(&model->Triangles[j].facenormal, &end) > 0 && intersecting) {
7168                         if ((animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
7169                             start = velocity;
7170                             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;
7171                             if (findLengthfast(&start) < findLengthfast(&velocity)) {
7172                                 velocity = start;
7173                             }
7174                         }
7175                         *p1 += model->Triangles[j].facenormal * (distance - radius * .5);
7176                     }
7177                 }
7178                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
7179                     olddistance = distance;
7180                     firstintersecting = j;
7181                     *p = point;
7182                 }
7183             }
7184         }
7185     }
7186     if (*rotate) {
7187         *p = DoRotation(*p, 0, *rotate, 0);
7188     }
7189     *p = *p + *move;
7190     if (*rotate) {
7191         *p1 = DoRotation(*p1, 0, *rotate, 0);
7192     }
7193     *p1 += *move;
7194     return firstintersecting;
7195 }
7196
7197 int findPathDist(int start, int end)
7198 {
7199     int connected;
7200     int closest;
7201
7202     unsigned int smallestcount = 1000;
7203     for (char i = 0; i < 50; i++) {
7204         unsigned int count = 0;
7205         int last = start;
7206         int last2 = -1;
7207         int last3 = -1;
7208         int last4 = -1;
7209         while (last != end && count < 30) {
7210             closest = -1;
7211             for (int j = 0; j < Game::numpathpoints; j++) {
7212                 if (j != last && j != last2 && j != last3 && j != last4) {
7213                     connected = 0;
7214                     if (Game::numpathpointconnect[j]) {
7215                         for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7216                             if (Game::pathpointconnect[j][k] == last) {
7217                                 connected = 1;
7218                             }
7219                         }
7220                     }
7221                     if (!connected) {
7222                         if (Game::numpathpointconnect[last]) {
7223                             for (int k = 0; k < Game::numpathpointconnect[last]; k++) {
7224                                 if (Game::pathpointconnect[last][k] == j) {
7225                                     connected = 1;
7226                                 }
7227                             }
7228                         }
7229                     }
7230                     if (connected) {
7231                         if (closest == -1 || Random() % 2 == 0) {
7232                             closest = j;
7233                         }
7234                     }
7235                 }
7236             }
7237             last4 = last3;
7238             last3 = last2;
7239             last2 = last;
7240             last = closest;
7241             count++;
7242         }
7243         if (count < smallestcount) {
7244             smallestcount = count;
7245         }
7246     }
7247     return smallestcount;
7248 }
7249
7250 void Person::takeWeapon(int weaponId)
7251 {
7252     weaponactive = 0;
7253     weapons[weaponId].owner = id;
7254     if (num_weapons > 0) {
7255         weaponids[num_weapons] = weaponids[0];
7256     }
7257     num_weapons++;
7258     weaponids[0] = weaponId;
7259 }
7260
7261 void Person::addClothes()
7262 {
7263     if (numclothes > 0) {
7264         for (int i = 0; i < numclothes; i++) {
7265             addClothes(i);
7266         }
7267         DoMipmaps();
7268     }
7269 }
7270
7271 bool Person::addClothes(const int& clothesId)
7272 {
7273     LOGFUNC;
7274     const std::string fileName = clothes[clothesId];
7275
7276     GLubyte* array = &skeleton.skinText[0];
7277
7278     //Load Image
7279     ImageRec texture;
7280     bool opened = load_image(Folders::getResourcePath(fileName).c_str(), texture);
7281
7282     float alphanum;
7283     //Is it valid?
7284     if (opened) {
7285         float tintr = clothestintr[clothesId];
7286         float tintg = clothestintg[clothesId];
7287         float tintb = clothestintb[clothesId];
7288
7289         if (tintr > 1) {
7290             tintr = 1;
7291         }
7292         if (tintg > 1) {
7293             tintg = 1;
7294         }
7295         if (tintb > 1) {
7296             tintb = 1;
7297         }
7298
7299         if (tintr < 0) {
7300             tintr = 0;
7301         }
7302         if (tintg < 0) {
7303             tintg = 0;
7304         }
7305         if (tintb < 0) {
7306             tintb = 0;
7307         }
7308
7309         int bytesPerPixel = texture.bpp / 8;
7310
7311         int tempnum = 0;
7312         alphanum = 255;
7313         for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
7314             if (bytesPerPixel == 3) {
7315                 alphanum = 255;
7316             } else if ((i + 1) % 4 == 0) {
7317                 alphanum = texture.data[i];
7318             }
7319             if ((i + 1) % 4 || bytesPerPixel == 3) {
7320                 if ((i % 4) == 0) {
7321                     texture.data[i] *= tintr;
7322                 }
7323                 if ((i % 4) == 1) {
7324                     texture.data[i] *= tintg;
7325                 }
7326                 if ((i % 4) == 2) {
7327                     texture.data[i] *= tintb;
7328                 }
7329                 array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
7330                 tempnum++;
7331             }
7332         }
7333         return 1;
7334     } else {
7335         return 0;
7336     }
7337 }
7338
7339 void Person::doAI()
7340 {
7341     if (aitype != playercontrolled && !Dialog::inDialog()) {
7342         jumpclimb = 0;
7343         //disable movement in editor
7344         if (Game::editorenabled) {
7345             stunned = 1;
7346         }
7347
7348         pause = 0;
7349         if (distsqflat(&Person::players[0]->coords, &coords) < 30 &&
7350             Person::players[0]->coords.y > coords.y + 2 &&
7351             !Person::players[0]->onterrain) {
7352             pause = 1;
7353         }
7354
7355         //pathfinding
7356         if (aitype == pathfindtype) {
7357             if (finalpathfindpoint == -1) {
7358                 float closestdistance;
7359                 float tempdist = 0.0f;
7360                 int closest;
7361                 XYZ colpoint;
7362                 closest = -1;
7363                 closestdistance = -1;
7364                 for (int j = 0; j < Game::numpathpoints; j++) {
7365                     if (closest == -1 || distsq(&finalfinaltarget, &Game::pathpoint[j]) < closestdistance) {
7366                         closestdistance = distsq(&finalfinaltarget, &Game::pathpoint[j]);
7367                         closest = j;
7368                         finaltarget = Game::pathpoint[j];
7369                     }
7370                 }
7371                 finalpathfindpoint = closest;
7372                 for (int j = 0; j < Game::numpathpoints; j++) {
7373                     for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7374                         DistancePointLine(&finalfinaltarget, &Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]], &tempdist, &colpoint);
7375                         if (sq(tempdist) < closestdistance) {
7376                             if (findDistance(&colpoint, &Game::pathpoint[j]) + findDistance(&colpoint, &Game::pathpoint[Game::pathpointconnect[j][k]]) <
7377                                 findDistance(&Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]]) + .1) {
7378                                 closestdistance = sq(tempdist);
7379                                 closest = j;
7380                                 finaltarget = colpoint;
7381                             }
7382                         }
7383                     }
7384                 }
7385                 finalpathfindpoint = closest;
7386             }
7387             if (targetpathfindpoint == -1) {
7388                 float closestdistance;
7389                 float tempdist = 0.0f;
7390                 int closest;
7391                 XYZ colpoint;
7392                 closest = -1;
7393                 closestdistance = -1;
7394                 if (lastpathfindpoint == -1) {
7395                     for (int j = 0; j < Game::numpathpoints; j++) {
7396                         if (j != lastpathfindpoint) {
7397                             if (closest == -1 || (distsq(&coords, &Game::pathpoint[j]) < closestdistance)) {
7398                                 closestdistance = distsq(&coords, &Game::pathpoint[j]);
7399                                 closest = j;
7400                             }
7401                         }
7402                     }
7403                     targetpathfindpoint = closest;
7404                     for (int j = 0; j < Game::numpathpoints; j++) {
7405                         if (j != lastpathfindpoint) {
7406                             for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7407                                 DistancePointLine(&coords, &Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]], &tempdist, &colpoint);
7408                                 if (sq(tempdist) < closestdistance) {
7409                                     if (findDistance(&colpoint, &Game::pathpoint[j]) + findDistance(&colpoint, &Game::pathpoint[Game::pathpointconnect[j][k]]) <
7410                                         findDistance(&Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]]) + .1) {
7411                                         closestdistance = sq(tempdist);
7412                                         closest = j;
7413                                     }
7414                                 }
7415                             }
7416                         }
7417                     }
7418                     targetpathfindpoint = closest;
7419                 } else {
7420                     for (int j = 0; j < Game::numpathpoints; j++) {
7421                         if (j != lastpathfindpoint &&
7422                             j != lastpathfindpoint2 &&
7423                             j != lastpathfindpoint3 &&
7424                             j != lastpathfindpoint4) {
7425                             bool connected = 0;
7426                             if (Game::numpathpointconnect[j]) {
7427                                 for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7428                                     if (Game::pathpointconnect[j][k] == lastpathfindpoint) {
7429                                         connected = 1;
7430                                     }
7431                                 }
7432                             }
7433                             if (!connected) {
7434                                 if (Game::numpathpointconnect[lastpathfindpoint]) {
7435                                     for (int k = 0; k < Game::numpathpointconnect[lastpathfindpoint]; k++) {
7436                                         if (Game::pathpointconnect[lastpathfindpoint][k] == j) {
7437                                             connected = 1;
7438                                         }
7439                                     }
7440                                 }
7441                             }
7442                             if (connected) {
7443                                 tempdist = findPathDist(j, finalpathfindpoint);
7444                                 if (closest == -1 || tempdist < closestdistance) {
7445                                     closestdistance = tempdist;
7446                                     closest = j;
7447                                 }
7448                             }
7449                         }
7450                     }
7451                     targetpathfindpoint = closest;
7452                 }
7453             }
7454             losupdatedelay -= multiplier;
7455
7456             targetyaw = roughDirectionTo(coords, Game::pathpoint[targetpathfindpoint]);
7457             lookyaw = targetyaw;
7458
7459             //reached target point
7460             if (distsqflat(&coords, &Game::pathpoint[targetpathfindpoint]) < .6) {
7461                 lastpathfindpoint4 = lastpathfindpoint3;
7462                 lastpathfindpoint3 = lastpathfindpoint2;
7463                 lastpathfindpoint2 = lastpathfindpoint;
7464                 lastpathfindpoint = targetpathfindpoint;
7465                 if (lastpathfindpoint2 == -1) {
7466                     lastpathfindpoint2 = lastpathfindpoint;
7467                 }
7468                 if (lastpathfindpoint3 == -1) {
7469                     lastpathfindpoint3 = lastpathfindpoint2;
7470                 }
7471                 if (lastpathfindpoint4 == -1) {
7472                     lastpathfindpoint4 = lastpathfindpoint3;
7473                 }
7474                 targetpathfindpoint = -1;
7475             }
7476             if (distsqflat(&coords, &finalfinaltarget) <
7477                     distsqflat(&coords, &finaltarget) ||
7478                 distsqflat(&coords, &finaltarget) < .6 * sq(scale * 5) ||
7479                 lastpathfindpoint == finalpathfindpoint) {
7480                 aitype = passivetype;
7481             }
7482
7483             forwardkeydown = 1;
7484             leftkeydown = 0;
7485             backkeydown = 0;
7486             rightkeydown = 0;
7487             crouchkeydown = 0;
7488             attackkeydown = 0;
7489             throwkeydown = 0;
7490
7491             if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7492                 targetyaw += 90 * (whichdirection * 2 - 1);
7493             }
7494
7495             if (collided < 1 || animTarget != jumpupanim) {
7496                 jumpkeydown = 0;
7497             }
7498             if ((collided > .8 && jumppower >= 5)) {
7499                 jumpkeydown = 1;
7500             }
7501
7502             if ((!Tutorial::active || cananger) &&
7503                 hostile &&
7504                 !Person::players[0]->dead &&
7505                 distsq(&coords, &Person::players[0]->coords) < 400 &&
7506                 occluded < 25) {
7507                 if (distsq(&coords, &Person::players[0]->coords) < 12 &&
7508                     Animation::animations[Person::players[0]->animTarget].height != lowheight &&
7509                     !Game::editorenabled &&
7510                     (Person::players[0]->coords.y < coords.y + 5 || Person::players[0]->onterrain)) {
7511                     aitype = attacktypecutoff;
7512                 }
7513                 if (distsq(&coords, &Person::players[0]->coords) < 30 &&
7514                     Animation::animations[Person::players[0]->animTarget].height == highheight &&
7515                     !Game::editorenabled) {
7516                     aitype = attacktypecutoff;
7517                 }
7518
7519                 if (losupdatedelay < 0 && !Game::editorenabled && occluded < 2) {
7520                     losupdatedelay = .2;
7521                     for (unsigned j = 0; j < Person::players.size(); j++) {
7522                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
7523                             if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0) {
7524                                 if (distsq(&coords, &Person::players[j]->coords) < 400) {
7525                                     if (normaldotproduct(facing, Person::players[j]->coords - coords) > 0) {
7526                                         if (Person::players[j]->coords.y < coords.y + 5 || Person::players[j]->onterrain) {
7527                                             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) ||
7528                                                 (Person::players[j]->animTarget == hanganim &&
7529                                                  normaldotproduct(Person::players[j]->facing, coords - Person::players[j]->coords) < 0)) {
7530                                                 aitype = searchtype;
7531                                                 lastchecktime = 12;
7532                                                 lastseen = Person::players[j]->coords;
7533                                                 lastseentime = 12;
7534                                             }
7535                                         }
7536                                     }
7537                                 }
7538                             }
7539                         }
7540                     }
7541                 }
7542             }
7543             if (aitype == attacktypecutoff && Game::musictype != 2) {
7544                 if (creature != wolftype) {
7545                     stunned = .6;
7546                     surprised = .6;
7547                 }
7548             }
7549         }
7550
7551         if (aitype != passivetype && Game::leveltime > .5) {
7552             howactive = typeactive;
7553         }
7554
7555         if (aitype == passivetype) {
7556             aiupdatedelay -= multiplier;
7557             losupdatedelay -= multiplier;
7558             lastseentime += multiplier;
7559             pausetime -= multiplier;
7560             if (lastseentime > 1) {
7561                 lastseentime = 1;
7562             }
7563
7564             if (aiupdatedelay < 0) {
7565                 if (numwaypoints > 1 && howactive == typeactive && pausetime <= 0) {
7566                     targetyaw = roughDirectionTo(coords, waypoints[waypoint]);
7567                     lookyaw = targetyaw;
7568                     aiupdatedelay = .05;
7569
7570                     if (distsqflat(&coords, &waypoints[waypoint]) < 1) {
7571                         if (waypointtype[waypoint] == wppause) {
7572                             pausetime = 4;
7573                         }
7574                         waypoint++;
7575                         if (waypoint > numwaypoints - 1) {
7576                             waypoint = 0;
7577                         }
7578                     }
7579                 }
7580
7581                 if (numwaypoints > 1 && howactive == typeactive && pausetime <= 0) {
7582                     forwardkeydown = 1;
7583                 } else {
7584                     forwardkeydown = 0;
7585                 }
7586                 leftkeydown = 0;
7587                 backkeydown = 0;
7588                 rightkeydown = 0;
7589                 crouchkeydown = 0;
7590                 attackkeydown = 0;
7591                 throwkeydown = 0;
7592
7593                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7594                     if (!avoidsomething) {
7595                         targetyaw += 90 * (whichdirection * 2 - 1);
7596                     } else {
7597                         XYZ leftpos, rightpos;
7598                         float leftdist, rightdist;
7599                         leftpos = coords + DoRotation(facing, 0, 90, 0);
7600                         rightpos = coords - DoRotation(facing, 0, 90, 0);
7601                         leftdist = distsq(&leftpos, &avoidwhere);
7602                         rightdist = distsq(&rightpos, &avoidwhere);
7603                         if (leftdist < rightdist) {
7604                             targetyaw += 90;
7605                         } else {
7606                             targetyaw -= 90;
7607                         }
7608                     }
7609                 }
7610             }
7611             if (collided < 1 || animTarget != jumpupanim) {
7612                 jumpkeydown = 0;
7613             }
7614             if ((collided > .8 && jumppower >= 5)) {
7615                 jumpkeydown = 1;
7616             }
7617
7618             //hearing sounds
7619             if (!Game::editorenabled) {
7620                 if (howactive <= typesleeping) {
7621                     if (numenvsounds > 0 && (!Tutorial::active || cananger) && hostile) {
7622                         for (int j = 0; j < numenvsounds; j++) {
7623                             float vol = howactive == typesleeping ? envsoundvol[j] - 14 : envsoundvol[j];
7624                             if (vol > 0 && distsq(&coords, &envsound[j]) < 2 * (vol + vol * (creature == rabbittype) * 3)) {
7625                                 aitype = attacktypecutoff;
7626                             }
7627                         }
7628                     }
7629                 }
7630
7631                 if (aitype != passivetype) {
7632                     if (howactive == typesleeping) {
7633                         setTargetAnimation(getupfromfrontanim);
7634                     }
7635                     howactive = typeactive;
7636                 }
7637             }
7638
7639             if (howactive < typesleeping &&
7640                 ((!Tutorial::active || cananger) && hostile) &&
7641                 !Person::players[0]->dead &&
7642                 distsq(&coords, &Person::players[0]->coords) < 400 &&
7643                 occluded < 25) {
7644                 if (distsq(&coords, &Person::players[0]->coords) < 12 &&
7645                     Animation::animations[Person::players[0]->animTarget].height != lowheight && !Game::editorenabled) {
7646                     aitype = attacktypecutoff;
7647                 }
7648                 if (distsq(&coords, &Person::players[0]->coords) < 30 &&
7649                     Animation::animations[Person::players[0]->animTarget].height == highheight && !Game::editorenabled) {
7650                     aitype = attacktypecutoff;
7651                 }
7652
7653                 //wolf smell
7654                 if (creature == wolftype) {
7655                     XYZ windsmell;
7656                     for (unsigned j = 0; j < Person::players.size(); j++) {
7657                         if (j == 0 || (Person::players[j]->dead && Person::players[j]->bloodloss > 0)) {
7658                             float smelldistance = 50;
7659                             if (j == 0 && Person::players[j]->num_weapons > 0) {
7660                                 if (weapons[Person::players[j]->weaponids[0]].bloody) {
7661                                     smelldistance = 100;
7662                                 }
7663                                 if (Person::players[j]->num_weapons == 2) {
7664                                     if (weapons[Person::players[j]->weaponids[1]].bloody) {
7665                                         smelldistance = 100;
7666                                     }
7667                                 }
7668                             }
7669                             if (j != 0) {
7670                                 smelldistance = 100;
7671                             }
7672                             windsmell = windvector;
7673                             Normalise(&windsmell);
7674                             windsmell = windsmell * 2 + Person::players[j]->coords;
7675                             if (distsq(&coords, &windsmell) < smelldistance && !Game::editorenabled) {
7676                                 aitype = attacktypecutoff;
7677                             }
7678                         }
7679                     }
7680                 }
7681
7682                 if (howactive < typesleeping && losupdatedelay < 0 && !Game::editorenabled && occluded < 2) {
7683                     losupdatedelay = .2;
7684                     for (unsigned j = 0; j < Person::players.size(); j++) {
7685                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
7686                             if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0) {
7687                                 if (distsq(&coords, &Person::players[j]->coords) < 400) {
7688                                     if (normaldotproduct(facing, Person::players[j]->coords - coords) > 0) {
7689                                         if ((-1 == Object::checkcollide(
7690                                                        DoRotation(jointPos(head), 0, yaw, 0) *
7691                                                                scale +
7692                                                            coords,
7693                                                        DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0) *
7694                                                                Person::players[j]->scale +
7695                                                            Person::players[j]->coords) &&
7696                                              !Person::players[j]->isWallJump()) ||
7697                                             (Person::players[j]->animTarget == hanganim &&
7698                                              normaldotproduct(Person::players[j]->facing, coords - Person::players[j]->coords) < 0)) {
7699                                             lastseentime -= .2;
7700                                             if (j == 0 && Animation::animations[Person::players[j]->animTarget].height == lowheight) {
7701                                                 lastseentime -= .4;
7702                                             } else {
7703                                                 lastseentime -= .6;
7704                                             }
7705                                         }
7706                                     }
7707                                 }
7708                             }
7709                             if (lastseentime <= 0) {
7710                                 aitype = searchtype;
7711                                 lastchecktime = 12;
7712                                 lastseen = Person::players[j]->coords;
7713                                 lastseentime = 12;
7714                             }
7715                         }
7716                     }
7717                 }
7718             }
7719             //alerted surprise
7720             if (aitype == attacktypecutoff && Game::musictype != 2) {
7721                 if (creature != wolftype) {
7722                     stunned = .6;
7723                     surprised = .6;
7724                 }
7725                 if (creature == wolftype) {
7726                     stunned = .47;
7727                     surprised = .47;
7728                 }
7729                 numseen++;
7730             }
7731         }
7732
7733         //search for player
7734         int j;
7735         if (aitype == searchtype) {
7736             aiupdatedelay -= multiplier;
7737             losupdatedelay -= multiplier;
7738             if (!pause) {
7739                 lastseentime -= multiplier;
7740             }
7741             lastchecktime -= multiplier;
7742
7743             if (isRun() && !onground) {
7744                 if (coords.y > terrain.getHeight(coords.x, coords.z) + 10) {
7745                     XYZ test2 = coords + facing;
7746                     test2.y += 5;
7747                     XYZ test = coords + facing;
7748                     test.y -= 10;
7749                     j = Object::checkcollide(test2, test, laststanding);
7750                     if (j == -1) {
7751                         j = Object::checkcollide(test2, test);
7752                     }
7753                     if (j == -1) {
7754                         velocity = 0;
7755                         setTargetAnimation(getStop());
7756                         targetyaw += 180;
7757                         stunned = .5;
7758                         //aitype=passivetype;
7759                         aitype = pathfindtype;
7760                         finalfinaltarget = waypoints[waypoint];
7761                         finalpathfindpoint = -1;
7762                         targetpathfindpoint = -1;
7763                         lastpathfindpoint = -1;
7764                         lastpathfindpoint2 = -1;
7765                         lastpathfindpoint3 = -1;
7766                         lastpathfindpoint4 = -1;
7767                     } else {
7768                         laststanding = j;
7769                     }
7770                 }
7771             }
7772             //check out last seen location
7773             if (aiupdatedelay < 0) {
7774                 targetyaw = roughDirectionTo(coords, lastseen);
7775                 lookyaw = targetyaw;
7776                 aiupdatedelay = .05;
7777                 forwardkeydown = 1;
7778
7779                 if (distsqflat(&coords, &lastseen) < 1 * sq(scale * 5) || lastchecktime < 0) {
7780                     forwardkeydown = 0;
7781                     aiupdatedelay = 1;
7782                     lastseen.x += (float(Random() % 100) - 50) / 25;
7783                     lastseen.z += (float(Random() % 100) - 50) / 25;
7784                     lastchecktime = 3;
7785                 }
7786
7787                 leftkeydown = 0;
7788                 backkeydown = 0;
7789                 rightkeydown = 0;
7790                 crouchkeydown = 0;
7791                 attackkeydown = 0;
7792                 throwkeydown = 0;
7793
7794                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7795                     if (!avoidsomething) {
7796                         targetyaw += 90 * (whichdirection * 2 - 1);
7797                     } else {
7798                         XYZ leftpos, rightpos;
7799                         float leftdist, rightdist;
7800                         leftpos = coords + DoRotation(facing, 0, 90, 0);
7801                         rightpos = coords - DoRotation(facing, 0, 90, 0);
7802                         leftdist = distsq(&leftpos, &avoidwhere);
7803                         rightdist = distsq(&rightpos, &avoidwhere);
7804                         if (leftdist < rightdist) {
7805                             targetyaw += 90;
7806                         } else {
7807                             targetyaw -= 90;
7808                         }
7809                     }
7810                 }
7811             }
7812             if (collided < 1 || animTarget != jumpupanim) {
7813                 jumpkeydown = 0;
7814             }
7815             if ((collided > .8 && jumppower >= 5)) {
7816                 jumpkeydown = 1;
7817             }
7818
7819             if (numenvsounds > 0 && ((!Tutorial::active || cananger) && hostile)) {
7820                 for (int k = 0; k < numenvsounds; k++) {
7821                     if (distsq(&coords, &envsound[k]) < 2 * (envsoundvol[k] + envsoundvol[k] * (creature == rabbittype) * 3)) {
7822                         aitype = attacktypecutoff;
7823                     }
7824                 }
7825             }
7826
7827             if (!Person::players[0]->dead &&
7828                 losupdatedelay < 0 &&
7829                 !Game::editorenabled &&
7830                 occluded < 2 &&
7831                 ((!Tutorial::active || cananger) && hostile)) {
7832                 losupdatedelay = .2;
7833                 if (distsq(&coords, &Person::players[0]->coords) < 4 && Animation::animations[animTarget].height != lowheight) {
7834                     aitype = attacktypecutoff;
7835                     lastseentime = 1;
7836                 }
7837                 if (abs(Random() % 2) || Animation::animations[animTarget].height != lowheight) {
7838                     //TODO: factor out canSeePlayer()
7839                     if (distsq(&coords, &Person::players[0]->coords) < 400) {
7840                         if (normaldotproduct(facing, Person::players[0]->coords - coords) > 0) {
7841                             if ((Object::checkcollide(
7842                                      DoRotation(jointPos(head), 0, yaw, 0) *
7843                                              scale +
7844                                          coords,
7845                                      DoRotation(Person::players[0]->jointPos(head), 0, Person::players[0]->yaw, 0) *
7846                                              Person::players[0]->scale +
7847                                          Person::players[0]->coords) == -1) ||
7848                                 (Person::players[0]->animTarget == hanganim && normaldotproduct(Person::players[0]->facing, coords - Person::players[0]->coords) < 0)) {
7849                                 /* //TODO: changed j to 0 on a whim, make sure this is correct
7850                                 (Person::players[j]->animTarget==hanganim&&normaldotproduct(
7851                                     Person::players[j]->facing,coords-Person::players[j]->coords)<0)
7852                                 */
7853                                 aitype = attacktypecutoff;
7854                                 lastseentime = 1;
7855                             }
7856                         }
7857                     }
7858                 }
7859             }
7860             //player escaped
7861             if (lastseentime < 0) {
7862                 //aitype=passivetype;
7863                 numescaped++;
7864                 aitype = pathfindtype;
7865                 finalfinaltarget = waypoints[waypoint];
7866                 finalpathfindpoint = -1;
7867                 targetpathfindpoint = -1;
7868                 lastpathfindpoint = -1;
7869                 lastpathfindpoint2 = -1;
7870                 lastpathfindpoint3 = -1;
7871                 lastpathfindpoint4 = -1;
7872             }
7873         }
7874
7875         if (aitype != gethelptype) {
7876             runninghowlong = 0;
7877         }
7878
7879         //get help from buddies
7880         if (aitype == gethelptype) {
7881             runninghowlong += multiplier;
7882             aiupdatedelay -= multiplier;
7883
7884             if (aiupdatedelay < 0 || ally == 0) {
7885                 aiupdatedelay = .2;
7886
7887                 //find closest ally
7888                 //TODO: factor out closest search somehow
7889                 if (!ally) {
7890                     int closest = -1;
7891                     float closestdist = -1;
7892                     for (unsigned k = 0; k < Person::players.size(); k++) {
7893                         if ((k != id) && (k != 0) && !Person::players[k]->dead &&
7894                             (Person::players[k]->howactive < typedead1) &&
7895                             !Person::players[k]->skeleton.free &&
7896                             (Person::players[k]->aitype == passivetype)) {
7897                             float distance = distsq(&coords, &Person::players[k]->coords);
7898                             if (closestdist == -1 || distance < closestdist) {
7899                                 closestdist = distance;
7900                                 closest = k;
7901                             }
7902                         }
7903                     }
7904                     if (closest != -1) {
7905                         ally = closest;
7906                     } else {
7907                         ally = 0;
7908                     }
7909                     lastseen = Person::players[0]->coords;
7910                     lastseentime = 12;
7911                 }
7912
7913                 lastchecktime = 12;
7914
7915                 XYZ facing = coords;
7916                 XYZ flatfacing = Person::players[ally]->coords;
7917                 facing.y += jointPos(head).y * scale;
7918                 flatfacing.y += Person::players[ally]->jointPos(head).y * Person::players[ally]->scale;
7919                 if (-1 != Object::checkcollide(facing, flatfacing)) {
7920                     lastseentime -= .1;
7921                 }
7922
7923                 //no available ally, run back to player
7924                 if (ally <= 0 ||
7925                     Person::players[ally]->skeleton.free ||
7926                     Person::players[ally]->aitype != passivetype ||
7927                     lastseentime <= 0) {
7928                     aitype = searchtype;
7929                     lastseentime = 12;
7930                 }
7931
7932                 //seek out ally
7933                 if (ally > 0) {
7934                     targetyaw = roughDirectionTo(coords, Person::players[ally]->coords);
7935                     lookyaw = targetyaw;
7936                     aiupdatedelay = .05;
7937                     forwardkeydown = 1;
7938
7939                     if (distsqflat(&coords, &Person::players[ally]->coords) < 3) {
7940                         aitype = searchtype;
7941                         lastseentime = 12;
7942                         Person::players[ally]->aitype = searchtype;
7943                         if (Person::players[ally]->lastseentime < lastseentime) {
7944                             Person::players[ally]->lastseen = lastseen;
7945                             Person::players[ally]->lastseentime = lastseentime;
7946                             Person::players[ally]->lastchecktime = lastchecktime;
7947                         }
7948                     }
7949
7950                     if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7951                         if (!avoidsomething) {
7952                             targetyaw += 90 * (whichdirection * 2 - 1);
7953                         } else {
7954                             XYZ leftpos, rightpos;
7955                             float leftdist, rightdist;
7956                             leftpos = coords + DoRotation(facing, 0, 90, 0);
7957                             rightpos = coords - DoRotation(facing, 0, 90, 0);
7958                             leftdist = distsq(&leftpos, &avoidwhere);
7959                             rightdist = distsq(&rightpos, &avoidwhere);
7960                             if (leftdist < rightdist) {
7961                                 targetyaw += 90;
7962                             } else {
7963                                 targetyaw -= 90;
7964                             }
7965                         }
7966                     }
7967                 }
7968
7969                 leftkeydown = 0;
7970                 backkeydown = 0;
7971                 rightkeydown = 0;
7972                 crouchkeydown = 0;
7973                 attackkeydown = 0;
7974             }
7975             if (collided < 1 || animTarget != jumpupanim) {
7976                 jumpkeydown = 0;
7977             }
7978             if (collided > .8 && jumppower >= 5) {
7979                 jumpkeydown = 1;
7980             }
7981         }
7982
7983         //retreiving a weapon on the ground
7984         if (aitype == getweapontype) {
7985             aiupdatedelay -= multiplier;
7986             lastchecktime -= multiplier;
7987
7988             if (aiupdatedelay < 0) {
7989                 aiupdatedelay = .2;
7990
7991                 //ALLY IS WEPON
7992                 if (ally < 0) {
7993                     int closest = -1;
7994                     float closestdist = -1;
7995                     for (unsigned k = 0; k < weapons.size(); k++) {
7996                         if (weapons[k].owner == -1) {
7997                             float distance = distsq(&coords, &weapons[k].position);
7998                             if (closestdist == -1 || distance < closestdist) {
7999                                 closestdist = distance;
8000                                 closest = k;
8001                             }
8002                         }
8003                     }
8004                     if (closest != -1) {
8005                         ally = closest;
8006                     } else {
8007                         ally = -1;
8008                     }
8009                 }
8010
8011                 lastseentime = 12;
8012
8013                 if (!Person::players[0]->dead && ((!Tutorial::active || cananger) && hostile)) {
8014                     if (ally < 0 || weaponactive != -1 || lastchecktime <= 0) {
8015                         aitype = attacktypecutoff;
8016                         lastseentime = 1;
8017                     }
8018                 }
8019                 if (!Person::players[0]->dead) {
8020                     if (ally >= 0) {
8021                         if (weapons[ally].owner != -1 ||
8022                             distsq(&coords, &weapons[ally].position) > 16) {
8023                             aitype = attacktypecutoff;
8024                             lastseentime = 1;
8025                         }
8026                         //TODO: factor these out as moveToward()
8027                         targetyaw = roughDirectionTo(coords, weapons[ally].position);
8028                         lookyaw = targetyaw;
8029                         aiupdatedelay = .05;
8030                         forwardkeydown = 1;
8031
8032                         if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
8033                             if (!avoidsomething) {
8034                                 targetyaw += 90 * (whichdirection * 2 - 1);
8035                             } else {
8036                                 XYZ leftpos, rightpos;
8037                                 float leftdist, rightdist;
8038                                 leftpos = coords + DoRotation(facing, 0, 90, 0);
8039                                 rightpos = coords - DoRotation(facing, 0, 90, 0);
8040                                 leftdist = distsq(&leftpos, &avoidwhere);
8041                                 rightdist = distsq(&rightpos, &avoidwhere);
8042                                 if (leftdist < rightdist) {
8043                                     targetyaw += 90;
8044                                 } else {
8045                                     targetyaw -= 90;
8046                                 }
8047                             }
8048                         }
8049                     }
8050                 }
8051
8052                 leftkeydown = 0;
8053                 backkeydown = 0;
8054                 rightkeydown = 0;
8055                 attackkeydown = 0;
8056                 throwkeydown = 1;
8057                 crouchkeydown = 0;
8058                 if (animTarget != crouchremoveknifeanim &&
8059                     animTarget != removeknifeanim) {
8060                     throwtogglekeydown = 0;
8061                 }
8062                 drawkeydown = 0;
8063             }
8064             if (collided < 1 || animTarget != jumpupanim) {
8065                 jumpkeydown = 0;
8066             }
8067             if ((collided > .8 && jumppower >= 5)) {
8068                 jumpkeydown = 1;
8069             }
8070         }
8071
8072         if (aitype == attacktypecutoff) {
8073             aiupdatedelay -= multiplier;
8074             //dodge or reverse rabbit kicks, knife throws, flips
8075             if (damage < damagetolerance * 2 / 3) {
8076                 if ((Person::players[0]->animTarget == rabbitkickanim ||
8077                      Person::players[0]->animTarget == knifethrowanim ||
8078                      (Person::players[0]->isFlip() &&
8079                       normaldotproduct(Person::players[0]->facing, Person::players[0]->coords - coords) < 0)) &&
8080                     !Person::players[0]->skeleton.free &&
8081                     (aiupdatedelay < .1)) {
8082                     attackkeydown = 0;
8083                     if (isIdle()) {
8084                         crouchkeydown = 1;
8085                     }
8086                     if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->weaponactive != -1) {
8087                         if (weapons[Person::players[0]->weaponids[0]].getType() == knife) {
8088                             if (isIdle() || isCrouch() || isRun() || isFlip()) {
8089                                 if (abs(Random() % 2) == 0) {
8090                                     setTargetAnimation(backhandspringanim);
8091                                 } else {
8092                                     setTargetAnimation(rollanim);
8093                                 }
8094                                 targetyaw += 90 * (abs(Random() % 2) * 2 - 1);
8095                                 wentforweapon = 0;
8096                             }
8097                             if (animTarget == jumpupanim || animTarget == jumpdownanim) {
8098                                 setTargetAnimation(flipanim);
8099                             }
8100                         }
8101                     }
8102                     forwardkeydown = 0;
8103                     aiupdatedelay = .02;
8104                 }
8105             }
8106             //get confused by flips
8107             if (Person::players[0]->isFlip() &&
8108                 !Person::players[0]->skeleton.free &&
8109                 Person::players[0]->animTarget != walljumprightkickanim &&
8110                 Person::players[0]->animTarget != walljumpleftkickanim) {
8111                 if (distsq(&Person::players[0]->coords, &coords) < 25) {
8112                     if ((1 - damage / damagetolerance) > .5) {
8113                         stunned = 1;
8114                     }
8115                 }
8116             }
8117             //go for weapon on the ground
8118             if (wentforweapon < 3) {
8119                 for (unsigned k = 0; k < weapons.size(); k++) {
8120                     if (creature != wolftype) {
8121                         if (num_weapons == 0 &&
8122                             weapons[k].owner == -1 &&
8123                             weapons[k].velocity.x == 0 &&
8124                             weapons[k].velocity.z == 0 &&
8125                             weapons[k].velocity.y == 0) {
8126                             if (distsq(&coords, &weapons[k].position) < 16) {
8127                                 wentforweapon++;
8128                                 lastchecktime = 6;
8129                                 aitype = getweapontype;
8130                                 ally = -1;
8131                             }
8132                         }
8133                     }
8134                 }
8135             }
8136             //dodge/reverse walljump kicks
8137             if (damage < damagetolerance / 2) {
8138                 if (Animation::animations[animTarget].height != highheight) {
8139                     if (damage < damagetolerance * .5 &&
8140                         ((Person::players[0]->animTarget == walljumprightkickanim ||
8141                           Person::players[0]->animTarget == walljumpleftkickanim) &&
8142                          ((aiupdatedelay < .15 &&
8143                            difficulty == 2) ||
8144                           (aiupdatedelay < .08 &&
8145                            difficulty != 2)))) {
8146                         crouchkeydown = 1;
8147                     }
8148                 }
8149             }
8150             //walked off a ledge (?)
8151             if (isRun() && !onground) {
8152                 if (coords.y > terrain.getHeight(coords.x, coords.z) + 10) {
8153                     XYZ test2 = coords + facing;
8154                     test2.y += 5;
8155                     XYZ test = coords + facing;
8156                     test.y -= 10;
8157                     j = Object::checkcollide(test2, test, laststanding);
8158                     if (j == -1) {
8159                         j = Object::checkcollide(test2, test);
8160                     }
8161                     if (j == -1) {
8162                         velocity = 0;
8163                         setTargetAnimation(getStop());
8164                         targetyaw += 180;
8165                         stunned = .5;
8166                         aitype = pathfindtype;
8167                         finalfinaltarget = waypoints[waypoint];
8168                         finalpathfindpoint = -1;
8169                         targetpathfindpoint = -1;
8170                         lastpathfindpoint = -1;
8171                         lastpathfindpoint2 = -1;
8172                         lastpathfindpoint3 = -1;
8173                         lastpathfindpoint4 = -1;
8174                     } else {
8175                         laststanding = j;
8176                     }
8177                 }
8178             }
8179             //lose sight of player in the air (?)
8180             if (Person::players[0]->coords.y > coords.y + 5 &&
8181                 Animation::animations[Person::players[0]->animTarget].height != highheight &&
8182                 !Person::players[0]->onterrain) {
8183                 aitype = pathfindtype;
8184                 finalfinaltarget = waypoints[waypoint];
8185                 finalpathfindpoint = -1;
8186                 targetpathfindpoint = -1;
8187                 lastpathfindpoint = -1;
8188                 lastpathfindpoint2 = -1;
8189                 lastpathfindpoint3 = -1;
8190                 lastpathfindpoint4 = -1;
8191             }
8192             //it's time to think (?)
8193             if (aiupdatedelay < 0 &&
8194                 !Animation::animations[animTarget].attack &&
8195                 animTarget != staggerbackhighanim &&
8196                 animTarget != staggerbackhardanim &&
8197                 animTarget != backhandspringanim &&
8198                 animTarget != dodgebackanim) {
8199                 //draw weapon
8200                 if (weaponactive == -1 && num_weapons > 0) {
8201                     drawkeydown = Random() % 2;
8202                 } else {
8203                     drawkeydown = 0;
8204                 }
8205                 rabbitkickenabled = Random() % 2;
8206                 //chase player
8207                 XYZ rotatetarget = Person::players[0]->coords + Person::players[0]->velocity;
8208                 XYZ targetpoint = Person::players[0]->coords;
8209                 float vellength = findLength(&velocity);
8210                 if (vellength != 0 &&
8211                     distsq(&Person::players[0]->coords, &coords) < distsq(&rotatetarget, &coords)) {
8212                     targetpoint += Person::players[0]->velocity *
8213                                    findDistance(&Person::players[0]->coords, &coords) / vellength;
8214                 }
8215                 targetyaw = roughDirectionTo(coords, targetpoint);
8216                 lookyaw = targetyaw;
8217                 aiupdatedelay = .2 + fabs((float)(Random() % 100) / 1000);
8218
8219                 if (distsq(&coords, &Person::players[0]->coords) > 5 && (Person::players[0]->weaponactive == -1 || weaponactive != -1)) {
8220                     forwardkeydown = 1;
8221                 } else if ((distsq(&coords, &Person::players[0]->coords) > 16 ||
8222                             distsq(&coords, &Person::players[0]->coords) < 9) &&
8223                            Person::players[0]->weaponactive != -1) {
8224                     forwardkeydown = 1;
8225                 } else if (Random() % 6 == 0 || (creature == wolftype && Random() % 3 == 0)) {
8226                     forwardkeydown = 1;
8227                 } else {
8228                     forwardkeydown = 0;
8229                 }
8230                 //chill out around the corpse
8231                 if (Person::players[0]->dead) {
8232                     forwardkeydown = 0;
8233                     if (Random() % 10 == 0) {
8234                         forwardkeydown = 1;
8235                     }
8236                     if (Random() % 100 == 0) {
8237                         aitype = pathfindtype;
8238                         finalfinaltarget = waypoints[waypoint];
8239                         finalpathfindpoint = -1;
8240                         targetpathfindpoint = -1;
8241                         lastpathfindpoint = -1;
8242                         lastpathfindpoint2 = -1;
8243                         lastpathfindpoint3 = -1;
8244                         lastpathfindpoint4 = -1;
8245                     }
8246                 }
8247                 leftkeydown = 0;
8248                 backkeydown = 0;
8249                 rightkeydown = 0;
8250                 crouchkeydown = 0;
8251                 throwkeydown = 0;
8252
8253                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
8254                     targetyaw += 90 * (whichdirection * 2 - 1);
8255                 }
8256                 //attack!!!
8257                 if (Random() % 2 == 0 || weaponactive != -1 || creature == wolftype) {
8258                     attackkeydown = 1;
8259                 } else {
8260                     attackkeydown = 0;
8261                 }
8262                 if (isRun() && Random() % 6 && distsq(&coords, &Person::players[0]->coords) > 7) {
8263                     attackkeydown = 0;
8264                 }
8265
8266                 //TODO: wat
8267                 if (aitype != playercontrolled &&
8268                     (isIdle() ||
8269                      isCrouch() ||
8270                      isRun())) {
8271                     int target = -2;
8272                     for (unsigned j = 0; j < Person::players.size(); j++) {
8273                         if (j != id && !Person::players[j]->skeleton.free &&
8274                             Person::players[j]->hasvictim &&
8275                             (Tutorial::active && reversaltrain ||
8276                              Random() % 2 == 0 && difficulty == 2 ||
8277                              Random() % 4 == 0 && difficulty == 1 ||
8278                              Random() % 8 == 0 && difficulty == 0 ||
8279                              Person::players[j]->lastattack2 == Person::players[j]->animTarget &&
8280                                  Person::players[j]->lastattack3 == Person::players[j]->animTarget &&
8281                                  (Random() % 2 == 0 || difficulty == 2) ||
8282                              (isIdle() || isRun()) &&
8283                                  Person::players[j]->weaponactive != -1 ||
8284                              Person::players[j]->animTarget == swordslashanim &&
8285                                  weaponactive != -1 ||
8286                              Person::players[j]->animTarget == staffhitanim ||
8287                              Person::players[j]->animTarget == staffspinhitanim)) {
8288                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 4 &&
8289                                 Person::players[j]->victim == Person::players[id] &&
8290                                 (Person::players[j]->animTarget == sweepanim ||
8291                                  Person::players[j]->animTarget == spinkickanim ||
8292                                  Person::players[j]->animTarget == staffhitanim ||
8293                                  Person::players[j]->animTarget == staffspinhitanim ||
8294                                  Person::players[j]->animTarget == winduppunchanim ||
8295                                  Person::players[j]->animTarget == upunchanim ||
8296                                  Person::players[j]->animTarget == wolfslapanim ||
8297                                  Person::players[j]->animTarget == knifeslashstartanim ||
8298                                  Person::players[j]->animTarget == swordslashanim &&
8299                                      (distsq(&Person::players[j]->coords, &coords) < 2 ||
8300                                       weaponactive != -1))) {
8301                                 if (target >= 0) {
8302                                     target = -1;
8303                                 } else {
8304                                     target = j;
8305                                 }
8306                             }
8307                         }
8308                     }
8309                     if (target >= 0) {
8310                         Person::players[target]->Reverse();
8311                     }
8312                 }
8313
8314                 if (collided < 1) {
8315                     jumpkeydown = 0;
8316                 }
8317                 if (collided > .8 && jumppower >= 5 ||
8318                     distsq(&coords, &Person::players[0]->coords) > 400 &&
8319                         onterrain &&
8320                         creature == rabbittype) {
8321                     jumpkeydown = 1;
8322                 }
8323                 //TODO: why are we controlling the human?
8324                 if (normaldotproduct(facing, Person::players[0]->coords - coords) > 0) {
8325                     Person::players[0]->jumpkeydown = 0;
8326                 }
8327                 if (Person::players[0]->animTarget == jumpdownanim &&
8328                     distsq(&Person::players[0]->coords, &coords) < 40) {
8329                     crouchkeydown = 1;
8330                 }
8331                 if (jumpkeydown) {
8332                     attackkeydown = 0;
8333                 }
8334
8335                 if (Tutorial::active) {
8336                     if (!canattack) {
8337                         attackkeydown = 0;
8338                     }
8339                 }
8340
8341                 XYZ facing = coords;
8342                 XYZ flatfacing = Person::players[0]->coords;
8343                 facing.y += jointPos(head).y * scale;
8344                 flatfacing.y += Person::players[0]->jointPos(head).y * Person::players[0]->scale;
8345                 if (occluded >= 2) {
8346                     if (-1 != Object::checkcollide(facing, flatfacing)) {
8347                         if (!pause) {
8348                             lastseentime -= .2;
8349                         }
8350                         if (lastseentime <= 0 &&
8351                             (creature != wolftype ||
8352                              weaponstuck == -1)) {
8353                             aitype = searchtype;
8354                             lastchecktime = 12;
8355                             lastseen = Person::players[0]->coords;
8356                             lastseentime = 12;
8357                         }
8358                     } else {
8359                         lastseentime = 1;
8360                     }
8361                 }
8362             }
8363         }
8364         if (Animation::animations[Person::players[0]->animTarget].height == highheight &&
8365             (aitype == attacktypecutoff ||
8366              aitype == searchtype)) {
8367             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
8368                 XYZ test = Person::players[0]->coords;
8369                 test.y -= 40;
8370                 if (-1 == Object::checkcollide(Person::players[0]->coords, test)) {
8371                     stunned = 1;
8372                 }
8373             }
8374         }
8375         //stunned
8376         if (aitype == passivetype && !(numwaypoints > 1) ||
8377             stunned > 0 ||
8378             pause && damage > superpermanentdamage) {
8379             if (pause) {
8380                 lastseentime = 1;
8381             }
8382             targetyaw = yaw;
8383             forwardkeydown = 0;
8384             leftkeydown = 0;
8385             backkeydown = 0;
8386             rightkeydown = 0;
8387             jumpkeydown = 0;
8388             attackkeydown = 0;
8389             crouchkeydown = 0;
8390             throwkeydown = 0;
8391         }
8392
8393         XYZ facing;
8394         facing = 0;
8395         facing.z = -1;
8396
8397         XYZ flatfacing = DoRotation(facing, 0, yaw + 180, 0);
8398         facing = flatfacing;
8399
8400         if (aitype == attacktypecutoff) {
8401             targetheadyaw = 180 - roughDirectionTo(coords, Person::players[0]->coords);
8402             targetheadpitch = pitchTo(coords, Person::players[0]->coords);
8403         } else if (howactive >= typesleeping) {
8404             targetheadyaw = targetyaw;
8405             targetheadpitch = 0;
8406         } else {
8407             if (interestdelay <= 0) {
8408                 interestdelay = .7 + (float)(abs(Random() % 100)) / 100;
8409                 headtarget = coords;
8410                 headtarget.x += (float)(abs(Random() % 200) - 100) / 100;
8411                 headtarget.z += (float)(abs(Random() % 200) - 100) / 100;
8412                 headtarget.y += (float)(abs(Random() % 200) - 100) / 300;
8413                 headtarget += facing * 1.5;
8414             }
8415             targetheadyaw = 180 - roughDirectionTo(coords, headtarget);
8416             targetheadpitch = pitchTo(coords, headtarget);
8417         }
8418     }
8419 }