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