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