]> git.jsancho.org Git - lugaru.git/blob - Source/Objects/Person.cpp
1187fb7ba76a6d3db2e29c4ece4ba1db35b17ebc
[lugaru.git] / Source / Objects / Person.cpp
1 /*
2 Copyright (C) 2003, 2010 - Wolfire Games
3 Copyright (C) 2010-2017 - Lugaru contributors (see AUTHORS file)
4
5 This file is part of Lugaru.
6
7 Lugaru is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 Lugaru is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Lugaru.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "Objects/Person.hpp"
22
23 #include "Animation/Animation.hpp"
24 #include "Audio/Sounds.hpp"
25 #include "Audio/openal_wrapper.hpp"
26 #include "Game.hpp"
27 #include "Level/Awards.hpp"
28 #include "Level/Dialog.hpp"
29 #include "Tutorial.hpp"
30 #include "Utils/Folders.hpp"
31
32 extern float multiplier;
33 extern Terrain terrain;
34 extern float gravity;
35 extern int environment;
36 extern int detail;
37 extern FRUSTUM frustum;
38 extern XYZ viewer;
39 extern float realmultiplier;
40 extern int slomo;
41 extern float slomodelay;
42 extern bool cellophane;
43 extern float texdetail;
44 extern float realtexdetail;
45 extern int bloodtoggle;
46 extern bool autoslomo;
47 extern float camerashake;
48 extern float woozy;
49 extern float viewdistance;
50 extern float blackout;
51 extern int difficulty;
52 extern bool decalstoggle;
53 extern float fadestart;
54 extern bool freeze;
55 extern bool winfreeze;
56 extern bool showpoints;
57 extern bool immediate;
58 extern float smoketex;
59 extern bool reversaltrain;
60 extern bool canattack;
61 extern bool cananger;
62 extern float damagedealt;
63 extern int hostile;
64 extern float hostiletime;
65
66 extern bool gamestarted;
67
68 extern XYZ envsound[30];
69 extern float envsoundvol[30];
70 extern int numenvsounds;
71 extern float envsoundlife[30];
72
73 extern XYZ windvector;
74
75 std::vector<std::shared_ptr<Person>> Person::players;
76
77 Person::Person()
78     : whichpatchx(0)
79     , whichpatchz(0)
80     , animCurrent(bounceidleanim)
81     , animTarget(bounceidleanim)
82     , frameCurrent(0)
83     , frameTarget(1)
84     , oldanimCurrent(0)
85     , oldanimTarget(0)
86     , oldframeCurrent(0)
87     , oldframeTarget(0)
88     , howactive(typeactive)
89     , parriedrecently(0)
90     , superruntoggle(false)
91     , lastattack(0)
92     , lastattack2(0)
93     , lastattack3(0)
94     , currentoffset()
95     , targetoffset()
96     , offset()
97     , target(0)
98     , transspeed(0)
99     ,
100
101     realoldcoords()
102     , oldcoords()
103     , coords()
104     , velocity()
105
106     , unconscioustime(0)
107
108     , immobile(false)
109
110     , velspeed(0)
111     , targetyaw(0)
112     , targetrot(0)
113     , rot(0)
114     , oldrot(0)
115     , lookyaw(0)
116     , lookpitch(0)
117     , yaw(0)
118     , pitch(0)
119     , lowyaw(0)
120     , tilt(0)
121     , targettilt(0)
122     , tilt2(0)
123     , targettilt2(0)
124     , rabbitkickenabled(false)
125     ,
126
127     bloodloss(0)
128     , bleeddelay(0)
129     , skiddelay(0)
130     , skiddingdelay(0)
131     , deathbleeding(0)
132     , tempdeltav(0)
133
134     , damagetolerance(0)
135     , damage(0)
136     , permanentdamage(0)
137     , superpermanentdamage(0)
138     , lastcollide(0)
139     , dead(0)
140
141     , jumppower(5)
142     , onground(false)
143
144     , wentforweapon(0)
145
146     , calcrot(false)
147
148     , facing()
149
150     , bleeding(0)
151     , bleedx(0)
152     , bleedy(0)
153     , direction(0)
154     , texupdatedelay(0)
155     ,
156
157     headyaw(0)
158     , headpitch(0)
159     , targetheadyaw(0)
160     , targetheadpitch(0)
161     ,
162
163     onterrain(false)
164     , pause(false)
165     ,
166
167     grabdelay(0)
168     ,
169
170     victim(nullptr)
171     , hasvictim(false)
172     ,
173
174     updatedelay(0)
175     , normalsupdatedelay(0)
176     ,
177
178     jumpstart(false)
179     , forwardkeydown(false)
180     , forwardstogglekeydown(false)
181     , rightkeydown(false)
182     , leftkeydown(false)
183     , backkeydown(false)
184     , jumpkeydown(false)
185     , jumptogglekeydown(false)
186     , crouchkeydown(false)
187     , crouchtogglekeydown(false)
188     , drawkeydown(false)
189     , drawtogglekeydown(false)
190     , throwkeydown(false)
191     , throwtogglekeydown(false)
192     , attackkeydown(false)
193     , feint(false)
194     , lastfeint(false)
195     , headless(false)
196     ,
197
198     crouchkeydowntime(0)
199     , jumpkeydowntime(0)
200     , freefall(false)
201     ,
202
203     turnspeed(0)
204     ,
205
206     aitype(passivetype)
207     , aiupdatedelay(0)
208     , losupdatedelay(0)
209     , ally(0)
210     , collide(0)
211     , collided(-10)
212     , avoidcollided(0)
213     , loaded(false)
214     , whichdirection(false)
215     , whichdirectiondelay(0)
216     , avoidsomething(false)
217     , avoidwhere()
218     , blooddimamount(0)
219     ,
220
221     staggerdelay(0)
222     , blinkdelay(0)
223     , twitchdelay(0)
224     , twitchdelay2(0)
225     , twitchdelay3(0)
226     , lefthandmorphness(0)
227     , righthandmorphness(0)
228     , headmorphness(0)
229     , chestmorphness(0)
230     , tailmorphness(0)
231     , targetlefthandmorphness(0)
232     , targetrighthandmorphness(0)
233     , targetheadmorphness(1)
234     , targetchestmorphness(0)
235     , targettailmorphness(0)
236     , lefthandmorphstart(0)
237     , lefthandmorphend(0)
238     , righthandmorphstart(0)
239     , righthandmorphend(0)
240     , headmorphstart(0)
241     , headmorphend(0)
242     , chestmorphstart(0)
243     , chestmorphend(0)
244     , tailmorphstart(0)
245     , tailmorphend(0)
246     ,
247
248     weaponmissdelay(0)
249     , highreversaldelay(0)
250     , lowreversaldelay(0)
251     ,
252
253     creature(rabbittype)
254     ,
255
256     id(0)
257     ,
258
259     skeleton()
260     ,
261
262     speed(0)
263     , scale(-1)
264     , power(0)
265     , speedmult(0)
266     ,
267
268     protectionhead(0)
269     , protectionhigh(0)
270     , protectionlow(0)
271     , armorhead(0)
272     , armorhigh(0)
273     , armorlow(0)
274     , metalhead(false)
275     , metalhigh(false)
276     , metallow(false)
277     ,
278
279     numclothes(0)
280     ,
281
282     landhard(false)
283     , bled(false)
284     , spurt(false)
285     , onfire(false)
286     , onfiredelay(0)
287     , burnt(0)
288     ,
289
290     flamedelay(0)
291     ,
292
293     playerdetail(0)
294     ,
295
296     num_weapons(0)
297     , weaponactive(-1)
298     , weaponstuck(-1)
299     , weaponstuckwhere(0)
300     ,
301
302     numwaypoints(0)
303     , pausetime(0)
304     ,
305
306     headtarget()
307     , interestdelay(0)
308     ,
309
310     finalfinaltarget()
311     , finaltarget()
312     , finalpathfindpoint(0)
313     , targetpathfindpoint(0)
314     , lastpathfindpoint(0)
315     , lastpathfindpoint2(0)
316     , lastpathfindpoint3(0)
317     , lastpathfindpoint4(0)
318     ,
319
320     waypoint(0)
321     ,
322
323     lastseen()
324     , lastseentime(0)
325     , lastchecktime(0)
326     , stunned(0)
327     , surprised(0)
328     , runninghowlong(0)
329     , occluded(0)
330     , lastoccluded(0)
331     , laststanding(0)
332     , escapednum(0)
333     ,
334
335     speechdelay(0)
336     , neckspurtdelay(0)
337     , neckspurtparticledelay(0)
338     , neckspurtamount(0)
339
340     , whichskin(0)
341     , rabbitkickragdoll(false)
342
343     , tempanimation("Tempanim", lowheight, neutral)
344
345     , jumpclimb(false)
346 {
347     damagetolerance = PersonType::types[creature].defaultDamageTolerance;
348     setProportions(1, 1, 1, 1);
349 }
350
351 /* Read a person in tfile. Throws an error if it’s not valid */
352 Person::Person(FILE* tfile, int mapvers, unsigned i)
353     : Person()
354 {
355     id = i;
356     funpackf(tfile, "Bi Bi Bf Bf Bf Bi", &whichskin, &creature, &coords.x, &coords.y, &coords.z, &num_weapons);
357     if (mapvers >= 5) {
358         funpackf(tfile, "Bi", &howactive);
359     } else {
360         howactive = typeactive;
361     }
362     if (mapvers >= 3) {
363         funpackf(tfile, "Bf", &scale);
364     } else {
365         scale = -1;
366     }
367     if (mapvers >= 11) {
368         funpackf(tfile, "Bb", &immobile);
369     } else {
370         immobile = 0;
371     }
372     if (mapvers >= 12) {
373         funpackf(tfile, "Bf", &yaw);
374     } else {
375         yaw = 0;
376     }
377     targetyaw = yaw;
378     if (num_weapons < 0 || num_weapons > 5) {
379         throw InvalidPersonException();
380     }
381     if (num_weapons > 0 && num_weapons < 5) {
382         for (int j = 0; j < num_weapons; j++) {
383             weaponids[j] = weapons.size();
384             int type;
385             funpackf(tfile, "Bi", &type);
386             weapons.push_back(Weapon(type, id));
387         }
388     }
389     funpackf(tfile, "Bi", &numwaypoints);
390     for (int j = 0; j < numwaypoints; j++) {
391         funpackf(tfile, "Bf", &waypoints[j].x);
392         funpackf(tfile, "Bf", &waypoints[j].y);
393         funpackf(tfile, "Bf", &waypoints[j].z);
394         if (mapvers >= 5) {
395             funpackf(tfile, "Bi", &waypointtype[j]);
396         } else {
397             waypointtype[j] = wpkeepwalking;
398         }
399     }
400
401     funpackf(tfile, "Bi", &waypoint);
402     if (waypoint > (numwaypoints - 1)) {
403         waypoint = 0;
404     }
405
406     funpackf(tfile, "Bf Bf Bf", &armorhead, &armorhigh, &armorlow);
407     funpackf(tfile, "Bf Bf Bf", &protectionhead, &protectionhigh, &protectionlow);
408     funpackf(tfile, "Bf Bf Bf", &metalhead, &metalhigh, &metallow);
409     funpackf(tfile, "Bf Bf", &power, &speedmult);
410
411     if (mapvers >= 4) {
412         funpackf(tfile, "Bf Bf Bf Bf", &proportions[0], &proportions[1], &proportions[2], &proportions[3]);
413     } else {
414         setProportions(1, 1, 1, 1);
415     }
416
417     funpackf(tfile, "Bi", &numclothes);
418     for (int k = 0; k < numclothes; k++) {
419         int templength;
420         funpackf(tfile, "Bi", &templength);
421         for (int l = 0; l < templength; l++) {
422             funpackf(tfile, "Bb", &clothes[k][l]);
423         }
424         clothes[k][templength] = '\0';
425         funpackf(tfile, "Bf Bf Bf", &clothestintr[k], &clothestintg[k], &clothestintb[k]);
426     }
427
428     loaded = true;
429
430     damagetolerance = PersonType::types[creature].defaultDamageTolerance;
431
432     if (scale < 0) {
433         scale = PersonType::types[creature].defaultScale;
434     }
435
436     oldcoords = coords;
437     realoldcoords = coords;
438 }
439
440 void Person::changeCreatureType(person_type type)
441 {
442     creature = type;
443     whichskin = 0;
444     skeletonLoad(type == rabbittype);
445     scale = PersonType::types[creature].defaultScale;
446     damagetolerance = PersonType::types[creature].defaultDamageTolerance;
447 }
448
449 void Person::skeletonLoad(bool clothes)
450 {
451     skeleton.id = id;
452     skeleton.Load(
453         PersonType::types[creature].figureFileName,
454         PersonType::types[creature].lowFigureFileName,
455         PersonType::types[creature].clothesFileName,
456         PersonType::types[creature].modelFileNames[0],
457         PersonType::types[creature].modelFileNames[1],
458         PersonType::types[creature].modelFileNames[2],
459         PersonType::types[creature].modelFileNames[3],
460         PersonType::types[creature].modelFileNames[4],
461         PersonType::types[creature].modelFileNames[5],
462         PersonType::types[creature].modelFileNames[6],
463         PersonType::types[creature].lowModelFileName,
464         PersonType::types[creature].modelClothesFileName,
465         clothes);
466
467     skeleton.drawmodel.textureptr.load(PersonType::types[creature].skins[whichskin], 1, &skeleton.skinText[0], &skeleton.skinsize);
468 }
469
470 void Person::setProportions(float head, float body, float arms, float legs)
471 {
472     proportions[0] = head;
473     proportions[1] = body;
474     proportions[2] = arms;
475     proportions[3] = legs;
476 }
477
478 float Person::getProportion(int part) const
479 {
480     return proportions[part];
481 }
482
483 XYZ Person::getProportionXYZ(int part) const
484 {
485     XYZ prop = PersonType::types[creature].proportions[part] * proportions[part];
486     if (cellophane) {
487         prop.z = 0;
488     }
489     return prop;
490 }
491
492 /* EFFECT
493  *
494  * USES:
495  * GameTick/doPlayerCollisions
496  */
497 void Person::CheckKick()
498 {
499     if (!(hasvictim && (animTarget == rabbitkickanim && victim && victim != this->shared_from_this() && frameCurrent >= 2 && animCurrent == rabbitkickanim) && distsq(&coords, &victim->coords) < 1.2 && !victim->skeleton.free)) {
500         return;
501     }
502
503     if (Animation::animations[victim->animTarget].height != lowheight) {
504         float damagemult = PersonType::types[creature].power * power * power;
505         XYZ relative = velocity;
506         relative.y = 0;
507         Normalise(&relative);
508
509         victim->spurt = 1;
510         DoBlood(.2, 250);
511         if (!Tutorial::active) {
512             emit_sound_at(heavyimpactsound, victim->coords);
513         }
514         victim->RagDoll(0);
515         for (unsigned i = 0; i < victim->skeleton.joints.size(); i++) {
516             victim->skeleton.joints[i].velocity += relative * 120 * damagemult;
517         }
518         victim->Puff(neck);
519         victim->DoDamage(100 * damagemult / victim->protectionhigh);
520         if (id == 0) {
521             camerashake += .4;
522         }
523
524         target = 0;
525         frameCurrent = 3;
526         animTarget = backflipanim;
527         frameTarget = 4;
528         velocity = facing * -10;
529         velocity.y = 5;
530         skeleton.free = 0;
531         if (id == 0) {
532             resume_stream(whooshsound);
533         }
534
535         award_bonus(id, cannon);
536     } else if (victim->isCrouch()) {
537         animTarget = rabbitkickreversedanim;
538         animCurrent = rabbitkickreversedanim;
539         victim->animCurrent = rabbitkickreversalanim;
540         victim->animTarget = rabbitkickreversalanim;
541         targettilt2 = 0;
542         frameCurrent = 0;
543         frameTarget = 1;
544         target = 0;
545         velocity = 0;
546         victim->oldcoords = victim->coords;
547         coords = victim->coords;
548         victim->targetyaw = targetyaw;
549         victim->victim = this->shared_from_this();
550     }
551 }
552
553 /* EFFECT
554  *
555  * USES:
556  * GameTick::doPlayerCollisions - spread fire between players
557  * GameTick::ProcessDevKeys - press f to ignite
558  * Person::DoStuff - spread fire from lit campfires and bushes
559  */
560 void Person::CatchFire()
561 {
562     XYZ flatfacing, flatvelocity;
563     int howmany;
564     for (int i = 0; i < 10; i++) {
565         howmany = fabs(Random() % (skeleton.joints.size()));
566         if (skeleton.free) {
567             flatvelocity = skeleton.joints[howmany].velocity;
568             flatfacing = skeleton.joints[howmany].position * scale + coords;
569         } else {
570             flatvelocity = velocity;
571             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
572         }
573         Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, 2, 1);
574     }
575
576     onfiredelay = 0.5;
577
578     emit_sound_at(firestartsound, coords);
579
580     emit_stream_at(stream_firesound, coords);
581
582     flamedelay = 0;
583
584     onfire = 1;
585 }
586
587 /* FUNCTION
588  * idle animation for this creature (depending on status)
589  */
590 int Person::getIdle()
591 {
592     if (Dialog::inDialog() && (howactive == typeactive) && PersonType::types[creature].hasAnimTalkIdle()) {
593         return PersonType::types[creature].animTalkIdle;
594     }
595     if (hasvictim && (victim != this->shared_from_this())) {
596         if ((!victim->dead && victim->aitype != passivetype &&
597              victim->aitype != searchtype && aitype != passivetype && aitype != searchtype &&
598              victim->id < Person::players.size())) {
599             if ((aitype == playercontrolled && stunned <= 0 && weaponactive == -1) || pause) {
600                 return PersonType::types[creature].animFightIdle;
601             }
602             if (aitype == playercontrolled && stunned <= 0 && weaponactive != -1) {
603                 if (weapons[weaponids[weaponactive]].getType() == knife) {
604                     return knifefightidleanim;
605                 }
606                 if (weapons[weaponids[weaponactive]].getType() == sword && victim->weaponactive != -1) {
607                     return swordfightidlebothanim;
608                 }
609                 if (weapons[weaponids[weaponactive]].getType() == sword) {
610                     return swordfightidleanim;
611                 }
612                 if (weapons[weaponids[weaponactive]].getType() == staff) {
613                     return swordfightidleanim;
614                 }
615             }
616             if (aitype != playercontrolled && stunned <= 0 && creature != wolftype && !pause) {
617                 return fightsidestep;
618             }
619         }
620     }
621     if ((damage > permanentdamage || damage > damagetolerance * .8 || deathbleeding > 0) && creature != wolftype) {
622         return hurtidleanim;
623     }
624     if (howactive == typesitting) {
625         return sitanim;
626     }
627     if (howactive == typesittingwall) {
628         return sitwallanim;
629     }
630     if (howactive == typesleeping) {
631         return sleepanim;
632     }
633     if (howactive == typedead1) {
634         return dead1anim;
635     }
636     if (howactive == typedead2) {
637         return dead2anim;
638     }
639     if (howactive == typedead3) {
640         return dead3anim;
641     }
642     if (howactive == typedead4) {
643         return dead4anim;
644     }
645     return PersonType::types[creature].animBounceIdle;
646 }
647
648 /* FUNCTION
649  * crouch animation for this creature
650  */
651 int Person::getCrouch()
652 {
653     return PersonType::types[creature].animCrouch;
654 }
655
656 /* FUNCTION
657  * running animation for this creature (can be upright or all fours)
658  */
659 int Person::getRun()
660 {
661     if (superruntoggle && (weaponactive == -1)) {
662         return PersonType::types[creature].animRunning;
663     } else {
664         return PersonType::types[creature].animRun;
665     }
666 }
667
668 /* FUNCTION
669  */
670 int Person::getStop()
671 {
672     return PersonType::types[creature].animStop;
673 }
674
675 /* FUNCTION
676  */
677 int Person::getLanding()
678 {
679     return PersonType::types[creature].animLanding;
680 }
681
682 /* FUNCTION
683  */
684 int Person::getLandhard()
685 {
686     return PersonType::types[creature].animLandingHard;
687 }
688
689 /* EFFECT
690  *
691  * USES:
692  * Person::DoAnimations
693  */
694 static void
695 SolidHitBonus(int playerid)
696 {
697     if (bonustime < 1.5 && bonus >= solidhit && bonus <= megacombo) {
698         award_bonus(playerid, bonus == megacombo ? bonus : bonus + 1);
699     } else {
700         award_bonus(playerid, solidhit);
701     }
702 }
703
704 /* EFFECT
705  * spawns blood effects
706  */
707 void Person::DoBlood(float howmuch, int which)
708 {
709     // FIXME: should abstract out inputs
710     static int bleedxint, bleedyint;
711     static XYZ bloodvel;
712     if (bloodtoggle && !Tutorial::active) {
713         if (bleeding <= 0 && spurt) {
714             spurt = 0;
715             for (int i = 0; i < 3; i++) {
716                 // emit blood particles
717                 bloodvel = 0;
718                 if (skeleton.free) {
719                     bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
720                     bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
721                     Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
722                     Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
723                 } else {
724                     bloodvel.z = 10;
725                     bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
726                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
727                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
728                     Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
729                 }
730             }
731             if (Random() % 2 == 0) { // 50% chance
732                 for (int i = 0; i < 3; i++) {
733                     if (Random() % 2 != 0) {
734                         // emit teeth particles
735                         bloodvel = 0;
736                         if (skeleton.free) {
737                             bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
738                             bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
739                         } else {
740                             bloodvel.z = 10;
741                             bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
742                             bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
743                         }
744                         bloodvel *= .2;
745                         if (skeleton.free) {
746                             Sprite::MakeSprite(splintersprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
747                         } else {
748                             Sprite::MakeSprite(splintersprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
749                         }
750                         Sprite::setLastSpriteSpecial(3); // sets it to teeth
751                     }
752                 }
753             }
754         }
755         if (decalstoggle) {
756             // FIXME: manipulating attributes
757             bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
758             bleedxint = 0;
759             bleedyint = 0;
760             while (PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
761                 bleedxint = abs(Random() % 512);
762                 bleedyint = abs(Random() % 512);
763             }
764             bleedy = bleedxint;
765             bleedx = bleedyint;
766             bleedy /= realtexdetail;
767             bleedx /= realtexdetail;
768             direction = abs(Random() % 2) * 2 - 1;
769         }
770     }
771     if (bleeding > 2) {
772         bleeding = 2;
773     }
774 }
775
776 /* EFFECT
777  * spawns big blood effects and ???
778  * modifies character's skin texture
779  */
780 void Person::DoBloodBig(float howmuch, int which)
781 {
782     static int bleedxint, bleedyint, i, j;
783     static XYZ bloodvel;
784     if (howmuch && id == 0) {
785         blooddimamount = 1;
786     }
787
788     if (!Tutorial::active || id == 0) {
789         if (aitype != playercontrolled && howmuch > 0) {
790             // play pain sounds
791             int whichsound = -1;
792
793             if (creature == wolftype) {
794                 int i = abs(Random() % 2);
795                 if (i == 0) {
796                     whichsound = snarlsound;
797                 }
798                 if (i == 1) {
799                     whichsound = snarl2sound;
800                 }
801             }
802             if (creature == rabbittype) {
803                 int i = abs(Random() % 2);
804                 if (i == 0) {
805                     whichsound = rabbitpainsound;
806                 }
807                 if (i == 1 && howmuch >= 2) {
808                     whichsound = rabbitpain1sound;
809                 }
810             }
811
812             if (whichsound != -1) {
813                 emit_sound_at(whichsound, coords);
814                 addEnvSound(coords);
815             }
816         }
817     }
818
819     if (id == 0 && howmuch > 0) {
820         Game::flash(.5, 0);
821     }
822
823     if (bloodtoggle && decalstoggle && !Tutorial::active) {
824         if (bleeding <= 0 && spurt) {
825             spurt = 0;
826             for (int i = 0; i < 3; i++) {
827                 // emit blood particles
828                 // FIXME: copypaste from above
829                 bloodvel = 0;
830                 if (skeleton.free) {
831                     bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
832                     bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
833                     Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
834                     Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
835                 } else {
836                     bloodvel.z = 10;
837                     bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
838                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
839                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
840                     Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
841                 }
842             }
843         }
844
845         // weird texture manipulation code follows.
846         // looks like this is painting blood onto the character's skin texture
847         // FIXME: surely there's a better way
848
849         int offsetx = 0, offsety = 0;
850         if (which == 225) {
851             offsety = Random() % 40;
852             offsetx = abs(Random() % 60);
853         }
854         if (which == 190 || which == 185) {
855             offsety = Random() % 40;
856             offsetx = abs(Random() % 100) - 20;
857         }
858         if (which == 175) {
859             offsety = Random() % 10;
860             offsetx = Random() % 10;
861         }
862         if (which == 170) {
863             offsety = Random() % 20;
864             offsetx = Random() % 20;
865         }
866         if (which == 220 || which == 215) {
867             offsetx = 20;
868         }
869
870         int startx = 512;
871         int starty = 512;
872         int endx = 0;
873         int endy = 0;
874         GLubyte color;
875         for (i = 0; i < 512; i++) {
876             for (j = 0; j < 512; j++) {
877                 if (PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
878                     if (i < startx) {
879                         startx = i;
880                     }
881                     if (j < starty) {
882                         starty = j;
883                     }
884                     if (i > endx) {
885                         endx = i;
886                     }
887                     if (j > endy) {
888                         endy = j;
889                     }
890                 }
891             }
892         }
893
894         startx += offsetx;
895         endx += offsetx;
896         starty += offsety;
897         endy += offsety;
898
899         if (startx < 0) {
900             startx = 0;
901         }
902         if (starty < 0) {
903             starty = 0;
904         }
905         if (endx > 512 - 1) {
906             endx = 512 - 1;
907         }
908         if (endy > 512 - 1) {
909             endy = 512 - 1;
910         }
911         if (endx < startx) {
912             endx = startx;
913         }
914         if (endy < starty) {
915             endy = starty;
916         }
917
918         startx /= realtexdetail;
919         starty /= realtexdetail;
920         endx /= realtexdetail;
921         endy /= realtexdetail;
922
923         int texdetailint = realtexdetail;
924         int where;
925         for (i = startx; i < endx; i++) {
926             for (j = starty; j < endy; j++) {
927                 if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
928                     color = Random() % 85 + 170;
929                     where = i * skeleton.skinsize * 3 + j * 3;
930                     if (skeleton.skinText[where + 0] > color / 2) {
931                         skeleton.skinText[where + 0] = color / 2;
932                     }
933                     skeleton.skinText[where + 1] = 0;
934                     skeleton.skinText[where + 2] = 0;
935                 }
936             }
937         }
938         skeleton.drawmodel.textureptr.bind();
939         DoMipmaps();
940
941         bleedxint = 0;
942         bleedyint = 0;
943         while (PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] > which + 4 || PersonType::types[creature].bloodText[bleedxint * 512 * 3 + bleedyint * 3 + 0] < which - 4 || bleedxint < 10 || bleedyint < 10 || bleedxint > 500 || bleedyint > 500) {
944             bleedxint = abs(Random() % 512);
945             bleedyint = abs(Random() % 512);
946         }
947         bleedy = bleedxint + offsetx;
948         bleedx = bleedyint + offsety;
949         bleedy /= realtexdetail;
950         bleedx /= realtexdetail;
951         if (bleedx < 0) {
952             bleedx = 0;
953         }
954         if (bleedy < 0) {
955             bleedy = 0;
956         }
957         if (bleedx > skeleton.skinsize - 1) {
958             bleedx = skeleton.skinsize - 1;
959         }
960         if (bleedy > skeleton.skinsize - 1) {
961             bleedy = skeleton.skinsize - 1;
962         }
963         direction = abs(Random() % 2) * 2 - 1;
964     }
965     bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
966     deathbleeding += bleeding;
967     bloodloss += bleeding * 3;
968
969     if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
970         if (abs(Random() % 2) == 0) {
971             aitype = gethelptype;
972             lastseentime = 12;
973         } else {
974             aitype = attacktypecutoff;
975         }
976         ally = 0;
977     }
978     if (bleeding > 2) {
979         bleeding = 2;
980     }
981 }
982
983 /* EFFECT
984  * similar to DoBloodBig
985  */
986 bool Person::DoBloodBigWhere(float howmuch, int which, XYZ where)
987 {
988     static int i, j;
989     static XYZ bloodvel;
990     static XYZ startpoint, endpoint, colpoint, movepoint;
991     static float rotationpoint;
992     static int whichtri;
993     static XYZ p1, p2, p3, p0;
994     XYZ bary;
995     XYZ gxx, gyy;
996     float coordsx, coordsy;
997     float total;
998
999     if (bloodtoggle && decalstoggle && !Tutorial::active) {
1000         where -= coords;
1001         if (!skeleton.free) {
1002             where = DoRotation(where, 0, -yaw, 0);
1003         }
1004         //where=scale;
1005         startpoint = where;
1006         startpoint.y += 100;
1007         endpoint = where;
1008         endpoint.y -= 100;
1009         movepoint = 0;
1010         rotationpoint = 0;
1011         // ray testing for a tri in the character model
1012         whichtri = skeleton.drawmodel.LineCheck(&startpoint, &endpoint, &colpoint, &movepoint, &rotationpoint);
1013         if (whichtri != -1) {
1014             // low level geometry math
1015             p0 = colpoint;
1016             p1 = skeleton.drawmodel.getTriangleVertex(whichtri, 0);
1017             p2 = skeleton.drawmodel.getTriangleVertex(whichtri, 1);
1018             p3 = skeleton.drawmodel.getTriangleVertex(whichtri, 2);
1019
1020             bary.x = distsq(&p0, &p1);
1021             bary.y = distsq(&p0, &p2);
1022             bary.z = distsq(&p0, &p3);
1023
1024             total = bary.x + bary.y + bary.z;
1025             bary.x /= total;
1026             bary.y /= total;
1027             bary.z /= total;
1028
1029             bary.x = 1 - bary.x;
1030             bary.y = 1 - bary.y;
1031             bary.z = 1 - bary.z;
1032
1033             total = bary.x + bary.y + bary.z;
1034             bary.x /= total;
1035             bary.y /= total;
1036             bary.z /= total;
1037
1038             gxx.x = skeleton.drawmodel.Triangles[whichtri].gx[0];
1039             gxx.y = skeleton.drawmodel.Triangles[whichtri].gx[1];
1040             gxx.z = skeleton.drawmodel.Triangles[whichtri].gx[2];
1041             gyy.x = skeleton.drawmodel.Triangles[whichtri].gy[0];
1042             gyy.y = skeleton.drawmodel.Triangles[whichtri].gy[1];
1043             gyy.z = skeleton.drawmodel.Triangles[whichtri].gy[2];
1044             coordsx = skeleton.drawmodel.Triangles[whichtri].gx[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gx[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gx[2] * bary.z;
1045             coordsy = skeleton.drawmodel.Triangles[whichtri].gy[0] * bary.x + skeleton.drawmodel.Triangles[whichtri].gy[1] * bary.y + skeleton.drawmodel.Triangles[whichtri].gy[2] * bary.z;
1046
1047             if (bleeding <= 0 && spurt) {
1048                 spurt = 0;
1049                 for (int i = 0; i < 3; i++) {
1050                     // emit blood particles
1051                     // FIXME: more copypaste code
1052                     bloodvel = 0;
1053                     if (skeleton.free) {
1054                         bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0);
1055                         bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
1056                         Sprite::MakeSprite(bloodsprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
1057                         Sprite::MakeSprite(bloodflamesprite, jointPos(head) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
1058                     } else {
1059                         bloodvel.z = 10;
1060                         bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
1061                         bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
1062                         Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
1063                         Sprite::MakeSprite(bloodflamesprite, DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .3, 1);
1064                     }
1065                 }
1066             }
1067
1068             // texture manipulation follows
1069
1070             int offsetx = 0, offsety = 0;
1071             offsetx = (1 + coordsy) * 512 - 291;
1072             offsety = coordsx * 512 - 437;
1073
1074             int startx = 512;
1075             int starty = 512;
1076             int endx = 0;
1077             int endy = 0;
1078             GLubyte color;
1079             for (i = 0; i < 512; i++) {
1080                 for (j = 0; j < 512; j++) {
1081                     if (PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[i * 512 * 3 + j * 3 + 0] >= which - 4) {
1082                         if (i < startx) {
1083                             startx = i;
1084                         }
1085                         if (j < starty) {
1086                             starty = j;
1087                         }
1088                         if (i > endx) {
1089                             endx = i;
1090                         }
1091                         if (j > endy) {
1092                             endy = j;
1093                         }
1094                     }
1095                 }
1096             }
1097             startx += offsetx;
1098             endx += offsetx;
1099             starty += offsety;
1100             endy += offsety;
1101
1102             if (startx < 0) {
1103                 startx = 0;
1104             }
1105             if (starty < 0) {
1106                 starty = 0;
1107             }
1108             if (endx > 512 - 1) {
1109                 endx = 512 - 1;
1110             }
1111             if (endy > 512 - 1) {
1112                 endy = 512 - 1;
1113             }
1114             if (endx < startx) {
1115                 endx = startx;
1116             }
1117             if (endy < starty) {
1118                 endy = starty;
1119             }
1120
1121             startx /= realtexdetail;
1122             starty /= realtexdetail;
1123             endx /= realtexdetail;
1124             endy /= realtexdetail;
1125
1126             int texdetailint = realtexdetail;
1127             int where;
1128             for (i = startx; i < endx; i++) {
1129                 for (j = starty; j < endy; j++) {
1130                     if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= which + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= which - 4) {
1131                         color = Random() % 85 + 170;
1132                         where = i * skeleton.skinsize * 3 + j * 3;
1133                         if (skeleton.skinText[where + 0] > color / 2) {
1134                             skeleton.skinText[where + 0] = color / 2;
1135                         }
1136                         skeleton.skinText[where + 1] = 0;
1137                         skeleton.skinText[where + 2] = 0;
1138                     } else if (PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] <= 160 + 4 && PersonType::types[creature].bloodText[(i * texdetailint - offsetx) * 512 * 3 + (j * texdetailint - offsety) * 3 + 0] >= 160 - 4) {
1139                         color = Random() % 85 + 170;
1140                         where = i * skeleton.skinsize * 3 + j * 3;
1141                         if (skeleton.skinText[where + 0] > color / 2) {
1142                             skeleton.skinText[where + 0] = color / 2;
1143                         }
1144                         skeleton.skinText[where + 1] = 0;
1145                         skeleton.skinText[where + 2] = 0;
1146                     }
1147                 }
1148             }
1149             skeleton.drawmodel.textureptr.bind();
1150             DoMipmaps();
1151
1152             bleedy = (1 + coordsy) * 512;
1153             bleedx = coordsx * 512;
1154             bleedy /= realtexdetail;
1155             bleedx /= realtexdetail;
1156             if (bleedx < 0) {
1157                 bleedx = 0;
1158             }
1159             if (bleedy < 0) {
1160                 bleedy = 0;
1161             }
1162             if (bleedx > skeleton.skinsize - 1) {
1163                 bleedx = skeleton.skinsize - 1;
1164             }
1165             if (bleedy > skeleton.skinsize - 1) {
1166                 bleedy = skeleton.skinsize - 1;
1167             }
1168             direction = abs(Random() % 2) * 2 - 1;
1169         }
1170         if (whichtri == -1) {
1171             return 0;
1172         }
1173     }
1174     bleeding = howmuch + (float)abs(Random() % 100) / 200 - .25;
1175     deathbleeding += bleeding;
1176     bloodloss += bleeding * 3;
1177
1178     if (!Tutorial::active && aitype != playercontrolled && bloodloss > damagetolerance * 2 / 3 && bloodloss < damagetolerance && creature == rabbittype) {
1179         if (abs(Random() % 2) == 0) {
1180             aitype = gethelptype;
1181             lastseentime = 12;
1182         } else {
1183             aitype = attacktypecutoff;
1184         }
1185         ally = 0;
1186     }
1187     if (bleeding > 2) {
1188         bleeding = 2;
1189     }
1190     return 1;
1191 }
1192
1193 /* EFFECT
1194  * guessing this performs a reversal
1195  */
1196 void Person::Reverse()
1197 {
1198     if (!((victim->aitype == playercontrolled || hostiletime > 1 || staggerdelay <= 0) && victim->animTarget != jumpupanim && victim->animTarget != jumpdownanim && (!Tutorial::active || cananger) && hostile)) {
1199         return;
1200     }
1201
1202     if (normaldotproduct(victim->facing, victim->coords - coords) > 0 && (victim->id != 0 || difficulty >= 2) && (creature != wolftype || victim->creature == wolftype)) {
1203         return;
1204     }
1205
1206     if (animTarget == sweepanim) {
1207         animTarget = sweepreversedanim;
1208         animCurrent = sweepreversedanim;
1209         victim->animCurrent = sweepreversalanim;
1210         victim->animTarget = sweepreversalanim;
1211     }
1212     if (animTarget == spinkickanim) {
1213         animTarget = spinkickreversedanim;
1214         animCurrent = spinkickreversedanim;
1215         victim->animCurrent = spinkickreversalanim;
1216         victim->animTarget = spinkickreversalanim;
1217     }
1218     if (animTarget == upunchanim || animTarget == rabbittacklinganim) {
1219         if (animTarget == rabbittacklinganim) {
1220             frameCurrent = 6;
1221             frameTarget = 7;
1222             victim->frameCurrent = 6;
1223             victim->frameTarget = 7;
1224         }
1225         animTarget = upunchreversedanim;
1226         animCurrent = upunchreversedanim;
1227         victim->animCurrent = upunchreversalanim;
1228         victim->animTarget = upunchreversalanim;
1229     }
1230     if (animTarget == staffhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
1231         if (victim->weaponactive != -1) {
1232             victim->throwtogglekeydown = 1;
1233             XYZ tempVelocity = victim->velocity * .2;
1234             if (tempVelocity.x == 0) {
1235                 tempVelocity.x = .1;
1236             }
1237             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
1238             victim->num_weapons--;
1239             if (victim->num_weapons) {
1240                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
1241                 if (victim->weaponstuck == victim->num_weapons) {
1242                     victim->weaponstuck = 0;
1243                 }
1244             }
1245
1246             victim->weaponactive = -1;
1247             for (unsigned j = 0; j < Person::players.size(); j++) {
1248                 Person::players[j]->wentforweapon = 0;
1249             }
1250         }
1251
1252         animTarget = staffhitreversedanim;
1253         animCurrent = staffhitreversedanim;
1254         victim->animCurrent = staffhitreversalanim;
1255         victim->animTarget = staffhitreversalanim;
1256     }
1257     if (animTarget == staffspinhitanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 2 == 0)) {
1258         if (victim->weaponactive != -1) {
1259             victim->throwtogglekeydown = 1;
1260             XYZ tempVelocity = victim->velocity * .2;
1261             if (tempVelocity.x == 0) {
1262                 tempVelocity.x = .1;
1263             }
1264             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
1265             victim->num_weapons--;
1266             if (victim->num_weapons) {
1267                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
1268                 if (victim->weaponstuck == victim->num_weapons) {
1269                     victim->weaponstuck = 0;
1270                 }
1271             }
1272
1273             victim->weaponactive = -1;
1274             for (unsigned j = 0; j < Person::players.size(); j++) {
1275                 Person::players[j]->wentforweapon = 0;
1276             }
1277         }
1278         animTarget = staffspinhitreversedanim;
1279         animCurrent = staffspinhitreversedanim;
1280         victim->animCurrent = staffspinhitreversalanim;
1281         victim->animTarget = staffspinhitreversalanim;
1282     }
1283     if (animTarget == swordslashanim && distsq(&victim->coords, &coords) < 2 && ((victim->id == 0 && victim->crouchkeydown) || Random() % 4 == 0)) {
1284         if (victim->weaponactive != -1) {
1285             victim->throwtogglekeydown = 1;
1286             XYZ tempVelocity = victim->velocity * .2;
1287             if (tempVelocity.x == 0) {
1288                 tempVelocity.x = .1;
1289             }
1290             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
1291             victim->num_weapons--;
1292             if (victim->num_weapons) {
1293                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
1294                 if (victim->weaponstuck == victim->num_weapons) {
1295                     victim->weaponstuck = 0;
1296                 }
1297             }
1298
1299             victim->weaponactive = -1;
1300             for (unsigned j = 0; j < Person::players.size(); j++) {
1301                 Person::players[j]->wentforweapon = 0;
1302             }
1303         }
1304         animTarget = swordslashreversedanim;
1305         animCurrent = swordslashreversedanim;
1306         victim->animCurrent = swordslashreversalanim;
1307         victim->animTarget = swordslashreversalanim;
1308     }
1309     if (animTarget == knifeslashstartanim && distsq(&victim->coords, &coords) < 2 && (victim->id == 0 || Random() % 4 == 0)) {
1310         if (victim->weaponactive != -1) {
1311             victim->throwtogglekeydown = 1;
1312             XYZ tempVelocity = victim->velocity * .2;
1313             if (tempVelocity.x == 0) {
1314                 tempVelocity.x = .1;
1315             }
1316             weapons[victim->weaponids[0]].drop(tempVelocity, tempVelocity, false);
1317             victim->num_weapons--;
1318             if (victim->num_weapons) {
1319                 victim->weaponids[0] = victim->weaponids[victim->num_weapons];
1320                 if (victim->weaponstuck == victim->num_weapons) {
1321                     victim->weaponstuck = 0;
1322                 }
1323             }
1324
1325             victim->weaponactive = -1;
1326             for (unsigned j = 0; j < Person::players.size(); j++) {
1327                 Person::players[j]->wentforweapon = 0;
1328             }
1329         }
1330         animTarget = knifeslashreversedanim;
1331         animCurrent = knifeslashreversedanim;
1332         victim->animCurrent = knifeslashreversalanim;
1333         victim->animTarget = knifeslashreversalanim;
1334     }
1335     if (animTarget != knifeslashstartanim && animTarget != staffhitanim && animTarget != staffspinhitanim && animTarget != winduppunchanim && animTarget != wolfslapanim && animTarget != swordslashanim) {
1336         victim->targettilt2 = targettilt2;
1337         victim->frameCurrent = frameCurrent;
1338         victim->frameTarget = frameTarget;
1339         victim->target = target;
1340         victim->velocity = 0;
1341         victim->oldcoords = victim->coords;
1342         victim->coords = coords;
1343         victim->targetyaw = targetyaw;
1344         victim->yaw = targetyaw;
1345         victim->victim = this->shared_from_this();
1346     }
1347     if (animTarget == winduppunchanim) {
1348         animTarget = winduppunchblockedanim;
1349         victim->animTarget = blockhighleftanim;
1350         victim->frameTarget = 1;
1351         victim->target = .5;
1352         victim->victim = this->shared_from_this();
1353         victim->targetyaw = targetyaw + 180;
1354     }
1355     if (animTarget == wolfslapanim) {
1356         animTarget = winduppunchblockedanim;
1357         victim->animTarget = blockhighleftanim;
1358         victim->frameTarget = 1;
1359         victim->target = .5;
1360         victim->victim = this->shared_from_this();
1361         victim->targetyaw = targetyaw + 180;
1362     }
1363     if ((animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) && victim->weaponactive != -1) {
1364         animTarget = swordslashparriedanim;
1365         parriedrecently = .4;
1366         victim->parriedrecently = 0;
1367         victim->animTarget = swordslashparryanim;
1368         victim->frameTarget = 1;
1369         victim->target = .5;
1370         victim->victim = this->shared_from_this();
1371         victim->targetyaw = targetyaw + 180;
1372
1373         if (abs(Random() % 20) == 0 || weapons[victim->weaponids[victim->weaponactive]].getType() == knife) {
1374             if (victim->weaponactive != -1) {
1375                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
1376                     if (weapons[victim->weaponids[0]].getType() == staff) {
1377                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1378                     }
1379                     if (weapons[weaponids[0]].getType() == staff) {
1380                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1381                     }
1382                     emit_sound_at(swordstaffsound, victim->coords);
1383                 } else {
1384                     emit_sound_at(metalhitsound, victim->coords);
1385                 }
1386             }
1387             XYZ aim;
1388             victim->Puff(righthand);
1389             victim->target = 0;
1390             victim->frameTarget = 0;
1391             victim->animTarget = staggerbackhighanim;
1392             victim->targetyaw = targetyaw + 180;
1393             victim->target = 0;
1394             aim = DoRotation(facing, 0, 90, 0) * 21;
1395             aim.y += 7;
1396             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
1397             victim->num_weapons--;
1398             if (victim->num_weapons) {
1399                 victim->weaponids[0] = victim->weaponids[num_weapons];
1400                 if (victim->weaponstuck == victim->num_weapons) {
1401                     victim->weaponstuck = 0;
1402                 }
1403             }
1404             victim->weaponactive = -1;
1405             for (unsigned i = 0; i < Person::players.size(); i++) {
1406                 Person::players[i]->wentforweapon = 0;
1407             }
1408         }
1409
1410         if (abs(Random() % 20) == 0) {
1411             if (weaponactive != -1) {
1412                 if (weapons[victim->weaponids[0]].getType() == staff || weapons[weaponids[0]].getType() == staff) {
1413                     if (weapons[victim->weaponids[0]].getType() == staff) {
1414                         weapons[victim->weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1415                     }
1416                     if (weapons[weaponids[0]].getType() == staff) {
1417                         weapons[weaponids[0]].damage += .2 + float(abs(Random() % 100) - 50) / 250;
1418                     }
1419
1420                     emit_sound_at(swordstaffsound, coords);
1421                 } else {
1422                     emit_sound_at(metalhitsound, coords);
1423                 }
1424             }
1425
1426             XYZ aim;
1427             Puff(righthand);
1428             target = 0;
1429             frameTarget = 0;
1430             animTarget = staggerbackhighanim;
1431             targetyaw = targetyaw + 180;
1432             target = 0;
1433             aim = DoRotation(facing, 0, 90, 0) * 21;
1434             aim.y += 7;
1435             weapons[victim->weaponids[0]].drop(aim * -.2, aim);
1436             num_weapons--;
1437             if (num_weapons) {
1438                 weaponids[0] = weaponids[num_weapons];
1439                 if (weaponstuck == num_weapons) {
1440                     weaponstuck = 0;
1441                 }
1442             }
1443             weaponactive = -1;
1444             for (unsigned i = 0; i < Person::players.size(); i++) {
1445                 Person::players[i]->wentforweapon = 0;
1446             }
1447         }
1448     }
1449     if (hasvictim) {
1450         if (animTarget == knifeslashstartanim || animTarget == swordslashanim || animTarget == staffhitanim || animTarget == staffspinhitanim) {
1451             if ((animTarget != staffhitanim && animTarget != staffspinhitanim) || distsq(&coords, &victim->coords) > .2) {
1452                 victim->animTarget = dodgebackanim;
1453                 victim->frameTarget = 0;
1454                 victim->target = 0;
1455
1456                 XYZ rotatetarget;
1457                 rotatetarget = coords - victim->coords;
1458                 Normalise(&rotatetarget);
1459                 victim->targetyaw = -asin(0 - rotatetarget.x);
1460                 victim->targetyaw *= 360 / 6.28;
1461                 if (rotatetarget.z < 0) {
1462                     victim->targetyaw = 180 - victim->targetyaw;
1463                 }
1464
1465                 victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
1466
1467                 victim->lastattack3 = victim->lastattack2;
1468                 victim->lastattack2 = victim->lastattack;
1469                 victim->lastattack = victim->animTarget;
1470             } else {
1471                 victim->animTarget = sweepanim;
1472                 victim->frameTarget = 0;
1473                 victim->target = 0;
1474
1475                 XYZ rotatetarget;
1476                 rotatetarget = coords - victim->coords;
1477                 Normalise(&rotatetarget);
1478                 victim->targetyaw = -asin(0 - rotatetarget.x);
1479                 victim->targetyaw *= 360 / 6.28;
1480                 if (rotatetarget.z < 0) {
1481                     victim->targetyaw = 180 - victim->targetyaw;
1482                 }
1483
1484                 victim->targettilt2 = -asin(rotatetarget.y) * 360 / 6.28; //*-70;
1485
1486                 victim->lastattack3 = victim->lastattack2;
1487                 victim->lastattack2 = victim->lastattack;
1488                 victim->lastattack = victim->animTarget;
1489             }
1490         }
1491     }
1492
1493     velocity = 0;
1494     victim->velocity = 0;
1495
1496     if (aitype != playercontrolled) {
1497         feint = 0;
1498         if (escapednum < 2) {
1499             int chances = ((difficulty == 2) ? 3 : ((difficulty == 1) ? 5 : 10));
1500             if ((Random() % chances) == 0) {
1501                 feint = 1;
1502             }
1503         }
1504     }
1505
1506     if (victim->id == 0 && Animation::animations[victim->animTarget].attack == reversal) {
1507         numreversals++;
1508     }
1509 }
1510
1511 /* EFFECT
1512  * get hurt
1513  */
1514 void Person::DoDamage(float howmuch)
1515 {
1516     // stats?
1517     if (id == 0) {
1518         damagetaken += howmuch / power;
1519     } else {
1520         damagedealt += howmuch / power;
1521     }
1522
1523     // reset bonuses
1524     if (id == 0 && (bonus == solidhit || bonus == twoxcombo || bonus == threexcombo || bonus == fourxcombo || bonus == megacombo)) {
1525         bonus = 0;
1526     }
1527
1528     // subtract health
1529     if (!Tutorial::active) {
1530         damage += howmuch / power;
1531         permanentdamage += howmuch / 2 / power;
1532         superpermanentdamage += howmuch / 4 / power;
1533     }
1534     // visual effects
1535     if (permanentdamage > damagetolerance / 2 && permanentdamage - howmuch < damagetolerance / 2 && Random() % 2) {
1536         DoBlood(1, 255);
1537     }
1538     if ((permanentdamage > damagetolerance * .8 && Random() % 2 && !deathbleeding) || spurt) {
1539         DoBlood(1, 255);
1540     }
1541     spurt = 0;
1542     if (id == 0) {
1543         camerashake += howmuch / 100;
1544         if ((howmuch > 50 && damage > damagetolerance / 2)) {
1545             blackout = damage / damagetolerance;
1546             if (blackout > 1) {
1547                 blackout = 1;
1548             }
1549         }
1550     }
1551
1552     // cancel attack?
1553     if (aitype == passivetype && damage < damagetolerance && ((!Tutorial::active || cananger) && hostile)) {
1554         aitype = attacktypecutoff;
1555     }
1556     if (!Tutorial::active && aitype != playercontrolled && damage < damagetolerance && damage > damagetolerance * 2 / 3 && creature == rabbittype) {
1557         if (abs(Random() % 2) == 0) {
1558             aitype = gethelptype;
1559             lastseentime = 12;
1560         } else {
1561             aitype = attacktypecutoff;
1562         }
1563         ally = 0;
1564     }
1565
1566     if (howmuch > damagetolerance * 50 && skeleton.free != 2) {
1567         XYZ flatvelocity2;
1568         XYZ flatfacing2;
1569         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
1570             if (skeleton.free) {
1571                 flatvelocity2 = skeleton.joints[i].velocity;
1572                 flatfacing2 = skeleton.joints[i].position * scale + coords;
1573             } else {
1574                 flatvelocity2 = velocity;
1575                 flatfacing2 = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
1576             }
1577             flatvelocity2.x += (float)(abs(Random() % 100) - 50) / 10;
1578             flatvelocity2.y += (float)(abs(Random() % 100) - 50) / 10;
1579             flatvelocity2.z += (float)(abs(Random() % 100) - 50) / 10;
1580             Sprite::MakeSprite(bloodflamesprite, flatfacing2, flatvelocity2, 1, 1, 1, 3, 1);
1581             Sprite::MakeSprite(bloodsprite, flatfacing2, flatvelocity2, 1, 1, 1, .4, 1);
1582             Sprite::MakeSprite(cloudsprite, flatfacing2, flatvelocity2 * 0, .6, 0, 0, 1, .5);
1583         }
1584
1585         emit_sound_at(splattersound, coords);
1586
1587         skeleton.free = 2;
1588         DoDamage(10000);
1589         RagDoll(0);
1590         if (!dead && creature == wolftype) {
1591             award_bonus(0, Wolfbonus);
1592         }
1593         dead = 2;
1594         coords = 20;
1595     }
1596
1597     // play sounds
1598     if (!Tutorial::active || id == 0) {
1599         if (speechdelay <= 0 && !dead && aitype != playercontrolled) {
1600             int whichsound = -1;
1601
1602             if (creature == wolftype) {
1603                 int i = abs(Random() % 2);
1604                 if (i == 0) {
1605                     whichsound = snarlsound;
1606                 }
1607                 if (i == 1) {
1608                     whichsound = snarl2sound;
1609                 }
1610             }
1611             if (creature == rabbittype) {
1612                 int i = abs(Random() % 2);
1613                 if (i == 0) {
1614                     whichsound = rabbitpainsound;
1615                 }
1616                 if (i == 1 && damage > damagetolerance) {
1617                     whichsound = rabbitpain1sound;
1618                 }
1619             }
1620
1621             if (whichsound != -1) {
1622                 emit_sound_at(whichsound, coords);
1623                 addEnvSound(coords);
1624             }
1625         }
1626     }
1627     speechdelay = .3;
1628 }
1629
1630 /* EFFECT
1631  * calculate/animate head facing direction?
1632  */
1633 void Person::DoHead()
1634 {
1635     static XYZ rotatearound;
1636     static XYZ facing;
1637     static float lookspeed = 500;
1638
1639     if (!freeze && !winfreeze) {
1640
1641         //head facing
1642         targetheadyaw = (float)((int)((0 - yaw - targetheadyaw + 180) * 100) % 36000) / 100;
1643         targetheadpitch = (float)((int)(targetheadpitch * 100) % 36000) / 100;
1644
1645         while (targetheadyaw > 180) {
1646             targetheadyaw -= 360;
1647         }
1648         while (targetheadyaw < -180) {
1649             targetheadyaw += 360;
1650         }
1651
1652         if (targetheadyaw > 160) {
1653             targetheadpitch = targetheadpitch * -1;
1654         }
1655         if (targetheadyaw < -160) {
1656             targetheadpitch = targetheadpitch * -1;
1657         }
1658         if (targetheadyaw > 160) {
1659             targetheadyaw = targetheadyaw - 180;
1660         }
1661         if (targetheadyaw < -160) {
1662             targetheadyaw = targetheadyaw + 180;
1663         }
1664
1665         if (targetheadpitch > 120) {
1666             targetheadpitch = 120;
1667         }
1668         if (targetheadpitch < -120) {
1669             targetheadpitch = -120;
1670         }
1671         if (targetheadyaw > 120) {
1672             targetheadyaw = 120;
1673         }
1674         if (targetheadyaw < -120) {
1675             targetheadyaw = -120;
1676         }
1677
1678         if (!isIdle()) {
1679             targetheadpitch = 0;
1680         }
1681         if (isIdle()) {
1682             if (targetheadyaw > 80) {
1683                 targetheadyaw = 80;
1684             }
1685             if (targetheadyaw < -80) {
1686                 targetheadyaw = -80;
1687             }
1688             if (targetheadpitch > 50) {
1689                 targetheadpitch = 50;
1690             }
1691             if (targetheadpitch < -50) {
1692                 targetheadpitch = -50;
1693             }
1694         }
1695
1696         if (abs(headyaw - targetheadyaw) < multiplier * lookspeed) {
1697             headyaw = targetheadyaw;
1698         } else if (headyaw > targetheadyaw) {
1699             headyaw -= multiplier * lookspeed;
1700         } else if (headyaw < targetheadyaw) {
1701             headyaw += multiplier * lookspeed;
1702         }
1703
1704         if (abs(headpitch - targetheadpitch) < multiplier * lookspeed / 2) {
1705             headpitch = targetheadpitch;
1706         } else if (headpitch > targetheadpitch) {
1707             headpitch -= multiplier * lookspeed / 2;
1708         } else if (headpitch < targetheadpitch) {
1709             headpitch += multiplier * lookspeed / 2;
1710         }
1711
1712         rotatearound = jointPos(neck);
1713         jointPos(head) = rotatearound + DoRotation(jointPos(head) - rotatearound, headpitch, 0, 0);
1714
1715         facing = 0;
1716         facing.z = -1;
1717         if (animTarget != bounceidleanim && animTarget != fightidleanim && animTarget != wolfidle && animTarget != knifefightidleanim && animTarget != drawrightanim && animTarget != drawleftanim && animTarget != walkanim) {
1718             facing = DoRotation(facing, headpitch * .4, 0, 0);
1719             facing = DoRotation(facing, 0, headyaw * .4, 0);
1720         }
1721
1722         if (animTarget == bounceidleanim || animTarget == fightidleanim || animTarget == wolfidle || animTarget == knifefightidleanim || animTarget == drawrightanim || animTarget == drawleftanim) {
1723             facing = DoRotation(facing, headpitch * .8, 0, 0);
1724             facing = DoRotation(facing, 0, headyaw * .8, 0);
1725         }
1726
1727         if (animTarget == walkanim) {
1728             facing = DoRotation(facing, headpitch * .6, 0, 0);
1729             facing = DoRotation(facing, 0, headyaw * .6, 0);
1730         }
1731
1732         skeleton.specialforward[0] = facing;
1733         //skeleton.specialforward[0]=DoRotation(facing,0,yaw,0);
1734         for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
1735             if (skeleton.muscles[i].visible && (skeleton.muscles[i].parent1->label == head || skeleton.muscles[i].parent2->label == head)) {
1736                 skeleton.FindRotationMuscle(i, animTarget);
1737             }
1738         }
1739     }
1740 }
1741
1742 /* EFFECT
1743  * ragdolls character?
1744  */
1745 void Person::RagDoll(bool checkcollision)
1746 {
1747     static XYZ change;
1748     static int i;
1749     static float speed;
1750     if (!skeleton.free) {
1751         if (id == 0) {
1752             numfalls++;
1753         }
1754         if (id == 0 && isFlip()) {
1755             numflipfail++;
1756         }
1757
1758         escapednum = 0;
1759
1760         facing = 0;
1761         facing.z = 1;
1762         facing = DoRotation(facing, 0, yaw, 0);
1763
1764         skeleton.freetime = 0;
1765
1766         skeleton.longdead = 0;
1767
1768         skeleton.free = 1;
1769         skeleton.broken = 0;
1770         skeleton.spinny = 1;
1771         freefall = 1;
1772         skeleton.freefall = 1;
1773
1774         if (!isnormal(velocity.x)) {
1775             velocity.x = 0;
1776         }
1777         if (!isnormal(velocity.y)) {
1778             velocity.y = 0;
1779         }
1780         if (!isnormal(velocity.z)) {
1781             velocity.z = 0;
1782         }
1783         if (!isnormal(yaw)) {
1784             yaw = 0;
1785         }
1786         if (!isnormal(coords.x)) {
1787             coords = 0;
1788         }
1789         if (!isnormal(tilt)) {
1790             tilt = 0;
1791         }
1792         if (!isnormal(tilt2)) {
1793             tilt2 = 0;
1794         }
1795
1796         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
1797             skeleton.joints[i].delay = 0;
1798             skeleton.joints[i].locked = 0;
1799             skeleton.joints[i].position = DoRotation(DoRotation(DoRotation(skeleton.joints[i].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
1800             if (!isnormal(skeleton.joints[i].position.x)) {
1801                 skeleton.joints[i].position = DoRotation(skeleton.joints[i].position, 0, yaw, 0);
1802             }
1803             if (!isnormal(skeleton.joints[i].position.x)) {
1804                 skeleton.joints[i].position = coords;
1805             }
1806             skeleton.joints[i].position.y += .1;
1807             skeleton.joints[i].oldposition = skeleton.joints[i].position;
1808             skeleton.joints[i].realoldposition = skeleton.joints[i].position * scale + coords;
1809         }
1810
1811         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
1812             skeleton.joints[i].velocity = 0;
1813             skeleton.joints[i].velchange = 0;
1814         }
1815         skeleton.DoConstraints(&coords, &scale);
1816         if (Animation::animations[animCurrent].height == lowheight || Animation::animations[animTarget].height == lowheight) {
1817             skeleton.DoConstraints(&coords, &scale);
1818             skeleton.DoConstraints(&coords, &scale);
1819             skeleton.DoConstraints(&coords, &scale);
1820             skeleton.DoConstraints(&coords, &scale);
1821         }
1822
1823         speed = targetFrame().speed * 2;
1824         if (currentFrame().speed > targetFrame().speed) {
1825             speed = currentFrame().speed * 2;
1826         }
1827         if (transspeed) {
1828             speed = transspeed * 2;
1829         }
1830
1831         speed *= speedmult;
1832
1833         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
1834             if ((Animation::animations[animCurrent].attack != reversed || animCurrent == swordslashreversedanim) && animCurrent != rabbitkickanim && !isLanding() && !wasLanding() && Animation::animations[animCurrent].height == Animation::animations[animTarget].height) {
1835                 skeleton.joints[i].velocity = velocity / scale + facing * 5 + DoRotation(DoRotation(DoRotation((targetFrame().joints[i].position - currentFrame().joints[i].position) * speed, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0);
1836             } else {
1837                 skeleton.joints[i].velocity = velocity / scale + facing * 5;
1838             }
1839             change.x = (float)(Random() % 100) / 100;
1840             change.y = (float)(Random() % 100) / 100;
1841             change.z = (float)(Random() % 100) / 100;
1842             skeleton.joints[i].velocity += change;
1843             skeleton.joints[fabs(Random() % skeleton.joints.size())].velocity -= change;
1844
1845             change.x = (float)(Random() % 100) / 100;
1846             change.y = (float)(Random() % 100) / 100;
1847             change.z = (float)(Random() % 100) / 100;
1848             skeleton.joints[i].velchange += change;
1849             skeleton.joints[fabs(Random() % skeleton.joints.size())].velchange -= change;
1850         }
1851
1852         if (checkcollision) {
1853             XYZ lowpoint;
1854             XYZ colpoint;
1855             if (!skeleton.joints.empty()) {
1856                 XYZ average;
1857                 average = 0;
1858                 for (unsigned j = 0; j < skeleton.joints.size(); j++) {
1859                     average += skeleton.joints[j].position;
1860                 }
1861                 average /= skeleton.joints.size();
1862                 coords += average * scale;
1863                 for (unsigned j = 0; j < skeleton.joints.size(); j++) {
1864                     skeleton.joints[j].position -= average;
1865                 }
1866             }
1867
1868             whichpatchx = coords.x / (terrain.size / subdivision * terrain.scale);
1869             whichpatchz = coords.z / (terrain.size / subdivision * terrain.scale);
1870             for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
1871                 i = terrain.patchobjects[whichpatchx][whichpatchz][l];
1872                 lowpoint = coords;
1873                 lowpoint.y += 1;
1874                 if (SphereCheck(&lowpoint, 3, &colpoint, &Object::objects[i]->position, &Object::objects[i]->yaw, &Object::objects[i]->model) != -1) {
1875                     coords.x = lowpoint.x;
1876                     coords.z = lowpoint.z;
1877                 }
1878             }
1879         }
1880
1881         yaw = 0;
1882         updatedelay = 0;
1883
1884         velocity = 0;
1885         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
1886             velocity += skeleton.joints[i].velocity * scale;
1887         }
1888         velocity /= skeleton.joints.size();
1889
1890         // drop weapon
1891         if (Random() % 2 == 0) {
1892             if (weaponactive != -1 && animTarget != rabbitkickanim && num_weapons > 0) {
1893                 weapons[weaponids[0]].drop(jointVel(righthand) * scale * -.3, jointVel(righthand) * scale);
1894                 weapons[weaponids[0]].velocity.x += .01;
1895                 num_weapons--;
1896                 if (num_weapons) {
1897                     weaponids[0] = weaponids[num_weapons];
1898                     if (weaponstuck == num_weapons) {
1899                         weaponstuck = 0;
1900                     }
1901                 }
1902                 weaponactive = -1;
1903                 for (unsigned i = 0; i < Person::players.size(); i++) {
1904                     Person::players[i]->wentforweapon = 0;
1905                 }
1906             }
1907         }
1908
1909         animTarget = bounceidleanim;
1910         animCurrent = bounceidleanim;
1911         frameTarget = 0;
1912         frameCurrent = 0;
1913     }
1914 }
1915
1916 /* EFFECT
1917  */
1918 void Person::FootLand(bodypart whichfoot, float opacity)
1919 {
1920     if ((whichfoot != leftfoot) && (whichfoot != rightfoot)) {
1921         cerr << "FootLand called on wrong bodypart" << endl;
1922         return;
1923     }
1924     static XYZ terrainlight;
1925     static XYZ footvel, footpoint;
1926     if (opacity >= 1 || skiddelay <= 0) {
1927         if (opacity > 1) {
1928             footvel = 0;
1929             footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
1930             if (distsq(&footpoint, &viewer)) {
1931                 Sprite::MakeSprite(cloudsprite, footpoint, footvel, 1, 1, 1, .5, .2 * opacity);
1932             }
1933         } else if (onterrain && terrain.getOpacity(coords.x, coords.z) < .2) {
1934             footvel = velocity / 5;
1935             if (footvel.y < .8) {
1936                 footvel.y = .8;
1937             }
1938             footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
1939             footpoint.y = terrain.getHeight(footpoint.x, footpoint.z);
1940             terrainlight = terrain.getLighting(footpoint.x, footpoint.z);
1941             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
1942                 if (environment == snowyenvironment) {
1943                     Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x, terrainlight.y, terrainlight.z, .5, .7 * opacity);
1944                     if (detail == 2) {
1945                         terrain.MakeDecal(footprintdecal, footpoint, .2, 1 * opacity, yaw);
1946                     }
1947                 } else if (environment == grassyenvironment) {
1948                     Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 90 / 255, terrainlight.y * 70 / 255, terrainlight.z * 8 / 255, .5, .5 * opacity);
1949                 } else if (environment == desertenvironment) {
1950                     Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, terrainlight.x * 190 / 255, terrainlight.y * 170 / 255, terrainlight.z * 108 / 255, .5, .7 * opacity);
1951                     if (detail == 2) {
1952                         terrain.MakeDecal(footprintdecal, footpoint, .2, .25 * opacity, yaw);
1953                     }
1954                 }
1955             }
1956         } else if (isLanding() || (animTarget == jumpupanim) || isLandhard()) {
1957             footvel = velocity / 5;
1958             if (footvel.y < .8) {
1959                 footvel.y = .8;
1960             }
1961             footpoint = DoRotation(jointPos(whichfoot), 0, yaw, 0) * scale + coords;
1962             if (distsq(&footpoint, &viewer) < viewdistance * viewdistance / 4) {
1963                 Sprite::MakeSprite(cloudsprite, footpoint, footvel * .6, 1, 1, 1, .5, .2 * opacity);
1964             }
1965         }
1966     }
1967 }
1968
1969 /* EFFECT
1970  * make a puff effect at a body part (dust effect?)
1971  */
1972 void Person::Puff(int whichlabel)
1973 {
1974     static XYZ footvel, footpoint;
1975
1976     footvel = 0;
1977     footpoint = DoRotation(jointPos(whichlabel), 0, yaw, 0) * scale + coords;
1978     Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 1, 1, .9, .3);
1979 }
1980
1981 /* EFFECT
1982  * I think I added this in an attempt to clean up code
1983  */
1984 void Person::setTargetAnimation(int animation)
1985 {
1986     animTarget = animation;
1987     frameTarget = 0;
1988     target = 0;
1989 }
1990
1991 /* EFFECT
1992  * MONSTER
1993  * TODO: ???
1994  */
1995 void Person::DoAnimations()
1996 {
1997     if (!skeleton.free) {
1998         static float oldtarget;
1999
2000         if (isIdle() && animCurrent != getIdle()) {
2001             normalsupdatedelay = 0;
2002         }
2003
2004         if (animTarget == tempanim || animCurrent == tempanim) {
2005             Animation::animations[tempanim] = tempanimation;
2006         }
2007         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
2008             float gLoc[3];
2009             gLoc[0] = coords.x;
2010             gLoc[1] = coords.y;
2011             gLoc[2] = coords.z;
2012
2013             if (id == 0) {
2014                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc);
2015                 OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
2016             }
2017             if (((velocity.y < -15) || (crouchkeydown && velocity.y < -8)) && abs(velocity.y) * 4 > fast_sqrt(velocity.x * velocity.x * velocity.z * velocity.z)) {
2018                 landhard = 1;
2019             }
2020             if (!crouchkeydown && velocity.y >= -15) {
2021                 landhard = 0;
2022             }
2023         }
2024         if ((animCurrent == jumpupanim || animTarget == jumpdownanim) /*&&velocity.y<40*/ && !isFlip() && (!isLanding() && !isLandhard()) && ((crouchkeydown && !crouchtogglekeydown))) {
2025             XYZ targfacing;
2026             targfacing = 0;
2027             targfacing.z = 1;
2028
2029             targfacing = DoRotation(targfacing, 0, targetyaw, 0);
2030
2031             if (normaldotproduct(targfacing, velocity) >= -.3) {
2032                 animTarget = flipanim;
2033             } else {
2034                 animTarget = backflipanim;
2035             }
2036             crouchtogglekeydown = 1;
2037             frameTarget = 0;
2038             target = 0;
2039
2040             if (id == 0) {
2041                 numflipped++;
2042             }
2043         }
2044
2045         if (Animation::animations[animTarget].attack != reversed) {
2046             feint = 0;
2047         }
2048         if (!crouchkeydown || (isLanding() || isLandhard()) || (wasLanding() || wasLandhard())) {
2049             crouchtogglekeydown = 0;
2050             if (aitype == playercontrolled) {
2051                 feint = 0;
2052             }
2053         } else {
2054             if (!crouchtogglekeydown && Animation::animations[animTarget].attack == reversed && aitype == playercontrolled && (escapednum < 2 || reversaltrain)) {
2055                 feint = 1;
2056             }
2057             if (!isFlip()) {
2058                 crouchtogglekeydown = 1;
2059             }
2060         }
2061
2062         if (Animation::animations[animTarget].attack || animCurrent == getupfrombackanim || animCurrent == getupfromfrontanim) {
2063             if (detail) {
2064                 normalsupdatedelay = 0;
2065             }
2066         }
2067
2068         if (target >= 1) {
2069             if (animTarget == rollanim && frameTarget == 3 && onfire) {
2070                 onfire = 0;
2071                 emit_sound_at(fireendsound, coords);
2072                 pause_sound(stream_firesound);
2073                 deathbleeding = 0;
2074             }
2075
2076             if (animTarget == rabbittacklinganim && frameTarget == 1) {
2077                 if (victim->aitype == attacktypecutoff && victim->stunned <= 0 && victim->surprised <= 0 && victim->id != 0) {
2078                     Reverse();
2079                 }
2080                 if (animTarget == rabbittacklinganim && frameTarget == 1 && !victim->isCrouch() && victim->animTarget != backhandspringanim) {
2081                     if (normaldotproduct(victim->facing, facing) > 0) {
2082                         victim->animTarget = rabbittackledbackanim;
2083                     } else {
2084                         victim->animTarget = rabbittackledfrontanim;
2085                     }
2086                     victim->frameTarget = 2;
2087                     victim->target = 0;
2088                     victim->yaw = yaw;
2089                     victim->targetyaw = yaw;
2090                     if (victim->aitype == gethelptype) {
2091                         victim->DoDamage(victim->damagetolerance - victim->damage);
2092                     }
2093                     //victim->DoDamage(30);
2094                     if (creature == wolftype) {
2095                         DoBloodBig(0, 255);
2096                         emit_sound_at(clawslicesound, victim->coords);
2097                         victim->spurt = 1;
2098                         victim->DoBloodBig(1 / victim->armorhead, 210);
2099                     }
2100                     award_bonus(id, TackleBonus,
2101                                 victim->aitype == gethelptype ? 50 : 0);
2102                 }
2103             }
2104
2105             if (!drawtogglekeydown && drawkeydown && (weaponactive == -1 || num_weapons == 1) && (targetFrame().label || (animTarget != animCurrent && animCurrent == rollanim)) && num_weapons > 0 && creature != wolftype) {
2106                 if (weapons[weaponids[0]].getType() == knife) {
2107                     if (weaponactive == -1) {
2108                         weaponactive = 0;
2109                     } else if (weaponactive == 0) {
2110                         weaponactive = -1;
2111                     }
2112
2113                     if (weaponactive == -1) {
2114                         emit_sound_at(knifesheathesound, coords);
2115                     }
2116                     if (weaponactive != -1) {
2117                         emit_sound_at(knifedrawsound, coords, 128);
2118                     }
2119                 }
2120                 drawtogglekeydown = 1;
2121             }
2122             //Footstep sounds
2123             if (!Tutorial::active || id == 0) {
2124                 if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
2125                     int whichsound = -1;
2126                     if (onterrain) {
2127                         if (terrain.getOpacity(coords.x, coords.z) < .2) {
2128                             if (targetFrame().label == 1) {
2129                                 whichsound = footstepsound;
2130                             } else {
2131                                 whichsound = footstepsound2;
2132                             }
2133                             if (targetFrame().label == 1) {
2134                                 FootLand(leftfoot, 1);
2135                             }
2136                             if (targetFrame().label == 2) {
2137                                 FootLand(rightfoot, 1);
2138                             }
2139                             if (targetFrame().label == 3 && isRun()) {
2140                                 FootLand(rightfoot, 1);
2141                                 FootLand(leftfoot, 1);
2142                             }
2143                         }
2144                         if (terrain.getOpacity(coords.x, coords.z) >= .2) {
2145                             if (targetFrame().label == 1) {
2146                                 whichsound = footstepsound3;
2147                             } else {
2148                                 whichsound = footstepsound4;
2149                             }
2150                         }
2151                     }
2152                     if (!onterrain) {
2153                         if (targetFrame().label == 1) {
2154                             whichsound = footstepsound3;
2155                         } else {
2156                             whichsound = footstepsound4;
2157                         }
2158                     }
2159                     if (targetFrame().label == 4 && (weaponactive == -1 || (animTarget != knifeslashstartanim && animTarget != knifethrowanim && animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != knifefollowanim))) {
2160                         if (Animation::animations[animTarget].attack != neutral) {
2161                             unsigned r = abs(Random() % 3);
2162                             if (r == 0) {
2163                                 whichsound = lowwhooshsound;
2164                             }
2165                             if (r == 1) {
2166                                 whichsound = midwhooshsound;
2167                             }
2168                             if (r == 2) {
2169                                 whichsound = highwhooshsound;
2170                             }
2171                         }
2172                         if (Animation::animations[animTarget].attack == neutral) {
2173                             whichsound = movewhooshsound;
2174                         }
2175                     } else if (targetFrame().label == 4) {
2176                         whichsound = knifeswishsound;
2177                     }
2178                     if (targetFrame().label == 8 && !Tutorial::active) {
2179                         whichsound = landsound2;
2180                     }
2181
2182                     if (whichsound != -1) {
2183                         emit_sound_at(whichsound, coords, 256.);
2184
2185                         if (id == 0) {
2186                             if (whichsound == footstepsound || whichsound == footstepsound2 || whichsound == footstepsound3 || whichsound == footstepsound4) {
2187                                 if (animTarget == wolfrunninganim || animTarget == rabbitrunninganim) {
2188                                     addEnvSound(coords, 15);
2189                                 } else {
2190                                     addEnvSound(coords, 6);
2191                                 }
2192                             }
2193                         }
2194
2195                         if (targetFrame().label == 3) {
2196                             whichsound--;
2197                             emit_sound_at(whichsound, coords, 128.);
2198                         }
2199                     }
2200                 }
2201             }
2202
2203             //Combat sounds
2204             if (!Tutorial::active || id == 0) {
2205                 if (speechdelay <= 0) {
2206                     if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) {
2207                         if ((targetFrame().label && (targetFrame().label < 5 || targetFrame().label == 8))) {
2208                             int whichsound = -1;
2209                             if (targetFrame().label == 4 && aitype != playercontrolled) {
2210                                 if (Animation::animations[animTarget].attack != neutral) {
2211                                     unsigned r = abs(Random() % 4);
2212                                     whichsound = PersonType::types[creature].soundsAttack[r];
2213                                     speechdelay = .3;
2214                                 }
2215                             }
2216
2217                             if (whichsound != -1) {
2218                                 emit_sound_at(whichsound, coords);
2219                             }
2220                         }
2221                     }
2222                 }
2223             }
2224
2225             if ((!wasLanding() && !wasLandhard()) && animCurrent != getIdle() && (isLanding() || isLandhard())) {
2226                 FootLand(leftfoot, 1);
2227                 FootLand(rightfoot, 1);
2228             }
2229
2230             transspeed = 0;
2231             currentoffset = targetoffset;
2232             frameTarget = frameCurrent;
2233             animCurrent = animTarget;
2234             frameTarget++;
2235
2236             if (animCurrent == removeknifeanim && currentFrame().label == 5) {
2237                 for (unsigned i = 0; i < weapons.size(); i++) {
2238                     if (weapons[i].owner == -1) {
2239                         if (distsqflat(&coords, &weapons[i].position) < 4 && weaponactive == -1) {
2240                             if (distsq(&coords, &weapons[i].position) >= 1) {
2241                                 if (weapons[i].getType() != staff) {
2242                                     emit_sound_at(knifedrawsound, coords, 128.);
2243                                 }
2244
2245                                 takeWeapon(i);
2246                             }
2247                         }
2248                     }
2249                 }
2250             }
2251
2252             if (animCurrent == crouchremoveknifeanim && currentFrame().label == 5) {
2253                 for (unsigned i = 0; i < weapons.size(); i++) {
2254                     bool willwork = true;
2255                     if (weapons[i].owner != -1) {
2256                         if (Person::players[weapons[i].owner]->weaponstuck != -1) {
2257                             if (Person::players[weapons[i].owner]->weaponids[Person::players[weapons[i].owner]->weaponstuck] == int(i)) {
2258                                 if (Person::players[weapons[i].owner]->num_weapons > 1) {
2259                                     willwork = 0;
2260                                 }
2261                             }
2262                         }
2263                     }
2264                     if ((weapons[i].owner == -1) || (hasvictim && (weapons[i].owner == int(victim->id)) && victim->skeleton.free)) {
2265                         if (willwork && distsqflat(&coords, &weapons[i].position) < 3 && weaponactive == -1) {
2266                             if (distsq(&coords, &weapons[i].position) < 1 || hasvictim) {
2267                                 bool fleshstuck = false;
2268                                 if (weapons[i].owner != -1) {
2269                                     if (victim->weaponstuck != -1) {
2270                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
2271                                             fleshstuck = true;
2272                                         }
2273                                     }
2274                                 }
2275                                 if (fleshstuck) {
2276                                     emit_sound_at(fleshstabremovesound, coords, 128.);
2277                                 } else {
2278                                     if (weapons[i].getType() != staff) {
2279                                         emit_sound_at(knifedrawsound, coords, 128.);
2280                                     }
2281                                 }
2282                                 if (weapons[i].owner != -1) {
2283                                     victim = Person::players[weapons[i].owner];
2284                                     if (victim->num_weapons == 1) {
2285                                         victim->num_weapons = 0;
2286                                     } else {
2287                                         victim->num_weapons = 1;
2288                                     }
2289
2290                                     //victim->weaponactive=-1;
2291                                     victim->skeleton.longdead = 0;
2292                                     victim->skeleton.free = 1;
2293                                     victim->skeleton.broken = 0;
2294
2295                                     for (unsigned j = 0; j < victim->skeleton.joints.size(); j++) {
2296                                         victim->skeleton.joints[j].velchange = 0;
2297                                         victim->skeleton.joints[j].locked = 0;
2298                                     }
2299
2300                                     XYZ relative;
2301                                     relative = 0;
2302                                     relative.y = 10;
2303                                     Normalise(&relative);
2304                                     XYZ footvel, footpoint;
2305                                     footvel = 0;
2306                                     footpoint = weapons[i].position;
2307                                     if (victim->weaponstuck != -1) {
2308                                         if (victim->weaponids[victim->weaponstuck] == int(i)) {
2309                                             if (bloodtoggle) {
2310                                                 Sprite::MakeSprite(cloudimpactsprite, footpoint, footvel, 1, 0, 0, .8, .3);
2311                                             }
2312                                             weapons[i].bloody = 2;
2313                                             weapons[i].blooddrip = 5;
2314                                             victim->weaponstuck = -1;
2315                                         }
2316                                     }
2317                                     if (victim->num_weapons > 0) {
2318                                         if (victim->weaponstuck != 0 && victim->weaponstuck != -1) {
2319                                             victim->weaponstuck = 0;
2320                                         }
2321                                         if (victim->weaponids[0] == int(i)) {
2322                                             victim->weaponids[0] = victim->weaponids[victim->num_weapons];
2323                                         }
2324                                     }
2325
2326                                     victim->jointVel(abdomen) += relative * 6;
2327                                     victim->jointVel(neck) += relative * 6;
2328                                     victim->jointVel(rightshoulder) += relative * 6;
2329                                     victim->jointVel(leftshoulder) += relative * 6;
2330                                 }
2331                                 takeWeapon(i);
2332                             }
2333                         }
2334                     }
2335                 }
2336             }
2337
2338             if (animCurrent == drawleftanim && currentFrame().label == 5) {
2339                 if (weaponactive == -1) {
2340                     weaponactive = 0;
2341                 } else if (weaponactive == 0) {
2342                     weaponactive = -1;
2343                     if (num_weapons == 2) {
2344                         int buffer;
2345                         buffer = weaponids[0];
2346                         weaponids[0] = weaponids[1];
2347                         weaponids[1] = buffer;
2348                     }
2349                 }
2350                 if (weaponactive == -1) {
2351                     emit_sound_at(knifesheathesound, coords, 128.);
2352                 }
2353                 if (weaponactive != -1) {
2354                     emit_sound_at(knifedrawsound, coords, 128.);
2355                 }
2356             }
2357
2358             if ((animCurrent == walljumprightkickanim && animTarget == walljumprightkickanim) || (animCurrent == walljumpleftkickanim && animTarget == walljumpleftkickanim)) {
2359                 XYZ rotatetarget = DoRotation(skeleton.forward, 0, yaw, 0);
2360                 Normalise(&rotatetarget);
2361                 targetyaw = -asin(0 - rotatetarget.x);
2362                 targetyaw *= 360 / 6.28;
2363                 if (rotatetarget.z < 0) {
2364                     targetyaw = 180 - targetyaw;
2365                 }
2366
2367                 if (animTarget == walljumprightkickanim) {
2368                     targetyaw += 40;
2369                 }
2370                 if (animTarget == walljumpleftkickanim) {
2371                     targetyaw -= 40;
2372                 }
2373             }
2374
2375             bool dojumpattack;
2376             dojumpattack = 0;
2377             if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && frameTarget == 3 && (jumpkeydown || attackkeydown || id != 0)) {
2378                 dojumpattack = 1;
2379             }
2380             if (hasvictim) {
2381                 if (distsq(&victim->coords, &/*Person::players[i]->*/ coords) < 5 && victim->aitype == gethelptype && (attackkeydown) && !victim->skeleton.free && victim->isRun() && victim->runninghowlong >= 1) {
2382                     dojumpattack = 1;
2383                 }
2384             }
2385             if (!hostile) {
2386                 dojumpattack = 0;
2387             }
2388             if (dojumpattack) {
2389                 if ((animTarget == rabbitrunninganim || animTarget == wolfrunninganim) && id == 0) {
2390                     animTarget = rabbittackleanim;
2391                     frameTarget = 0;
2392                     emit_sound_at(jumpsound, coords);
2393                 }
2394
2395                 float closestdist;
2396                 closestdist = 0;
2397                 int closestid;
2398                 closestid = -1;
2399                 XYZ targetloc;
2400                 targetloc = velocity;
2401                 Normalise(&targetloc);
2402                 targetloc += coords;
2403                 for (unsigned i = 0; i < Person::players.size(); i++) {
2404                     if (i != id) {
2405                         if (distsq(&targetloc, &Person::players[i]->coords) < closestdist || closestdist == 0) {
2406                             closestdist = distsq(&targetloc, &Person::players[i]->coords);
2407                             closestid = i;
2408                         }
2409                     }
2410                 }
2411                 if (closestid != -1) {
2412                     if (closestdist < 5 && !Person::players[closestid]->dead && Animation::animations[Person::players[closestid]->animTarget].height != lowheight && Person::players[closestid]->animTarget != backhandspringanim) {
2413                         hasvictim = 1;
2414                         victim = Person::players[closestid];
2415                         coords = victim->coords;
2416                         animCurrent = rabbittacklinganim;
2417                         animTarget = rabbittacklinganim;
2418                         frameCurrent = 0;
2419                         frameTarget = 1;
2420                         XYZ rotatetarget;
2421                         if (coords.z != victim->coords.z || coords.x != victim->coords.x) {
2422                             rotatetarget = coords - victim->coords;
2423                             Normalise(&rotatetarget);
2424                             targetyaw = -asin(0 - rotatetarget.x);
2425                             targetyaw *= 360 / 6.28;
2426                             if (rotatetarget.z < 0) {
2427                                 targetyaw = 180 - targetyaw;
2428                             }
2429                         }
2430                         if (animTarget != rabbitrunninganim) {
2431                             emit_sound_at(jumpsound, coords, 128.);
2432                         }
2433                     }
2434                 }
2435             }
2436
2437             //Move impacts
2438             float damagemult = PersonType::types[creature].power * power;
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 (animCurrent == spinkickanim && currentFrame().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 (animCurrent == wolfslapanim && currentFrame().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 (animCurrent == walljumprightkickanim && currentFrame().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 (animCurrent == walljumpleftkickanim && currentFrame().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 (animCurrent == blockhighleftstrikeanim && currentFrame().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 (animCurrent == killanim && currentFrame().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 (animCurrent == killanim && currentFrame().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 (animCurrent == dropkickanim && currentFrame().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 ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().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 ((animCurrent == crouchstabanim || animCurrent == swordgroundstabanim) && currentFrame().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 (animCurrent == upunchanim && currentFrame().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 (animCurrent == winduppunchanim && currentFrame().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 (animCurrent == blockhighleftanim && currentFrame().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 (animCurrent == swordslashparryanim && currentFrame().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 (animCurrent == knifethrowanim && currentFrame().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 (animCurrent == knifeslashstartanim && currentFrame().label == 5) {
3056                     if (hasvictim) {
3057                         if (distsq(&coords, &victim->coords) < (scale * 5) * (scale * 5) * 4.5 && 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 (animCurrent == swordslashanim && currentFrame().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 (animCurrent == staffhitanim && currentFrame().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 (animCurrent == staffspinhitanim && currentFrame().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 (animCurrent == staffgroundsmashanim && currentFrame().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 (animCurrent == lowkickanim && currentFrame().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 (animCurrent == sweepanim && currentFrame().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 (animCurrent == spinkickreversalanim && currentFrame().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 (animCurrent == staffhitreversalanim && currentFrame().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 (animCurrent == staffspinhitreversalanim && currentFrame().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 (animCurrent == upunchreversalanim && currentFrame().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 (animCurrent == swordslashreversalanim && currentFrame().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 && animCurrent == knifeslashreversalanim && currentFrame().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 && animCurrent == sneakattackanim && currentFrame().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 && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().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 && (animCurrent == knifefollowanim || animCurrent == knifesneakattackanim) && currentFrame().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 && (animCurrent == swordsneakattackanim) && currentFrame().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 && animCurrent == swordsneakattackanim && currentFrame().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 (animCurrent == sweepreversalanim && currentFrame().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 (animCurrent == sweepreversalanim && ((currentFrame().label == 9 && victim->damage < victim->damagetolerance) || (currentFrame().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())) {
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
4381             if (frameCurrent >= int(Animation::animations[animCurrent].frames.size())) {
4382                 frameCurrent = Animation::animations[animCurrent].frames.size() - 1;
4383             }
4384
4385             oldrot = rot;
4386             rot = targetrot * target;
4387             yaw += rot - oldrot;
4388             if (target == 1) {
4389                 rot = 0;
4390                 oldrot = 0;
4391                 targetrot = 0;
4392             }
4393
4394             if (animCurrent != oldanimCurrent || animTarget != oldanimTarget || ((frameCurrent != oldframeCurrent || frameTarget != oldframeTarget) && !calcrot)) {
4395                 //Old rotates
4396                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4397                     skeleton.joints[i].position = currentFrame().joints[i].position;
4398                 }
4399
4400                 skeleton.FindForwards();
4401
4402                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4403                     if (skeleton.muscles[i].visible) {
4404                         skeleton.FindRotationMuscle(i, animTarget);
4405                     }
4406                 }
4407                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4408                     if (skeleton.muscles[i].visible) {
4409                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100)) {
4410                             skeleton.muscles[i].oldrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
4411                         }
4412                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100)) {
4413                             skeleton.muscles[i].oldrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
4414                         }
4415                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100)) {
4416                             skeleton.muscles[i].oldrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
4417                         }
4418                     }
4419                 }
4420
4421                 //New rotates
4422                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4423                     skeleton.joints[i].position = targetFrame().joints[i].position;
4424                 }
4425
4426                 skeleton.FindForwards();
4427
4428                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4429                     if (skeleton.muscles[i].visible) {
4430                         skeleton.FindRotationMuscle(i, animTarget);
4431                     }
4432                 }
4433                 for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4434                     if (skeleton.muscles[i].visible) {
4435                         if (isnormal((float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100)) {
4436                             skeleton.muscles[i].newrotate1 = (float)((int)(skeleton.muscles[i].rotate1 * 100) % 36000) / 100;
4437                         }
4438                         if (isnormal((float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100)) {
4439                             skeleton.muscles[i].newrotate2 = (float)((int)(skeleton.muscles[i].rotate2 * 100) % 36000) / 100;
4440                         }
4441                         if (isnormal((float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100)) {
4442                             skeleton.muscles[i].newrotate3 = (float)((int)(skeleton.muscles[i].rotate3 * 100) % 36000) / 100;
4443                         }
4444                         if (skeleton.muscles[i].newrotate3 > skeleton.muscles[i].oldrotate3 + 180) {
4445                             skeleton.muscles[i].newrotate3 -= 360;
4446                         }
4447                         if (skeleton.muscles[i].newrotate3 < skeleton.muscles[i].oldrotate3 - 180) {
4448                             skeleton.muscles[i].newrotate3 += 360;
4449                         }
4450                         if (skeleton.muscles[i].newrotate2 > skeleton.muscles[i].oldrotate2 + 180) {
4451                             skeleton.muscles[i].newrotate2 -= 360;
4452                         }
4453                         if (skeleton.muscles[i].newrotate2 < skeleton.muscles[i].oldrotate2 - 180) {
4454                             skeleton.muscles[i].newrotate2 += 360;
4455                         }
4456                         if (skeleton.muscles[i].newrotate1 > skeleton.muscles[i].oldrotate1 + 180) {
4457                             skeleton.muscles[i].newrotate1 -= 360;
4458                         }
4459                         if (skeleton.muscles[i].newrotate1 < skeleton.muscles[i].oldrotate1 - 180) {
4460                             skeleton.muscles[i].newrotate1 += 360;
4461                         }
4462                     }
4463                 }
4464             }
4465
4466             oldanimCurrent = animCurrent;
4467             oldanimTarget = animTarget;
4468             oldframeTarget = frameTarget;
4469             oldframeCurrent = frameCurrent;
4470
4471             for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4472                 skeleton.joints[i].velocity = (currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * target - skeleton.joints[i].position) / multiplier;
4473                 skeleton.joints[i].position = currentFrame().joints[i].position * (1 - target) + targetFrame().joints[i].position * target;
4474             }
4475             offset = currentoffset * (1 - target) + targetoffset * target;
4476             for (unsigned i = 0; i < skeleton.muscles.size(); i++) {
4477                 if (skeleton.muscles[i].visible) {
4478                     skeleton.muscles[i].rotate1 = skeleton.muscles[i].oldrotate1 * (1 - target) + skeleton.muscles[i].newrotate1 * target;
4479                     skeleton.muscles[i].rotate2 = skeleton.muscles[i].oldrotate2 * (1 - target) + skeleton.muscles[i].newrotate2 * target;
4480                     skeleton.muscles[i].rotate3 = skeleton.muscles[i].oldrotate3 * (1 - target) + skeleton.muscles[i].newrotate3 * target;
4481                 }
4482             }
4483         }
4484
4485         if (isLanding() && landhard) {
4486             if (id == 0) {
4487                 camerashake += .4;
4488             }
4489             animTarget = getLandhard();
4490             frameTarget = 0;
4491             target = 0;
4492             landhard = 0;
4493             transspeed = 15;
4494         }
4495     }
4496 }
4497
4498 /* EFFECT
4499  * MONSTER
4500  * TODO
4501  */
4502 void Person::DoStuff()
4503 {
4504     static XYZ terrainnormal;
4505     static XYZ flatfacing;
4506     static XYZ flatvelocity;
4507     static float flatvelspeed;
4508     static int bloodsize;
4509     static int startx, starty, endx, endy;
4510     static GLubyte color;
4511     static XYZ bloodvel;
4512
4513     onfiredelay -= multiplier;
4514     if (onfiredelay < 0 && onfire) {
4515         if (Random() % 2 == 0) {
4516             crouchkeydown = 1;
4517         }
4518         onfiredelay = 0.3;
4519     }
4520
4521     crouchkeydowntime += multiplier;
4522     if (!crouchkeydown) {
4523         crouchkeydowntime = 0;
4524     }
4525     jumpkeydowntime += multiplier;
4526     if (!jumpkeydown && skeleton.free) {
4527         jumpkeydowntime = 0;
4528     }
4529
4530     if (hostile || damage > 0 || bloodloss > 0) {
4531         immobile = 0;
4532     }
4533
4534     if (isIdle() || isRun()) {
4535         targetoffset = 0;
4536     }
4537
4538     if (num_weapons == 1 && weaponactive != -1) {
4539         weaponstuck = -1;
4540     }
4541
4542     if (id == 0) {
4543         blooddimamount -= multiplier * .3;
4544     }
4545     speechdelay -= multiplier;
4546     texupdatedelay -= multiplier;
4547     interestdelay -= multiplier;
4548     flamedelay -= multiplier;
4549     parriedrecently -= multiplier;
4550     if (!victim) {
4551         victim = this->shared_from_this();
4552         hasvictim = 0;
4553     }
4554
4555     if (id == 0) {
4556         speed = 1.1 * speedmult;
4557     } else {
4558         speed = 1.0 * speedmult;
4559     }
4560     if (!skeleton.free) {
4561         rabbitkickragdoll = 0;
4562     }
4563
4564     speed *= speedmult;
4565
4566     if (id != 0 && (creature == rabbittype || difficulty != 2)) {
4567         superruntoggle = 0;
4568     }
4569     if (id != 0 && creature == wolftype && difficulty == 2) {
4570         superruntoggle = 0;
4571         if (aitype != passivetype) {
4572             superruntoggle = 1;
4573             if (aitype == attacktypecutoff && (Person::players[0]->isIdle() || Person::players[0]->isCrouch() || Person::players[0]->skeleton.free || Person::players[0]->animTarget == getupfrombackanim || Person::players[0]->animTarget == getupfromfrontanim || Person::players[0]->animTarget == sneakanim) && distsq(&coords, &Person::players[0]->coords) < 16) {
4574                 superruntoggle = 0;
4575             }
4576         }
4577         if (scale < 0.2) {
4578             superruntoggle = 0;
4579         }
4580         if (animTarget == wolfrunninganim && !superruntoggle) {
4581             animTarget = getRun();
4582             frameTarget = 0;
4583         }
4584     }
4585     if (weaponactive == -1 && num_weapons > 0) {
4586         if (weapons[weaponids[0]].getType() == staff) {
4587             weaponactive = 0;
4588         }
4589     }
4590
4591     if (onfire) {
4592         burnt += multiplier;
4593         deathbleeding = 1;
4594         if (burnt > .6) {
4595             burnt = .6;
4596         }
4597         OPENAL_SetVolume(channels[stream_firesound], 256 + 256 * findLength(&velocity) / 3);
4598
4599         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
4600             float gLoc[3];
4601             gLoc[0] = coords.x;
4602             gLoc[1] = coords.y;
4603             gLoc[2] = coords.z;
4604
4605             if (id == 0) {
4606                 OPENAL_3D_SetAttributes(channels[whooshsound], gLoc);
4607                 OPENAL_SetVolume(channels[whooshsound], 64 * findLength(&velocity) / 5);
4608             }
4609         }
4610     }
4611     while (flamedelay < 0 && onfire) {
4612         flamedelay += .006;
4613         int howmany = fabs(Random() % (skeleton.joints.size()));
4614         if (skeleton.free) {
4615             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4616             flatfacing = skeleton.joints[howmany].position * scale + coords;
4617         } else {
4618             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4619             flatvelocity = (coords - oldcoords) / multiplier / 2;
4620         }
4621         Sprite::MakeSprite(flamesprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, 1);
4622     }
4623
4624     while (flamedelay < 0 && !onfire && Tutorial::active && id != 0) {
4625         flamedelay += .05;
4626         int howmany = fabs(Random() % (skeleton.joints.size()));
4627         if (skeleton.free) {
4628             flatvelocity = skeleton.joints[howmany].velocity * scale / 2;
4629             flatfacing = skeleton.joints[howmany].position * scale + coords;
4630         } else {
4631             flatvelocity = (coords - oldcoords) / multiplier / 2;
4632             flatfacing = DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords;
4633         }
4634         Sprite::MakeSprite(breathsprite, flatfacing, flatvelocity, 1, 1, 1, .6 + (float)abs(Random() % 100) / 200 - .25, .3);
4635     }
4636
4637     if (bleeding > 0) {
4638         bleeding -= multiplier * .3;
4639         if (bloodtoggle == 2) {
4640             skeleton.drawmodel.textureptr.bind();
4641             if ((bleeding <= 0) && (detail != 2)) {
4642                 DoMipmaps();
4643             }
4644         }
4645     }
4646
4647     if (neckspurtamount > 0) {
4648         neckspurtamount -= multiplier;
4649         neckspurtdelay -= multiplier * 3;
4650         neckspurtparticledelay -= multiplier * 3;
4651         if (neckspurtparticledelay < 0 && neckspurtdelay > 2) {
4652             spurt = 0;
4653             bloodvel = 0;
4654             if (skeleton.free) {
4655                 bloodvel -= DoRotation(skeleton.forward * 10 * scale, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0);
4656                 bloodvel += DoRotation(jointVel(head), ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4657                 Sprite::MakeSprite(bloodsprite, (jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5) * scale + coords, bloodvel, 1, 1, 1, .05, .9);
4658             } else {
4659                 bloodvel.z = 5 * neckspurtamount;
4660                 bloodvel = DoRotation(bloodvel, ((float)(Random() % 100)) / 40, yaw + ((float)(Random() % 100)) / 40, 0) * scale;
4661                 bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 40, ((float)(Random() % 100)) / 40, 0) * scale;
4662                 Sprite::MakeSprite(bloodsprite, DoRotation(jointPos(neck) + (jointPos(neck) - jointPos(head)) / 5, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, .9);
4663             }
4664             neckspurtparticledelay = .05;
4665         }
4666         if (neckspurtdelay < 0) {
4667             neckspurtdelay = 3;
4668         }
4669     }
4670
4671     if (deathbleeding > 0 && dead != 2) {
4672         if (deathbleeding < 5) {
4673             bleeddelay -= deathbleeding * multiplier / 4;
4674         } else {
4675             bleeddelay -= 5 * multiplier / 4;
4676         }
4677         if (bleeddelay < 0 && bloodtoggle) {
4678             bleeddelay = 1;
4679             XYZ bloodvel;
4680             if (bloodtoggle) {
4681                 bloodvel = 0;
4682                 if (skeleton.free) {
4683                     bloodvel += DoRotation(jointVel(abdomen), ((float)(Random() % 100)) / 4, yaw + ((float)(Random() % 100)) / 4, 0) * scale;
4684                     Sprite::MakeSprite(bloodsprite, jointPos(abdomen) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
4685                 } else {
4686                     bloodvel += DoRotation(velocity, ((float)(Random() % 100)) / 4, ((float)(Random() % 100)) / 4, 0) * scale;
4687                     Sprite::MakeSprite(bloodsprite, DoRotation((jointPos(abdomen) + jointPos(abdomen)) / 2, 0, yaw, 0) * scale + coords, bloodvel, 1, 1, 1, .05, 1);
4688                 }
4689             }
4690         }
4691         bloodloss += deathbleeding * multiplier * 80;
4692         deathbleeding -= multiplier * 1.6;
4693         if (deathbleeding < 0) {
4694             deathbleeding = 0;
4695         }
4696         if (bloodloss > damagetolerance && Animation::animations[animTarget].attack == neutral) {
4697             if (weaponactive != -1) {
4698                 weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
4699                 weapons[weaponids[0]].velocity.x += .01;
4700                 num_weapons--;
4701                 if (num_weapons) {
4702                     weaponids[0] = weaponids[num_weapons];
4703                     if (weaponstuck == num_weapons) {
4704                         weaponstuck = 0;
4705                     }
4706                 }
4707                 weaponactive = -1;
4708                 for (unsigned i = 0; i < Person::players.size(); i++) {
4709                     Person::players[i]->wentforweapon = 0;
4710                 }
4711
4712                 if (id == 0) {
4713                     Game::flash(.5, 0);
4714                 }
4715             }
4716
4717             if (!dead && creature == wolftype) {
4718                 award_bonus(0, Wolfbonus);
4719             }
4720             dead = 2;
4721             if (animTarget == knifefollowedanim && !skeleton.free) {
4722                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
4723                     skeleton.joints[i].velocity = 0;
4724                     skeleton.joints[i].velocity.y = -2;
4725                 }
4726             }
4727             if (id != 0 && unconscioustime > .1) {
4728                 numafterkill++;
4729             }
4730
4731             RagDoll(0);
4732         }
4733     }
4734
4735     if (texupdatedelay < 0 && bleeding > 0 && bloodtoggle == 2 && distsq(&viewer, &coords) < 9) {
4736         texupdatedelay = .12;
4737
4738         bloodsize = 5 - realtexdetail;
4739
4740         startx = 0;
4741         starty = 0;
4742         startx = bleedy; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4743         starty = bleedx; //abs(Random()%(skeleton.skinsize-bloodsize-1));
4744         endx = startx + bloodsize;
4745         endy = starty + bloodsize;
4746
4747         if (startx < 0) {
4748             startx = 0;
4749             bleeding = 0;
4750         }
4751         if (starty < 0) {
4752             starty = 0;
4753             bleeding = 0;
4754         }
4755         if (endx > skeleton.skinsize - 1) {
4756             endx = skeleton.skinsize - 1;
4757             bleeding = 0;
4758         }
4759         if (endy > skeleton.skinsize - 1) {
4760             endy = skeleton.skinsize - 1;
4761             bleeding = 0;
4762         }
4763         if (endx < startx) {
4764             endx = startx;
4765         }
4766         if (endy < starty) {
4767             endy = starty;
4768         }
4769
4770         for (int i = startx; i < endx; i++) {
4771             for (int j = starty; j < endy; j++) {
4772                 if (Random() % 2 == 0) {
4773                     color = Random() % 85 + 170;
4774                     if (skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] > color / 2) {
4775                         skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 0] = color / 2;
4776                     }
4777                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 1] = 0;
4778                     skeleton.skinText[i * skeleton.skinsize * 3 + j * 3 + 2] = 0;
4779                 }
4780             }
4781         }
4782         if (detail > 1) {
4783             skeleton.drawmodel.textureptr.bind();
4784             DoMipmaps();
4785         }
4786
4787         if (skeleton.free) {
4788             bleedx += 4 * direction / realtexdetail;
4789             if (detail == 2) {
4790                 bleedy += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4791             } else {
4792                 bleedy += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4793             }
4794         } else {
4795             bleedy -= 4 / realtexdetail;
4796             if (detail == 2) {
4797                 bleedx += (abs(Random() % 3) - 1) * 2 / realtexdetail;
4798             } else {
4799                 bleedx += (abs(Random() % 3) - 1) * 4 / realtexdetail;
4800             }
4801         }
4802     }
4803
4804     if (abs(righthandmorphness - targetrighthandmorphness) < multiplier * 4) {
4805         righthandmorphness = targetrighthandmorphness;
4806         righthandmorphstart = righthandmorphend;
4807     } else if (righthandmorphness > targetrighthandmorphness) {
4808         righthandmorphness -= multiplier * 4;
4809     } else if (righthandmorphness < targetrighthandmorphness) {
4810         righthandmorphness += multiplier * 4;
4811     }
4812
4813     if (abs(lefthandmorphness - targetlefthandmorphness) < multiplier * 4) {
4814         lefthandmorphness = targetlefthandmorphness;
4815         lefthandmorphstart = lefthandmorphend;
4816     } else if (lefthandmorphness > targetlefthandmorphness) {
4817         lefthandmorphness -= multiplier * 4;
4818     } else if (lefthandmorphness < targetlefthandmorphness) {
4819         lefthandmorphness += multiplier * 4;
4820     }
4821
4822     if (creature == rabbittype || targettailmorphness == 5 || targettailmorphness == 0) {
4823         if (abs(tailmorphness - targettailmorphness) < multiplier * 10) {
4824             tailmorphness = targettailmorphness;
4825             tailmorphstart = tailmorphend;
4826         } else if (tailmorphness > targettailmorphness) {
4827             tailmorphness -= multiplier * 10;
4828         } else if (tailmorphness < targettailmorphness) {
4829             tailmorphness += multiplier * 10;
4830         }
4831     }
4832
4833     if (creature == wolftype) {
4834         if (abs(tailmorphness - targettailmorphness) < multiplier * 4) {
4835             tailmorphness = targettailmorphness;
4836             tailmorphstart = tailmorphend;
4837         } else if (tailmorphness > targettailmorphness) {
4838             tailmorphness -= multiplier * 2;
4839         } else if (tailmorphness < targettailmorphness) {
4840             tailmorphness += multiplier * 2;
4841         }
4842     }
4843
4844     if (headmorphend == 3 || headmorphstart == 3) {
4845         if (abs(headmorphness - targetheadmorphness) < multiplier * 7) {
4846             headmorphness = targetheadmorphness;
4847             headmorphstart = headmorphend;
4848         } else if (headmorphness > targetheadmorphness) {
4849             headmorphness -= multiplier * 7;
4850         } else if (headmorphness < targetheadmorphness) {
4851             headmorphness += multiplier * 7;
4852         }
4853     } else if (headmorphend == 5 || headmorphstart == 5) {
4854         if (abs(headmorphness - targetheadmorphness) < multiplier * 10) {
4855             headmorphness = targetheadmorphness;
4856             headmorphstart = headmorphend;
4857         } else if (headmorphness > targetheadmorphness) {
4858             headmorphness -= multiplier * 10;
4859         } else if (headmorphness < targetheadmorphness) {
4860             headmorphness += multiplier * 10;
4861         }
4862     } else {
4863         if (abs(headmorphness - targetheadmorphness) < multiplier * 4) {
4864             headmorphness = targetheadmorphness;
4865             headmorphstart = headmorphend;
4866         } else if (headmorphness > targetheadmorphness) {
4867             headmorphness -= multiplier * 4;
4868         } else if (headmorphness < targetheadmorphness) {
4869             headmorphness += multiplier * 4;
4870         }
4871     }
4872
4873     if (abs(chestmorphness - targetchestmorphness) < multiplier) {
4874         chestmorphness = targetchestmorphness;
4875         chestmorphstart = chestmorphend;
4876     } else if (chestmorphness > targetchestmorphness) {
4877         chestmorphness -= multiplier;
4878     } else if (chestmorphness < targetchestmorphness) {
4879         chestmorphness += multiplier;
4880     }
4881
4882     if (dead != 2 && howactive <= typesleeping) {
4883         if (chestmorphstart == 0 && chestmorphend == 0) {
4884             chestmorphness = 0;
4885             targetchestmorphness = 1;
4886             chestmorphend = 3;
4887         }
4888         if (chestmorphstart != 0 && chestmorphend != 0) {
4889             chestmorphness = 0;
4890             targetchestmorphness = 1;
4891             chestmorphend = 0;
4892             if (environment == snowyenvironment) {
4893                 XYZ footpoint;
4894                 XYZ footvel;
4895                 if (skeleton.free) {
4896                     footvel = skeleton.specialforward[0] * -1;
4897                     footpoint = ((jointPos(head) + jointPos(neck)) / 2) * scale + coords;
4898                 } else {
4899                     footvel = DoRotation(skeleton.specialforward[0], 0, yaw, 0) * -1;
4900                     footpoint = DoRotation((jointPos(head) + jointPos(neck)) / 2, 0, yaw, 0) * scale + coords;
4901                 }
4902                 if (animTarget == sleepanim) {
4903                     footvel = DoRotation(footvel, 0, 90, 0);
4904                 }
4905                 Sprite::MakeSprite(breathsprite, footpoint + footvel * .2, footvel * .4, 1, 1, 1, .4, .3);
4906             }
4907         }
4908
4909         if (!dead && howactive < typesleeping) {
4910             blinkdelay -= multiplier * 2;
4911             if (headmorphstart == 0 && headmorphend == 0 && blinkdelay <= 0) {
4912                 headmorphness = 0;
4913                 targetheadmorphness = 1;
4914                 headmorphend = 3;
4915                 blinkdelay = (float)(abs(Random() % 40)) / 5;
4916             }
4917             if (headmorphstart == 3 && headmorphend == 3) {
4918                 headmorphness = 0;
4919                 targetheadmorphness = 1;
4920                 headmorphend = 0;
4921             }
4922         }
4923         if (!dead) {
4924             twitchdelay -= multiplier * 1.5;
4925             if (animTarget != hurtidleanim) {
4926                 if (headmorphstart == 0 && headmorphend == 0 && twitchdelay <= 0) {
4927                     headmorphness = 0;
4928                     targetheadmorphness = 1;
4929                     headmorphend = 5;
4930                     twitchdelay = (float)(abs(Random() % 40)) / 5;
4931                 }
4932                 if (headmorphstart == 5 && headmorphend == 5) {
4933                     headmorphness = 0;
4934                     targetheadmorphness = 1;
4935                     headmorphend = 0;
4936                 }
4937             }
4938             if ((isIdle() || isCrouch()) && animTarget != hurtidleanim) {
4939                 twitchdelay3 -= multiplier * 1;
4940                 if (Random() % 2 == 0) {
4941                     if (righthandmorphstart == 0 && righthandmorphend == 0 && twitchdelay3 <= 0) {
4942                         righthandmorphness = 0;
4943                         targetrighthandmorphness = 1;
4944                         righthandmorphend = 1;
4945                         if (Random() % 2 == 0) {
4946                             twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4947                         }
4948                     }
4949                     if (righthandmorphstart == 1 && righthandmorphend == 1) {
4950                         righthandmorphness = 0;
4951                         targetrighthandmorphness = 1;
4952                         righthandmorphend = 0;
4953                     }
4954                 }
4955                 if (Random() % 2 == 0) {
4956                     if (lefthandmorphstart == 0 && lefthandmorphend == 0 && twitchdelay3 <= 0) {
4957                         lefthandmorphness = 0;
4958                         targetlefthandmorphness = 1;
4959                         lefthandmorphend = 1;
4960                         twitchdelay3 = (float)(abs(Random() % 40)) / 5;
4961                     }
4962                     if (lefthandmorphstart == 1 && lefthandmorphend == 1) {
4963                         lefthandmorphness = 0;
4964                         targetlefthandmorphness = 1;
4965                         lefthandmorphend = 0;
4966                     }
4967                 }
4968             }
4969         }
4970         if (!dead) {
4971             if (creature == rabbittype) {
4972                 if (howactive < typesleeping) {
4973                     twitchdelay2 -= multiplier * 1.5;
4974                 } else {
4975                     twitchdelay2 -= multiplier * 0.5;
4976                 }
4977                 if (howactive <= typesleeping) {
4978                     if (tailmorphstart == 0 && tailmorphend == 0 && twitchdelay2 <= 0) {
4979                         tailmorphness = 0;
4980                         targettailmorphness = 1;
4981                         tailmorphend = 1;
4982                         twitchdelay2 = (float)(abs(Random() % 40)) / 5;
4983                     }
4984                     if (tailmorphstart == 1 && tailmorphend == 1) {
4985                         tailmorphness = 0;
4986                         targettailmorphness = 1;
4987                         tailmorphend = 2;
4988                     }
4989                     if (tailmorphstart == 2 && tailmorphend == 2) {
4990                         tailmorphness = 0;
4991                         targettailmorphness = 1;
4992                         tailmorphend = 0;
4993                     }
4994                 }
4995             }
4996         }
4997     }
4998     if (creature == wolftype) {
4999         twitchdelay2 -= multiplier * 1.5;
5000         if (tailmorphend != 0) {
5001             if ((isRun() || animTarget == jumpupanim || animTarget == jumpdownanim || animTarget == backflipanim) && !skeleton.free) {
5002                 tailmorphness = 0;
5003                 targettailmorphness = 1;
5004                 tailmorphend = 0;
5005                 twitchdelay2 = .1;
5006             }
5007         }
5008         if (tailmorphend != 5) {
5009             if (animTarget == flipanim || animTarget == frontflipanim || animTarget == rollanim || skeleton.free) {
5010                 tailmorphness = 0;
5011                 targettailmorphness = 1;
5012                 tailmorphend = 5;
5013                 twitchdelay2 = .1;
5014             }
5015         }
5016         if (twitchdelay2 <= 0) {
5017             if (((tailmorphstart == 0 && tailmorphend == 0) || (tailmorphstart == 5 && tailmorphend == 5))) {
5018                 tailmorphness = 0;
5019                 targettailmorphness = 1;
5020                 tailmorphend = 1;
5021             }
5022             if (tailmorphstart == 1 && tailmorphend == 1) {
5023                 tailmorphness = 0;
5024                 targettailmorphness = 1;
5025                 tailmorphend = 2;
5026             }
5027             if (tailmorphstart == 2 && tailmorphend == 2) {
5028                 tailmorphness = 0;
5029                 targettailmorphness = 1;
5030                 tailmorphend = 3;
5031             }
5032             if (tailmorphstart == 3 && tailmorphend == 3) {
5033                 tailmorphness = 0;
5034                 targettailmorphness = 1;
5035                 tailmorphend = 4;
5036             }
5037             if (tailmorphstart == 4 && tailmorphend == 4) {
5038                 tailmorphness = 0;
5039                 targettailmorphness = 1;
5040                 tailmorphend = 1;
5041             }
5042         }
5043     }
5044
5045     if (dead != 1) {
5046         unconscioustime = 0;
5047     }
5048
5049     if (dead == 1 || howactive == typesleeping) {
5050         unconscioustime += multiplier;
5051         //If unconscious, close eyes and mouth
5052         if (righthandmorphend != 0) {
5053             righthandmorphness = 0;
5054         }
5055         righthandmorphend = 0;
5056         targetrighthandmorphness = 1;
5057
5058         if (lefthandmorphend != 0) {
5059             lefthandmorphness = 0;
5060         }
5061         lefthandmorphend = 0;
5062         targetlefthandmorphness = 1;
5063
5064         if (headmorphend != 3 && headmorphend != 5) {
5065             headmorphness = 0;
5066         }
5067         headmorphend = 3;
5068         targetheadmorphness = 1;
5069     }
5070
5071     if (howactive > typesleeping) {
5072         XYZ headpoint;
5073         headpoint = coords;
5074         if (bloodtoggle && !bled) {
5075             terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
5076             for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5077                 unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5078                 XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5079                 float size = .8;
5080                 float opacity = .6;
5081                 float yaw = 0;
5082                 Object::objects[j]->model.MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
5083             }
5084         }
5085         bled = 1;
5086     }
5087
5088     if (dead == 2 || howactive > typesleeping) {
5089         //If dead, open mouth and hands
5090         if (righthandmorphend != 0) {
5091             righthandmorphness = 0;
5092         }
5093         righthandmorphend = 0;
5094         targetrighthandmorphness = 1;
5095
5096         if (lefthandmorphend != 0) {
5097             lefthandmorphness = 0;
5098         }
5099         lefthandmorphend = 0;
5100         targetlefthandmorphness = 1;
5101
5102         if (headmorphend != 2) {
5103             headmorphness = 0;
5104         }
5105         headmorphend = 2;
5106         targetheadmorphness = 1;
5107     }
5108
5109     if (stunned > 0 && !dead && headmorphend != 2) {
5110         if (headmorphend != 4) {
5111             headmorphness = 0;
5112         }
5113         headmorphend = 4;
5114         targetheadmorphness = 1;
5115     }
5116
5117     if (damage > damagetolerance && !dead) {
5118
5119         dead = 1;
5120         unconscioustime = 0;
5121
5122         if (creature == wolftype) {
5123             award_bonus(0, Wolfbonus);
5124         }
5125
5126         RagDoll(0);
5127
5128         if (weaponactive != -1) {
5129             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
5130             weapons[weaponids[0]].velocity.x += .01;
5131             num_weapons--;
5132             if (num_weapons) {
5133                 weaponids[0] = weaponids[num_weapons];
5134                 if (weaponstuck == num_weapons) {
5135                     weaponstuck = 0;
5136                 }
5137             }
5138             weaponactive = -1;
5139             for (unsigned i = 0; i < Person::players.size(); i++) {
5140                 Person::players[i]->wentforweapon = 0;
5141             }
5142         }
5143
5144         if ((id == 0 || distsq(&coords, &viewer) < 50) && autoslomo) {
5145             slomo = 1;
5146             slomodelay = .2;
5147         }
5148
5149         damage += 20;
5150     }
5151
5152     if (!dead) {
5153         damage -= multiplier * 13;
5154         permanentdamage -= multiplier * 4;
5155         if (isIdle() || isCrouch()) {
5156             permanentdamage -= multiplier * 4;
5157         }
5158     }
5159     if (damage < 0) {
5160         damage = 0;
5161     }
5162     if (permanentdamage < 0) {
5163         permanentdamage = 0;
5164     }
5165     if (superpermanentdamage < 0) {
5166         superpermanentdamage = 0;
5167     }
5168     if (permanentdamage < superpermanentdamage) {
5169         permanentdamage = superpermanentdamage;
5170     }
5171     if (damage < permanentdamage) {
5172         damage = permanentdamage;
5173     }
5174     if (dead == 1 && damage < damagetolerance) {
5175         dead = 0;
5176         skeleton.free = 1;
5177         damage -= 20;
5178         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5179             skeleton.joints[i].velocity = 0;
5180         }
5181     }
5182     if (permanentdamage > damagetolerance && dead != 2) {
5183         DoBlood(1, 255);
5184
5185         if (weaponactive != -1) {
5186             weapons[weaponids[0]].drop(velocity * scale * -.3, velocity * scale);
5187             weapons[weaponids[0]].velocity.x += .01;
5188             num_weapons--;
5189             if (num_weapons) {
5190                 weaponids[0] = weaponids[num_weapons];
5191                 if (weaponstuck == num_weapons) {
5192                     weaponstuck = 0;
5193                 }
5194             }
5195             weaponactive = -1;
5196             for (unsigned i = 0; i < Person::players.size(); i++) {
5197                 Person::players[i]->wentforweapon = 0;
5198             }
5199         }
5200
5201         bled = 0;
5202
5203         if (!dead && creature == wolftype) {
5204             award_bonus(0, Wolfbonus);
5205         }
5206
5207         if (unconscioustime < .1 && (bonus != spinecrusher || bonustime > 1) && (bonus != FinishedBonus || bonustime > 1) && bloodloss < damagetolerance) {
5208             award_bonus(id, touchofdeath);
5209         }
5210         if (id != 0 && unconscioustime > .1) {
5211             numafterkill++;
5212         }
5213
5214         dead = 2;
5215
5216         skeleton.free = 1;
5217
5218         emit_sound_at(breaksound, coords);
5219     }
5220
5221     if (skeleton.free == 1) {
5222         if (id == 0) {
5223             pause_sound(whooshsound);
5224         }
5225
5226         if (!dead) {
5227             //If knocked over, open hands and close mouth
5228             if (righthandmorphend != 0) {
5229                 righthandmorphness = 0;
5230             }
5231             righthandmorphend = 0;
5232             targetrighthandmorphness = 1;
5233
5234             if (lefthandmorphend != 0) {
5235                 lefthandmorphness = 0;
5236             }
5237             lefthandmorphend = 0;
5238             targetlefthandmorphness = 1;
5239
5240             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5) {
5241                 if (headmorphend != 0) {
5242                     headmorphness = 0;
5243                 }
5244                 headmorphend = 0;
5245                 targetheadmorphness = 1;
5246             }
5247         }
5248
5249         skeleton.DoGravity(&scale);
5250         float damageamount;
5251         damageamount = skeleton.DoConstraints(&coords, &scale) * 5;
5252         if (damage > damagetolerance - damageamount && !dead && (bonus != spinecrusher || bonustime > 1) && (bonus != style || bonustime > 1) && (bonus != cannon || bonustime > 1)) {
5253             award_bonus(id, deepimpact);
5254         }
5255         DoDamage(damageamount / ((protectionhigh + protectionhead + protectionlow) / 3));
5256
5257         XYZ average;
5258         average = 0;
5259         if (!skeleton.joints.empty()) {
5260             for (unsigned j = 0; j < skeleton.joints.size(); j++) {
5261                 average += skeleton.joints[j].position;
5262             }
5263             average /= skeleton.joints.size();
5264             coords += average * scale;
5265             for (unsigned j = 0; j < skeleton.joints.size(); j++) {
5266                 skeleton.joints[j].position -= average;
5267             }
5268             average /= multiplier;
5269         }
5270
5271         velocity = 0;
5272         for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5273             velocity += skeleton.joints[i].velocity * scale;
5274         }
5275         velocity /= skeleton.joints.size();
5276
5277         if (!isnormal(velocity.x) && velocity.x) {
5278             velocity = 0;
5279         }
5280
5281         if (findLength(&average) < 10 && dead && skeleton.free) {
5282             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
5283             if (skeleton.longdead > 2000) {
5284                 if (skeleton.longdead > 6000) {
5285                     if (id == 0) {
5286                         pause_sound(whooshsound);
5287                     }
5288                     skeleton.free = 3;
5289                     DrawSkeleton();
5290                     skeleton.free = 2;
5291                 }
5292                 if (dead == 2 && bloodloss < damagetolerance) {
5293                     XYZ headpoint;
5294                     headpoint = (jointPos(head) + jointPos(neck)) / 2 * scale + coords;
5295                     DoBlood(1, 255);
5296                     if (bloodtoggle && !bled) {
5297                         terrain.MakeDecal(blooddecal, headpoint, .2 * 1.2, .5, 0);
5298                         for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5299                             unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5300                             XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5301                             float size = .2 * 1.2;
5302                             float opacity = .6;
5303                             float yaw = 0;
5304                             Object::objects[j]->model.MakeDecal(blooddecal, &point, &size, &opacity, &yaw);
5305                         }
5306                     }
5307                     bled = 1;
5308                 }
5309                 if (dead == 2 && bloodloss >= damagetolerance) {
5310                     XYZ headpoint;
5311                     headpoint = (jointPos(abdomen) + jointPos(neck)) / 2 * scale + coords;
5312                     if (bleeding <= 0) {
5313                         DoBlood(1, 255);
5314                     }
5315                     if (bloodtoggle && !bled) {
5316                         terrain.MakeDecal(blooddecalslow, headpoint, .8, .5, 0);
5317                         for (unsigned int l = 0; l < terrain.patchobjects[whichpatchx][whichpatchz].size(); l++) {
5318                             unsigned int j = terrain.patchobjects[whichpatchx][whichpatchz][l];
5319                             XYZ point = DoRotation(headpoint - Object::objects[j]->position, 0, -Object::objects[j]->yaw, 0);
5320                             float size = .8;
5321                             float opacity = .6;
5322                             float yaw = 0;
5323                             Object::objects[j]->model.MakeDecal(blooddecalslow, &point, &size, &opacity, &yaw);
5324                         }
5325                     }
5326                     bled = 1;
5327                 }
5328             }
5329         }
5330
5331         if (!dead && crouchkeydown && skeleton.freetime > .5 && id == 0 && skeleton.free) {
5332             bool canrecover = 1;
5333             XYZ startpoint, endpoint, colpoint, colviewer, coltarget;
5334             startpoint = coords;
5335             endpoint = coords;
5336             endpoint.y -= .7;
5337             if (terrain.lineTerrain(startpoint, endpoint, &colpoint) != -1) {
5338                 canrecover = 0;
5339             }
5340             if (velocity.y < -30) {
5341                 canrecover = 0;
5342             }
5343             for (unsigned int i = 0; i < Object::objects.size(); i++) {
5344                 if (Object::objects[i]->type != treeleavestype && Object::objects[i]->type != bushtype && Object::objects[i]->type != firetype) {
5345                     colviewer = startpoint;
5346                     coltarget = endpoint;
5347                     if (Object::objects[i]->model.LineCheck(&colviewer, &coltarget, &colpoint, &Object::objects[i]->position, &Object::objects[i]->yaw) != -1) {
5348                         canrecover = 0;
5349                     }
5350                 }
5351             }
5352             if (canrecover) {
5353                 skeleton.free = 0;
5354                 XYZ middle;
5355                 middle = 0;
5356
5357                 terrainnormal = jointPos(groin) - jointPos(abdomen);
5358                 if (joint(groin).locked && joint(abdomen).locked) {
5359                     terrainnormal = jointPos(groin) - jointPos(abdomen);
5360                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
5361                 }
5362                 if (joint(abdomen).locked && joint(neck).locked) {
5363                     terrainnormal = jointPos(abdomen) - jointPos(neck);
5364                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
5365                 }
5366                 if (joint(groin).locked && joint(neck).locked) {
5367                     terrainnormal = jointPos(groin) - jointPos(neck);
5368                     middle = (jointPos(groin) + jointPos(neck)) / 2;
5369                 }
5370                 Normalise(&terrainnormal);
5371
5372                 targetyaw = -asin(0 - terrainnormal.x);
5373                 targetyaw *= 360 / 6.28;
5374                 if (terrainnormal.z < 0) {
5375                     targetyaw = 180 - targetyaw;
5376                 }
5377                 yaw = targetyaw;
5378
5379                 frameTarget = 0;
5380                 animTarget = flipanim;
5381                 crouchtogglekeydown = 1;
5382                 target = 0;
5383                 tilt2 = 0;
5384                 targettilt2 = 0;
5385
5386                 animCurrent = tempanim;
5387                 frameCurrent = 0;
5388                 target = 0;
5389
5390                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5391                     tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
5392                     tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
5393                 }
5394             }
5395         }
5396
5397         if (findLength(&average) < 10 && !dead && skeleton.free) {
5398             skeleton.longdead += (2000 - findLength(&average)) * multiplier + multiplier;
5399             if (skeleton.longdead > (damage + 500) * 1.5) {
5400                 if (id == 0) {
5401                     pause_sound(whooshsound);
5402                 }
5403                 skeleton.free = 0;
5404                 velocity = 0;
5405                 XYZ middle;
5406                 middle = 0;
5407
5408                 terrainnormal = jointPos(groin) - jointPos(abdomen);
5409                 if (joint(groin).locked && joint(abdomen).locked) {
5410                     terrainnormal = jointPos(groin) - jointPos(abdomen);
5411                     middle = (jointPos(groin) + jointPos(abdomen)) / 2;
5412                 }
5413                 if (joint(abdomen).locked && joint(neck).locked) {
5414                     terrainnormal = jointPos(abdomen) - jointPos(neck);
5415                     middle = (jointPos(neck) + jointPos(abdomen)) / 2;
5416                 }
5417                 if (joint(groin).locked && joint(neck).locked) {
5418                     terrainnormal = jointPos(groin) - jointPos(neck);
5419                     middle = (jointPos(groin) + jointPos(neck)) / 2;
5420                 }
5421                 Normalise(&terrainnormal);
5422
5423                 targetyaw = -asin(0 - terrainnormal.x);
5424                 targetyaw *= 360 / 6.28;
5425                 if (terrainnormal.z < 0) {
5426                     targetyaw = 180 - targetyaw;
5427                 }
5428                 yaw = targetyaw;
5429
5430                 targettilt2 = asin(terrainnormal.y) * 180 / 3.14 * -1;
5431
5432                 if (skeleton.forward.y < 0) {
5433                     animTarget = getupfrombackanim;
5434                     frameTarget = 0;
5435                     targettilt2 = 0;
5436                 }
5437                 if (skeleton.forward.y > -.3) {
5438                     animTarget = getupfromfrontanim;
5439                     yaw += 180;
5440                     targetyaw += 180;
5441                     targettilt2 *= -1;
5442                     frameTarget = 0;
5443                     targettilt2 = 0;
5444                 }
5445
5446                 if ((Random() % 8 == 0 && id != 0 && creature == rabbittype) || (Random() % 2 == 0 && id != 0 && creature == wolftype) || (id == 0 && crouchkeydown && (forwardkeydown || backkeydown || leftkeydown || rightkeydown))) {
5447                     animTarget = rollanim;
5448                     targetyaw = lookyaw;
5449                     if (id == 0) {
5450                         if (rightkeydown) {
5451                             targetyaw -= 90;
5452                             if (forwardkeydown) {
5453                                 targetyaw += 45;
5454                             }
5455                             if (backkeydown) {
5456                                 targetyaw -= 45;
5457                             }
5458                         }
5459                         if (leftkeydown) {
5460                             targetyaw += 90;
5461                             if (forwardkeydown) {
5462                                 targetyaw -= 45;
5463                             }
5464                             if (backkeydown) {
5465                                 targetyaw += 45;
5466                             }
5467                         }
5468                         if (backkeydown) {
5469                             if (!leftkeydown && !rightkeydown) {
5470                                 targetyaw += 180;
5471                             }
5472                         }
5473                         targetyaw += 180;
5474                     }
5475                 }
5476
5477                 if (abs(targettilt2) > 50) {
5478                     targettilt2 = 0;
5479                 }
5480                 animCurrent = tempanim;
5481                 frameCurrent = 0;
5482                 target = 0;
5483                 tilt2 = targettilt2;
5484
5485                 if (middle.y > 0 && animTarget != rollanim) {
5486                     targetoffset.y = middle.y + 1;
5487                 }
5488
5489                 for (unsigned i = 0; i < skeleton.joints.size(); i++) {
5490                     tempanimation.frames[0].joints[i].position = skeleton.joints[i].position;
5491                     tempanimation.frames[0].joints[i].position = DoRotation(tempanimation.frames[0].joints[i].position, 0, -yaw, 0);
5492                 }
5493             }
5494         }
5495
5496         bool hasstaff;
5497         hasstaff = 0;
5498         if (num_weapons > 0) {
5499             if (weapons[0].getType() == staff) {
5500                 hasstaff = 1;
5501             }
5502         }
5503         if (!skeleton.freefall && freefall && ((jumpkeydown && jumpkeydowntime < .2) || (hasstaff && rabbitkickragdoll)) && !dead) {
5504             if (velocity.y > -30) {
5505                 XYZ tempvelocity;
5506                 tempvelocity = velocity;
5507                 Normalise(&tempvelocity);
5508                 targetyaw = -asin(0 - tempvelocity.x);
5509                 targetyaw *= 360 / 6.28;
5510                 if (velocity.z < 0) {
5511                     targetyaw = 180 - targetyaw;
5512                 }
5513                 //targetyaw+=180;
5514
5515                 skeleton.free = 0;
5516                 if (dotproduct(&skeleton.forward, &tempvelocity) < 0) {
5517                     animTarget = rollanim;
5518                     frameTarget = 2;
5519                 } else {
5520                     animTarget = backhandspringanim;
5521                     targetyaw += 180;
5522                     frameTarget = 6;
5523                 }
5524                 target = 0;
5525
5526                 emit_sound_at(movewhooshsound, coords, 128.);
5527
5528                 animCurrent = animTarget;
5529                 frameCurrent = frameTarget - 1;
5530                 target = 0;
5531
5532                 velocity = 0;
5533
5534                 yaw = targetyaw;
5535                 tilt = 0;
5536                 targettilt = 0;
5537                 tilt2 = 0;
5538                 targettilt2 = 0;
5539             }
5540         }
5541         if (skeleton.freefall == 0) {
5542             freefall = 0;
5543         }
5544     }
5545
5546     if (aitype != passivetype || skeleton.free == 1) {
5547         if (findLengthfast(&velocity) > .1) {
5548             for (unsigned int i = 0; i < Object::objects.size(); i++) {
5549                 if (Object::objects[i]->type == firetype) {
5550                     if (distsqflat(&coords, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 12 && distsq(&coords, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 49) {
5551                         if (onfire) {
5552                             if (!Object::objects[i]->onfire) {
5553                                 emit_sound_at(firestartsound, Object::objects[i]->position);
5554                             }
5555                             Object::objects[i]->onfire = 1;
5556                         }
5557                         if (!onfire) {
5558                             if (Object::objects[i]->onfire) {
5559                                 CatchFire();
5560                             }
5561                         }
5562                     }
5563                 }
5564                 if (Object::objects[i]->type == bushtype) {
5565                     if (distsqflat(&coords, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 12 && distsq(&coords, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 49) {
5566                         if (onfire) {
5567                             if (!Object::objects[i]->onfire) {
5568                                 emit_sound_at(firestartsound, Object::objects[i]->position);
5569                             }
5570                             Object::objects[i]->onfire = 1;
5571                         }
5572
5573                         if (!onfire) {
5574                             if (Object::objects[i]->onfire) {
5575                                 CatchFire();
5576                             }
5577                         }
5578                         if (Object::objects[i]->messedwith <= 0) {
5579                             XYZ tempvel;
5580                             XYZ pos;
5581
5582                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
5583
5584                             if (id == 0) {
5585                                 addEnvSound(coords, 4 * findLength(&velocity));
5586                             }
5587
5588                             int howmany = 0;
5589                             if (environment == grassyenvironment) {
5590                                 howmany = findLength(&velocity) * 4;
5591                             }
5592                             if (environment == snowyenvironment) {
5593                                 howmany = findLength(&velocity) * 2;
5594                             }
5595                             if (detail == 2) {
5596                                 if (environment != desertenvironment) {
5597                                     for (int j = 0; j < howmany; j++) {
5598                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5599                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5600                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5601                                         pos = coords;
5602                                         pos.y += 1;
5603                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5604                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5605                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5606                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
5607                                         Sprite::setLastSpriteSpecial(1);
5608                                     }
5609                                 }
5610                             }
5611                             howmany = findLength(&velocity) * 4;
5612                             if (detail == 2) {
5613                                 if (environment == snowyenvironment) {
5614                                     for (int j = 0; j < howmany; j++) {
5615                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5616                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5617                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5618                                         pos = coords;
5619                                         pos.y += 1;
5620                                         pos.x += float(abs(Random() % 100) - 50) / 200;
5621                                         pos.y += float(abs(Random() % 100) - 50) / 200;
5622                                         pos.z += float(abs(Random() % 100) - 50) / 200;
5623                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5624                                         Sprite::setLastSpriteSpecial(2);
5625                                     }
5626                                 }
5627                             }
5628                         }
5629                         Object::objects[i]->rotx += velocity.x * multiplier * 6;
5630                         Object::objects[i]->roty += velocity.z * multiplier * 6;
5631                         Object::objects[i]->messedwith = .5;
5632                     }
5633                 }
5634                 XYZ tempcoord;
5635                 if (Object::objects[i]->type == treeleavestype && environment != desertenvironment) {
5636                     if (Object::objects[i]->pitch == 0) {
5637                         tempcoord = coords;
5638                     } else {
5639                         tempcoord = coords - Object::objects[i]->position;
5640                         tempcoord = DoRotation(tempcoord, 0, -Object::objects[i]->yaw, 0);
5641                         tempcoord = DoRotation(tempcoord, -Object::objects[i]->pitch, 0, 0);
5642                         tempcoord += Object::objects[i]->position;
5643                     }
5644                     if (distsqflat(&tempcoord, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 8 && distsq(&tempcoord, &Object::objects[i]->position) < Object::objects[i]->scale * Object::objects[i]->scale * 300 && tempcoord.y > Object::objects[i]->position.y + 3 * Object::objects[i]->scale) {
5645                         if (Object::objects[i]->messedwith <= 0) {
5646                             XYZ tempvel;
5647                             XYZ pos;
5648
5649                             emit_sound_at(bushrustle, coords, 40 * findLength(&velocity));
5650
5651                             if (id == 0) {
5652                                 addEnvSound(coords, 4 * findLength(&velocity));
5653                             }
5654
5655                             int howmany = 0;
5656                             if (environment == grassyenvironment) {
5657                                 howmany = findLength(&velocity) * 4;
5658                             }
5659                             if (environment == snowyenvironment) {
5660                                 howmany = findLength(&velocity) * 2;
5661                             }
5662                             if (detail == 2) {
5663                                 if (environment != desertenvironment) {
5664                                     for (int j = 0; j < howmany; j++) {
5665                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5666                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5667                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5668                                         pos = coords;
5669                                         pos += velocity * .1;
5670                                         pos.y += 1;
5671                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5672                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5673                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5674                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .5 + velocity * float(abs(Random() % 100)) / 100, 165 / 255 + float(abs(Random() % 100) - 50) / 400, 0, 0, .2 + float(abs(Random() % 100) - 50) / 1300, 1);
5675                                         Sprite::setLastSpriteSpecial(1);
5676                                     }
5677                                 }
5678                             }
5679                             howmany = findLength(&velocity) * 4;
5680                             if (detail == 2) {
5681                                 if (environment == snowyenvironment) {
5682                                     for (int j = 0; j < howmany; j++) {
5683                                         tempvel.x = float(abs(Random() % 100) - 50) / 20;
5684                                         tempvel.y = float(abs(Random() % 100) - 50) / 20;
5685                                         tempvel.z = float(abs(Random() % 100) - 50) / 20;
5686                                         pos = coords;
5687                                         pos += velocity * .1;
5688                                         pos.y += 1;
5689                                         pos.x += float(abs(Random() % 100) - 50) / 150;
5690                                         pos.y += float(abs(Random() % 100) - 50) / 150;
5691                                         pos.z += float(abs(Random() % 100) - 50) / 150;
5692                                         Sprite::MakeSprite(splintersprite, pos, tempvel * .3 + velocity * float(abs(Random() % 100)) / 100 / 2, 1, 1, 1, .1, 1);
5693                                         Sprite::setLastSpriteSpecial(2);
5694                                     }
5695                                 }
5696                             }
5697                         }
5698                         Object::objects[i]->messedwith = .5;
5699                     }
5700                 }
5701             }
5702         }
5703     }
5704
5705     if (!skeleton.free) {
5706         bool play;
5707         play = 0;
5708         if ((stunned > 0 || surprised > 0) && Person::players.size() > 2 && aitype != passivetype) {
5709             play = 1;
5710         }
5711         if (hasvictim) {
5712             if (aitype != passivetype && victim->skeleton.free && !victim->dead) {
5713                 play = 1;
5714             }
5715         }
5716         if (Tutorial::active && id != 0) {
5717             play = 0;
5718         }
5719         if (play && aitype != playercontrolled) {
5720             int whichsound = -1;
5721             if (speechdelay <= 0) {
5722                 unsigned int i = abs(Random() % 4);
5723                 if (i < 2) {
5724                     whichsound = PersonType::types[creature].soundsTalk[i];
5725                 }
5726             }
5727             speechdelay = .3;
5728
5729             if (whichsound != -1) {
5730                 emit_sound_at(whichsound, coords);
5731             }
5732         }
5733
5734         if (animTarget == staggerbackhighanim) {
5735             staggerdelay = 1;
5736         }
5737         if (animTarget == staggerbackhardanim) {
5738             staggerdelay = 1;
5739         }
5740         staggerdelay -= multiplier;
5741         if (animTarget != crouchstabanim && animTarget != swordgroundstabanim && animTarget != staffgroundsmashanim) {
5742             hasvictim = 1;
5743         }
5744         if (velocity.y < -30 && animTarget == jumpdownanim) {
5745             RagDoll(0);
5746         }
5747         if (animCurrent != getIdle() && wasIdle() && animTarget != getIdle() && isIdle()) {
5748             animTarget = getIdle();
5749             frameTarget = 0;
5750             target = 0;
5751         }
5752         weaponmissdelay -= multiplier;
5753         highreversaldelay -= multiplier;
5754         lowreversaldelay -= multiplier;
5755         lastcollide -= multiplier;
5756         skiddelay -= multiplier;
5757         if (!isnormal(velocity.x) && velocity.x) {
5758             velocity = 0;
5759         }
5760         if (!isnormal(targettilt) && targettilt) {
5761             targettilt = 0;
5762         }
5763         if (!isnormal(targettilt2) && targettilt2) {
5764             targettilt2 = 0;
5765         }
5766         if (!isnormal(targetyaw) && targetyaw) {
5767             targetyaw = 0;
5768         }
5769
5770         if (animTarget == bounceidleanim || animTarget == wolfidle || animTarget == walkanim || animTarget == drawrightanim || animTarget == crouchdrawrightanim || animTarget == drawleftanim || animTarget == fightidleanim || animTarget == fightsidestep || animTarget == hanganim || isCrouch() || animTarget == backhandspringanim) {
5771             //open hands and close mouth
5772             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5773                 righthandmorphness = 0;
5774                 righthandmorphend = 0;
5775                 targetrighthandmorphness = 1;
5776             }
5777
5778             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5779                 lefthandmorphness = 0;
5780                 lefthandmorphend = 0;
5781                 targetlefthandmorphness = 1;
5782             }
5783
5784             if (headmorphend != 3 && headmorphend != 5 && headmorphstart != 3 && headmorphstart != 5 && headmorphend != 0 && headmorphness == targetheadmorphness) {
5785                 headmorphness = 0;
5786                 headmorphend = 0;
5787                 targetheadmorphness = 1;
5788             }
5789         }
5790
5791         if (animTarget == rollanim || animTarget == dodgebackanim || animTarget == removeknifeanim || animTarget == knifefightidleanim || animTarget == swordfightidleanim || animTarget == blockhighleftstrikeanim || animTarget == crouchremoveknifeanim || animTarget == sneakanim || animTarget == sweepanim || animTarget == spinkickreversedanim || animTarget == jumpdownanim || isWallJump() || isFlip() || animTarget == climbanim || isRun() || animTarget == getupfrombackanim || animTarget == getupfromfrontanim) {
5792             //open hands and mouth
5793             if (righthandmorphend != 0 && righthandmorphness == targetrighthandmorphness) {
5794                 righthandmorphness = 0;
5795                 righthandmorphend = 0;
5796                 targetrighthandmorphness = 1;
5797             }
5798
5799             if (lefthandmorphend != 0 && lefthandmorphness == targetlefthandmorphness) {
5800                 lefthandmorphness = 0;
5801                 lefthandmorphend = 0;
5802                 targetlefthandmorphness = 1;
5803             }
5804
5805             if (headmorphend != 1 && headmorphness == targetheadmorphness) {
5806                 headmorphness = 0;
5807                 headmorphend = 1;
5808                 targetheadmorphness = 1;
5809             }
5810         }
5811
5812         if (animTarget == jumpupanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || animTarget == swordfightidlebothanim || animTarget == blockhighleftanim) {
5813             //close hands and mouth
5814             if (righthandmorphend != 1 && righthandmorphness == targetrighthandmorphness) {
5815                 righthandmorphness = 0;
5816                 righthandmorphend = 1;
5817                 targetrighthandmorphness = 1;
5818             }
5819
5820             if (lefthandmorphend != 1 && lefthandmorphness == targetlefthandmorphness) {
5821                 lefthandmorphness = 0;
5822                 lefthandmorphend = 1;
5823                 targetlefthandmorphness = 1;
5824             }
5825
5826             if (headmorphend != 0 && headmorphness == targetheadmorphness) {
5827                 headmorphness = 0;
5828                 headmorphend = 0;
5829                 targetheadmorphness = 1;
5830             }
5831         }
5832
5833         if (animTarget == spinkickanim ||
5834             animTarget == staffspinhitreversalanim ||
5835             animTarget == staffspinhitreversedanim ||
5836             animTarget == staffhitreversalanim ||
5837             animTarget == staffhitreversedanim ||
5838             animTarget == hurtidleanim ||
5839             animTarget == winduppunchanim ||
5840             animTarget == swordslashreversalanim ||
5841             animTarget == swordslashreversedanim ||
5842             animTarget == knifeslashreversalanim ||
5843             animTarget == knifeslashreversedanim ||
5844             animTarget == knifethrowanim ||
5845             animTarget == knifefollowanim ||
5846             animTarget == knifefollowedanim ||
5847             animTarget == killanim ||
5848             animTarget == dropkickanim ||
5849             animTarget == upunchanim ||
5850             animTarget == knifeslashstartanim ||
5851             animTarget == swordslashanim ||
5852             animTarget == staffhitanim ||
5853             animTarget == staffspinhitanim ||
5854             animTarget == staffgroundsmashanim ||
5855             animTarget == spinkickreversalanim ||
5856             animTarget == sweepreversalanim ||
5857             animTarget == lowkickanim ||
5858             animTarget == sweepreversedanim ||
5859             animTarget == rabbitkickreversalanim ||
5860             animTarget == rabbitkickreversedanim ||
5861             animTarget == jumpreversalanim ||
5862             animTarget == jumpreversedanim) {
5863             //close hands and yell
5864             if (righthandmorphend != 1 &&
5865                 righthandmorphness == targetrighthandmorphness) {
5866                 righthandmorphness = 0;
5867                 righthandmorphend = 1;
5868                 targetrighthandmorphness = 1;
5869             }
5870
5871             if (lefthandmorphend != 1 &&
5872                 lefthandmorphness == targetlefthandmorphness) {
5873                 lefthandmorphness = 0;
5874                 lefthandmorphend = 1;
5875                 targetlefthandmorphness = 1;
5876             }
5877
5878             if (headmorphend != 2 && headmorphness == targetheadmorphness) {
5879                 headmorphness = 1;
5880                 headmorphend = 2;
5881                 targetheadmorphness = 1;
5882             }
5883         }
5884
5885         bool behind;
5886         behind = 0;
5887         if (hasvictim) {
5888             if ((victim != this->shared_from_this()) && !victim->dead && (victim->aitype != passivetype) &&
5889                 (victim->aitype != searchtype) && (aitype != passivetype) &&
5890                 (aitype != searchtype) && (victim->id < Person::players.size())) {
5891                 behind = (normaldotproduct(facing, coords - victim->coords) > 0);
5892             }
5893         }
5894
5895         if (!dead && animTarget != hurtidleanim) {
5896             if (behind || animTarget == killanim || animTarget == knifethrowanim || animTarget == knifefollowanim || animTarget == spinkickreversalanim || animTarget == rabbitkickreversedanim || animTarget == jumpreversedanim) {
5897                 if (headmorphend != 4 || headmorphness == targetheadmorphness) {
5898                     headmorphend = 4;
5899                     //headmorphness=1;
5900                     targetheadmorphness = 1;
5901                 }
5902             }
5903         }
5904
5905         if (weaponactive != -1) {
5906             if (weapons[weaponids[weaponactive]].getType() != staff) {
5907                 righthandmorphstart = 1;
5908                 righthandmorphend = 1;
5909             }
5910             if (weapons[weaponids[weaponactive]].getType() == staff) {
5911                 righthandmorphstart = 2;
5912                 righthandmorphend = 2;
5913             }
5914             targetrighthandmorphness = 1;
5915         }
5916
5917         terrainnormal = terrain.getNormal(coords.x, coords.z);
5918
5919         if (Animation::animations[animTarget].attack != reversal) {
5920             if (!isnormal(coords.x)) {
5921                 coords = oldcoords;
5922             }
5923             oldcoords = coords;
5924         }
5925
5926         flatfacing = 0;
5927         flatfacing.z = 1;
5928
5929         flatfacing = DoRotation(flatfacing, 0, yaw, 0);
5930         facing = flatfacing;
5931         ReflectVector(&facing, terrainnormal);
5932         Normalise(&facing);
5933
5934         if (isRun() ||
5935             animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim) {
5936             if (onterrain) {
5937                 targettilt2 = -facing.y * 20;
5938             } else {
5939                 targettilt2 = 0;
5940             }
5941         }
5942         onterrain = 0;
5943         if (!isRun() && !Animation::animations[animTarget].attack && animTarget != getupfromfrontanim && animTarget != getupfrombackanim && animTarget != sneakanim) {
5944             targettilt2 = 0;
5945         }
5946         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
5947             flatvelocity = velocity;
5948             flatvelocity.y = 0;
5949             flatvelspeed = findLength(&flatvelocity);
5950             targettilt = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(DoRotation(flatfacing, 0, -90, 0), flatvelocity);
5951             targettilt2 = flatvelspeed * fast_sqrt(abs(velocity.y) * .7) * normaldotproduct(flatfacing, flatvelocity);
5952             if (velocity.y < 0) {
5953                 targettilt2 *= -1;
5954             }
5955             if (velocity.y < 0) {
5956                 targettilt *= -1;
5957             }
5958             if (targettilt > 25) {
5959                 targettilt = 25;
5960             }
5961             if (targettilt < -25) {
5962                 targettilt = -25;
5963             }
5964         }
5965
5966         if (targettilt2 > 45) {
5967             targettilt2 = 45;
5968         }
5969         if (targettilt2 < -45) {
5970             targettilt2 = -45;
5971         }
5972         if (abs(tilt2 - targettilt2) < multiplier * 400) {
5973             tilt2 = targettilt2;
5974         } else if (tilt2 > targettilt2) {
5975             tilt2 -= multiplier * 400;
5976         } else if (tilt2 < targettilt2) {
5977             tilt2 += multiplier * 400;
5978         }
5979         if (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && animTarget != getupfromfrontanim) {
5980             if (tilt2 > 25) {
5981                 tilt2 = 25;
5982             }
5983             if (tilt2 < -25) {
5984                 tilt2 = -25;
5985             }
5986         }
5987
5988         if (!isnormal(targettilt) && targettilt) {
5989             targettilt = 0;
5990         }
5991         if (!isnormal(targettilt2) && targettilt2) {
5992             targettilt2 = 0;
5993         }
5994
5995         //Running velocity
5996         if (animTarget == rabbittackleanim) {
5997             velocity += facing * multiplier * speed * 700 * scale;
5998             velspeed = findLength(&velocity);
5999             if (velspeed > speed * 65 * scale) {
6000                 velocity /= velspeed;
6001                 velspeed = speed * 65 * scale;
6002                 velocity *= velspeed;
6003             }
6004             velocity.y += gravity * multiplier * 20;
6005             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6006             velspeed = findLength(&velocity);
6007             velocity = flatfacing * velspeed;
6008         }
6009         if (animTarget != rabbitrunninganim && animTarget != wolfrunninganim) {
6010             if (isRun() || animTarget == rabbitkickanim) {
6011                 velocity += facing * multiplier * speed * 700 * scale;
6012                 velspeed = findLength(&velocity);
6013                 if (velspeed > speed * 45 * scale) {
6014                     velocity /= velspeed;
6015                     velspeed = speed * 45 * scale;
6016                     velocity *= velspeed;
6017                 }
6018                 velocity.y += gravity * multiplier * 20;
6019                 ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6020                 velspeed = findLength(&velocity);
6021                 if (velspeed < speed * 30 * scale) {
6022                     velspeed = speed * 30 * scale;
6023                 }
6024                 velocity = flatfacing * velspeed;
6025             }
6026         } else if (isRun()) {
6027             velocity += facing * multiplier * speed * 700 * scale;
6028             velspeed = findLength(&velocity);
6029             if (creature == rabbittype) {
6030                 if (velspeed > speed * 55 * scale) {
6031                     velocity /= velspeed;
6032                     velspeed = speed * 55 * scale;
6033                     velocity *= velspeed;
6034                 }
6035             }
6036             if (creature == wolftype) {
6037                 if (velspeed > speed * 75 * scale) {
6038                     velocity /= velspeed;
6039                     velspeed = speed * 75 * scale;
6040                     velocity *= velspeed;
6041                 }
6042             }
6043             velocity.y += gravity * multiplier * 20;
6044             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6045             velspeed = findLength(&velocity);
6046             velocity = flatfacing * velspeed;
6047         }
6048
6049         if (animTarget == rollanim && targetFrame().label != 6) {
6050             velocity += facing * multiplier * speed * 700 * scale;
6051             velspeed = findLength(&velocity);
6052             if (velspeed > speed * 45 * scale) {
6053                 velocity /= velspeed;
6054                 velspeed = speed * 45 * scale;
6055                 velocity *= velspeed;
6056             }
6057             velocity.y += gravity * multiplier * 20;
6058             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6059             velspeed = findLength(&velocity);
6060             velocity = flatfacing * velspeed;
6061         }
6062
6063         if (animTarget == sneakanim || animTarget == walkanim) {
6064             velocity += facing * multiplier * speed * 700 * scale;
6065             velspeed = findLength(&velocity);
6066             if (velspeed > speed * 12 * scale) {
6067                 velocity /= velspeed;
6068                 velspeed = speed * 12 * scale;
6069                 velocity *= velspeed;
6070             }
6071             velocity.y += gravity * multiplier * 20;
6072             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6073             velspeed = findLength(&velocity);
6074             velocity = flatfacing * velspeed;
6075         }
6076
6077         if ((animTarget == fightidleanim || animTarget == knifefightidleanim) && (animCurrent == bounceidleanim || animCurrent == hurtidleanim)) {
6078             velocity += facing * multiplier * speed * 700 * scale;
6079             velspeed = findLength(&velocity);
6080             if (velspeed > speed * 2 * scale) {
6081                 velocity /= velspeed;
6082                 velspeed = speed * 2 * scale;
6083                 velocity *= velspeed;
6084             }
6085             velocity.y += gravity * multiplier * 20;
6086             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6087             velspeed = findLength(&velocity);
6088             velocity = flatfacing * velspeed;
6089         }
6090
6091         if ((animTarget == bounceidleanim || animCurrent == hurtidleanim) && (animCurrent == fightidleanim || animCurrent == knifefightidleanim)) {
6092             velocity -= facing * multiplier * speed * 700 * scale;
6093             velspeed = findLength(&velocity);
6094             if (velspeed > speed * 2 * scale) {
6095                 velocity /= velspeed;
6096                 velspeed = speed * 2 * scale;
6097                 velocity *= velspeed;
6098             }
6099             velocity.y += gravity * multiplier * 20;
6100             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6101             velspeed = findLength(&velocity);
6102             velocity = flatfacing * velspeed * -1;
6103         }
6104
6105         if (animTarget == fightsidestep) {
6106             velocity += DoRotation(facing * multiplier * speed * 700 * scale, 0, -90, 0);
6107             velspeed = findLength(&velocity);
6108             if (velspeed > speed * 12 * scale) {
6109                 velocity /= velspeed;
6110                 velspeed = speed * 12 * scale;
6111                 velocity *= velspeed;
6112             }
6113             velocity.y += gravity * multiplier * 20;
6114             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6115             velspeed = findLength(&velocity);
6116             velocity = DoRotation(flatfacing * velspeed, 0, -90, 0);
6117         }
6118
6119         if (animTarget == staggerbackhighanim) {
6120             coords -= facing * multiplier * speed * 16 * scale;
6121             velocity = 0;
6122         }
6123         if (animTarget == staggerbackhardanim && Animation::animations[staggerbackhardanim].frames[frameTarget].label != 6) {
6124             coords -= facing * multiplier * speed * 20 * scale;
6125             velocity = 0;
6126         }
6127
6128         if (animTarget == backhandspringanim) {
6129             //coords-=facing*multiplier*50*scale;
6130             velocity += facing * multiplier * speed * 700 * scale * -1;
6131             velspeed = findLength(&velocity);
6132             if (velspeed > speed * 50 * scale) {
6133                 velocity /= velspeed;
6134                 velspeed = speed * 50 * scale;
6135                 velocity *= velspeed;
6136             }
6137             velocity.y += gravity * multiplier * 20;
6138             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6139             velspeed = findLength(&velocity);
6140             velocity = flatfacing * velspeed * -1;
6141         }
6142         if (animTarget == dodgebackanim) {
6143             //coords-=facing*multiplier*50*scale;
6144             velocity += facing * multiplier * speed * 700 * scale * -1;
6145             velspeed = findLength(&velocity);
6146             if (velspeed > speed * 60 * scale) {
6147                 velocity /= velspeed;
6148                 velspeed = speed * 60 * scale;
6149                 velocity *= velspeed;
6150             }
6151             velocity.y += gravity * multiplier * 20;
6152             ReflectVector(&velocity, terrain.getNormal(coords.x, coords.z));
6153             velspeed = findLength(&velocity);
6154             velocity = flatfacing * velspeed * -1;
6155         }
6156
6157         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
6158             velspeed = findLength(&velocity);
6159         }
6160
6161         if (animTarget == jumpupanim || animTarget == jumpdownanim || isFlip()) {
6162             velocity.y += gravity * multiplier;
6163         }
6164
6165         if (animTarget != climbanim && animTarget != hanganim && !isWallJump()) {
6166             coords += velocity * multiplier;
6167         }
6168
6169         if (coords.y < terrain.getHeight(coords.x, coords.z) && (animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
6170             if (isFlip() && targetFrame().label == 7) {
6171                 RagDoll(0);
6172             }
6173
6174             if (animTarget == jumpupanim) {
6175                 jumppower = -4;
6176                 animTarget = getIdle();
6177             }
6178             target = 0;
6179             frameTarget = 0;
6180             onterrain = 1;
6181
6182             if (id == 0) {
6183                 pause_sound(whooshsound);
6184                 OPENAL_SetVolume(channels[whooshsound], 0);
6185             }
6186
6187             if (animTarget == jumpdownanim || isFlip()) {
6188                 if (isFlip()) {
6189                     jumppower = -4;
6190                 }
6191                 animTarget = getLanding();
6192                 emit_sound_at(landsound, coords, 128.);
6193
6194                 if (id == 0) {
6195                     addEnvSound(coords);
6196                 }
6197             }
6198         }
6199
6200         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && animTarget != climbanim && animTarget != hanganim && !isWallJump()) {
6201             coords.y += gravity * multiplier * 2;
6202         }
6203         if (animTarget != jumpupanim && animTarget != jumpdownanim && !isFlip() && coords.y < terrain.getHeight(coords.x, coords.z)) {
6204             coords.y = terrain.getHeight(coords.x, coords.z);
6205             onterrain = 1;
6206         }
6207
6208         if (isIdle() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim || animTarget == crouchstabanim || animTarget == swordgroundstabanim || isStop() || animTarget == removeknifeanim || animTarget == crouchremoveknifeanim || isLanding() || isCrouch() || Animation::animations[animTarget].attack || (animTarget == rollanim && targetFrame().label == 6)) {
6209             velspeed = findLength(&velocity);
6210             velocity.y = 0;
6211             if (velspeed < multiplier * 300 * scale) {
6212                 velocity = 0;
6213             } else {
6214                 velocity -= velocity / velspeed * multiplier * 300 * scale;
6215             }
6216             if (velspeed > 5 && (isLanding() || isLandhard())) {
6217                 skiddingdelay += multiplier;
6218                 if (skiddelay <= 0) {
6219                     FootLand(leftfoot, .5);
6220                     FootLand(rightfoot, .5);
6221                     skiddelay = .02;
6222                 }
6223             } else {
6224                 skiddingdelay = 0;
6225             }
6226         }
6227
6228         if (isLandhard()) {
6229             velspeed = findLength(&velocity);
6230             velocity = 0;
6231             if (velspeed > 5 && (isLanding() || isLandhard())) {
6232                 skiddingdelay += multiplier;
6233                 if (skiddelay <= 0) {
6234                     FootLand(leftfoot, .5);
6235                     FootLand(rightfoot, .5);
6236                     skiddelay = .02;
6237                 }
6238             } else {
6239                 skiddingdelay = 0;
6240             }
6241         }
6242
6243         if (skiddingdelay < 0) {
6244             skiddingdelay += multiplier;
6245         }
6246         if (skiddingdelay > .02 && !forwardkeydown && !backkeydown && !leftkeydown && !rightkeydown && !jumpkeydown && isLanding() && !landhard) {
6247             skiddingdelay = -1;
6248             if (!onterrain || environment == grassyenvironment) {
6249                 emit_sound_at(skidsound, coords, 128 * velspeed / 10);
6250             } else {
6251                 emit_sound_at(snowskidsound, coords, 128 * velspeed / 10);
6252             }
6253         }
6254
6255         if (Animation::animations[animTarget].attack == normalattack && animTarget != rabbitkickanim && !victim->skeleton.free) {
6256             terrainnormal = victim->coords - coords;
6257             Normalise(&terrainnormal);
6258             targetyaw = -asin(0 - terrainnormal.x);
6259             targetyaw *= 360 / 6.28;
6260             if (terrainnormal.z < 0) {
6261                 targetyaw = 180 - targetyaw;
6262             }
6263             targettilt2 = -asin(terrainnormal.y) * 360 / 6.28; //*-70;
6264         }
6265
6266         if (Animation::animations[animTarget].attack == reversal && animTarget != rabbittacklinganim) {
6267             targetyaw = victim->targetyaw;
6268         }
6269         if (animTarget == rabbittacklinganim) {
6270             coords = victim->coords;
6271         }
6272     }
6273     skeleton.oldfree = skeleton.free;
6274
6275     XYZ midterrain;
6276     midterrain = 0;
6277     midterrain.x = terrain.size * terrain.scale / 2;
6278     midterrain.z = terrain.size * terrain.scale / 2;
6279     if (distsqflat(&coords, &midterrain) > (terrain.size * terrain.scale / 2 - viewdistance) * (terrain.size * terrain.scale / 2 - viewdistance)) {
6280         XYZ tempposit;
6281         tempposit = coords - midterrain;
6282         tempposit.y = 0;
6283         Normalise(&tempposit);
6284         tempposit *= (terrain.size * terrain.scale / 2 - viewdistance);
6285         coords.x = tempposit.x + midterrain.x;
6286         coords.z = tempposit.z + midterrain.z;
6287     }
6288 }
6289
6290 /* EFFECT
6291  * inverse kinematics helper function
6292  */
6293 void IKHelper(Person* p, float interp)
6294 {
6295     XYZ point, change, change2;
6296     float heightleft, heightright;
6297
6298     // TODO: implement localToWorld and worldToLocal
6299     //       but keep in mind it won't be the same math if player is ragdolled or something
6300     //       - localToWorldStanding / worldToLocalStanding (or crouching or...?)
6301     //       then comb through code for places where to use it
6302
6303     // point = localToWorld(jointPos(leftfoot))
6304     point = DoRotation(p->jointPos(leftfoot), 0, p->yaw, 0) * p->scale + p->coords;
6305     // adjust height of foot
6306     heightleft = terrain.getHeight(point.x, point.z) + .04;
6307     point.y = heightleft;
6308     change = p->jointPos(leftankle) - p->jointPos(leftfoot);
6309     change2 = p->jointPos(leftknee) - p->jointPos(leftfoot);
6310     // jointPos(leftfoot) = interpolate(worldToLocal(point), jointPos(leftfoot), interp)
6311     p->jointPos(leftfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(leftfoot) * (1 - interp);
6312     // move ankle along with foot
6313     p->jointPos(leftankle) = p->jointPos(leftfoot) + change;
6314     // average knee pos between old and new pos
6315     p->jointPos(leftknee) = (p->jointPos(leftfoot) + change2) / 2 + (p->jointPos(leftknee)) / 2;
6316
6317     // do same as above for right leg
6318     point = DoRotation(p->jointPos(rightfoot), 0, p->yaw, 0) * p->scale + p->coords;
6319     heightright = terrain.getHeight(point.x, point.z) + .04;
6320     point.y = heightright;
6321     change = p->jointPos(rightankle) - p->jointPos(rightfoot);
6322     change2 = p->jointPos(rightknee) - p->jointPos(rightfoot);
6323     p->jointPos(rightfoot) = DoRotation((point - p->coords) / p->scale, 0, -p->yaw, 0) * interp + p->jointPos(rightfoot) * (1 - interp);
6324     p->jointPos(rightankle) = p->jointPos(rightfoot) + change;
6325     p->jointPos(rightknee) = (p->jointPos(rightfoot) + change2) / 2 + (p->jointPos(rightknee)) / 2;
6326
6327     // fix up skeleton now that we've moved body parts?
6328     p->skeleton.DoConstraints(&p->coords, &p->scale);
6329 }
6330
6331 /* EFFECT
6332  * MONSTER
6333  * TODO: ???
6334  */
6335 int Person::DrawSkeleton()
6336 {
6337     int oldplayerdetail;
6338     if ((frustum.SphereInFrustum(coords.x, coords.y + scale * 3, coords.z, scale * 8) && distsq(&viewer, &coords) < viewdistance * viewdistance) || skeleton.free == 3) {
6339         if (onterrain && (isIdle() || isCrouch() || wasIdle() || wasCrouch()) && !skeleton.free) {
6340             calcrot = 1;
6341         }
6342
6343         if (headless) {
6344             headmorphness = 0;
6345             headmorphstart = 6;
6346             headmorphend = 6;
6347         }
6348
6349         glAlphaFunc(GL_GREATER, 0.0001);
6350         XYZ terrainlight;
6351         float terrainheight;
6352         float distance;
6353         if (!isnormal(yaw)) {
6354             yaw = 0;
6355         }
6356         if (!isnormal(tilt)) {
6357             tilt = 0;
6358         }
6359         if (!isnormal(tilt2)) {
6360             tilt2 = 0;
6361         }
6362         oldplayerdetail = playerdetail;
6363         playerdetail = 0;
6364         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 32 && detail == 2) {
6365             playerdetail = 1;
6366         }
6367         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 128 && detail == 1) {
6368             playerdetail = 1;
6369         }
6370         if (distsq(&viewer, &coords) < viewdistance * viewdistance / 256 && (detail != 1 && detail != 2)) {
6371             playerdetail = 1;
6372         }
6373         if (id == 0) {
6374             playerdetail = 1;
6375         }
6376         if (playerdetail != oldplayerdetail) {
6377             updatedelay = 0;
6378             normalsupdatedelay = 0;
6379         }
6380         static float updatedelaychange;
6381         static float morphness;
6382         static float framemult;
6383         if (calcrot) {
6384             skeleton.FindForwards();
6385             if (howactive == typesittingwall) {
6386                 skeleton.specialforward[1] = 0;
6387                 skeleton.specialforward[1].z = 1;
6388             }
6389         }
6390         static XYZ mid;
6391         static float M[16];
6392         static int k;
6393         static int weaponattachmuscle;
6394         static int weaponrotatemuscle;
6395         static XYZ weaponpoint;
6396         static int start, endthing;
6397         if ((dead != 2 || skeleton.free != 2) && updatedelay <= 0) {
6398             if (!isSleeping() && !isSitting()) {
6399                 // TODO: give these meaningful names
6400                 const bool cond1 = (isIdle() || isCrouch() || isLanding() || isLandhard() || animTarget == drawrightanim || animTarget == drawleftanim || animTarget == crouchdrawrightanim);
6401                 const bool cond2 = (wasIdle() || wasCrouch() || wasLanding() || wasLandhard() || animCurrent == drawrightanim || animCurrent == drawleftanim || animCurrent == crouchdrawrightanim);
6402
6403                 if (onterrain && (cond1 && cond2) && !skeleton.free) {
6404                     IKHelper(this, 1);
6405                     if (creature == wolftype) {
6406                         IKHelper(this, 1);
6407                     }
6408                 }
6409
6410                 if (onterrain && (cond1 && !cond2) && !skeleton.free) {
6411                     IKHelper(this, target);
6412                     if (creature == wolftype) {
6413                         IKHelper(this, target);
6414                     }
6415                 }
6416
6417                 if (onterrain && (!cond1 && cond2) && !skeleton.free) {
6418                     IKHelper(this, 1 - target);
6419                     if (creature == wolftype) {
6420                         IKHelper(this, 1 - target);
6421                     }
6422                 }
6423             }
6424
6425             if (!skeleton.free && (!Animation::animations[animTarget].attack && animTarget != getupfrombackanim && ((animTarget != rollanim && !isFlip()) || targetFrame().label == 6) && animTarget != getupfromfrontanim && animTarget != wolfrunninganim && animTarget != rabbitrunninganim && animTarget != backhandspringanim && animTarget != walljumpfrontanim && animTarget != hurtidleanim && !isLandhard() && !isSleeping())) {
6426                 DoHead();
6427             } else {
6428                 targetheadyaw = -targetyaw;
6429                 targetheadpitch = 0;
6430                 if (Animation::animations[animTarget].attack == 3) {
6431                     targetheadyaw += 180;
6432                 }
6433             }
6434             for (int i = 0; i < skeleton.drawmodel.vertexNum; i++) {
6435                 skeleton.drawmodel.vertex[i] = 0;
6436                 skeleton.drawmodel.vertex[i].y = 999;
6437             }
6438             for (int i = 0; i < skeleton.drawmodellow.vertexNum; i++) {
6439                 skeleton.drawmodellow.vertex[i] = 0;
6440                 skeleton.drawmodellow.vertex[i].y = 999;
6441             }
6442             for (int i = 0; i < skeleton.drawmodelclothes.vertexNum; i++) {
6443                 skeleton.drawmodelclothes.vertex[i] = 0;
6444                 skeleton.drawmodelclothes.vertex[i].y = 999;
6445             }
6446             for (unsigned int i = 0; i < skeleton.muscles.size(); i++) {
6447                 // convenience renames
6448                 const int p1 = skeleton.muscles[i].parent1->label;
6449                 const int p2 = skeleton.muscles[i].parent2->label;
6450
6451                 if ((skeleton.muscles[i].vertices.size() > 0 && playerdetail) || (skeleton.muscles[i].verticeslow.size() > 0 && !playerdetail)) {
6452                     morphness = 0;
6453                     start = 0;
6454                     endthing = 0;
6455
6456                     if (p1 == righthand || p2 == righthand) {
6457                         morphness = righthandmorphness;
6458                         start = righthandmorphstart;
6459                         endthing = righthandmorphend;
6460                     }
6461                     if (p1 == lefthand || p2 == lefthand) {
6462                         morphness = lefthandmorphness;
6463                         start = lefthandmorphstart;
6464                         endthing = lefthandmorphend;
6465                     }
6466                     if (p1 == head || p2 == head) {
6467                         morphness = headmorphness;
6468                         start = headmorphstart;
6469                         endthing = headmorphend;
6470                     }
6471                     if ((p1 == neck && p2 == abdomen) || (p2 == neck && p1 == abdomen)) {
6472                         morphness = chestmorphness;
6473                         start = chestmorphstart;
6474                         endthing = chestmorphend;
6475                     }
6476                     if ((p1 == groin && p2 == abdomen) || (p2 == groin && p1 == abdomen)) {
6477                         morphness = tailmorphness;
6478                         start = tailmorphstart;
6479                         endthing = tailmorphend;
6480                     }
6481                     if (calcrot) {
6482                         skeleton.FindRotationMuscle(i, animTarget);
6483                     }
6484                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
6485                     glMatrixMode(GL_MODELVIEW);
6486                     glPushMatrix();
6487                     glLoadIdentity();
6488                     if (!skeleton.free) {
6489                         glRotatef(tilt2, 1, 0, 0);
6490                     }
6491                     if (!skeleton.free) {
6492                         glRotatef(tilt, 0, 0, 1);
6493                     }
6494
6495                     glTranslatef(mid.x, mid.y, mid.z);
6496
6497                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
6498                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
6499
6500                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
6501                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
6502
6503                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
6504                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
6505
6506                     if (playerdetail || skeleton.free == 3) {
6507                         for (unsigned j = 0; j < skeleton.muscles[i].vertices.size(); j++) {
6508                             XYZ& v0 = skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]];
6509                             XYZ& v1 = skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]];
6510                             glMatrixMode(GL_MODELVIEW);
6511                             glPushMatrix();
6512                             if (p1 == abdomen || p2 == abdomen) {
6513                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(1).x,
6514                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(1).y,
6515                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(1).z);
6516                             }
6517                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6518                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(2).x,
6519                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(2).y,
6520                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(2).z);
6521                             }
6522                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6523                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(3).x,
6524                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(3).y,
6525                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(3).z);
6526                             }
6527                             if (p1 == head || p2 == head) {
6528                                 glTranslatef((v0.x * (1 - morphness) + v1.x * morphness) * getProportionXYZ(0).x,
6529                                              (v0.y * (1 - morphness) + v1.y * morphness) * getProportionXYZ(0).y,
6530                                              (v0.z * (1 - morphness) + v1.z * morphness) * getProportionXYZ(0).z);
6531                             }
6532                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
6533                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x = M[12] * scale;
6534                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y = M[13] * scale;
6535                             skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z = M[14] * scale;
6536                             glPopMatrix();
6537                         }
6538                     }
6539                     if (!playerdetail || skeleton.free == 3) {
6540                         for (unsigned j = 0; j < skeleton.muscles[i].verticeslow.size(); j++) {
6541                             XYZ& v0 = skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]];
6542                             glMatrixMode(GL_MODELVIEW);
6543                             glPushMatrix();
6544                             if (p1 == abdomen || p2 == abdomen) {
6545                                 glTranslatef(v0.x * getProportionXYZ(1).x,
6546                                              v0.y * getProportionXYZ(1).y,
6547                                              v0.z * getProportionXYZ(1).z);
6548                             }
6549                             if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6550                                 glTranslatef(v0.x * getProportionXYZ(2).x,
6551                                              v0.y * getProportionXYZ(2).y,
6552                                              v0.z * getProportionXYZ(2).z);
6553                             }
6554                             if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6555                                 glTranslatef(v0.x * getProportionXYZ(3).x,
6556                                              v0.y * getProportionXYZ(3).y,
6557                                              v0.z * getProportionXYZ(3).z);
6558                             }
6559                             if (p1 == head || p2 == head) {
6560                                 glTranslatef(v0.x * getProportionXYZ(0).x,
6561                                              v0.y * getProportionXYZ(0).y,
6562                                              v0.z * getProportionXYZ(0).z);
6563                             }
6564
6565                             glGetFloatv(GL_MODELVIEW_MATRIX, M);
6566                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x = M[12] * scale;
6567                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y = M[13] * scale;
6568                             skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z = M[14] * scale;
6569                             glPopMatrix();
6570                         }
6571                     }
6572                     glPopMatrix();
6573                 }
6574                 if (skeleton.clothes && skeleton.muscles[i].verticesclothes.size() > 0) {
6575                     mid = (skeleton.muscles[i].parent1->position + skeleton.muscles[i].parent2->position) / 2;
6576
6577                     glMatrixMode(GL_MODELVIEW);
6578                     glPushMatrix();
6579                     glLoadIdentity();
6580                     if (!skeleton.free) {
6581                         glRotatef(tilt2, 1, 0, 0);
6582                     }
6583                     if (!skeleton.free) {
6584                         glRotatef(tilt, 0, 0, 1);
6585                     }
6586                     glTranslatef(mid.x, mid.y, mid.z);
6587                     skeleton.muscles[i].lastrotate1 = skeleton.muscles[i].rotate1;
6588                     glRotatef(-skeleton.muscles[i].lastrotate1 + 90, 0, 1, 0);
6589
6590                     skeleton.muscles[i].lastrotate2 = skeleton.muscles[i].rotate2;
6591                     glRotatef(-skeleton.muscles[i].lastrotate2 + 90, 0, 0, 1);
6592
6593                     skeleton.muscles[i].lastrotate3 = skeleton.muscles[i].rotate3;
6594                     glRotatef(-skeleton.muscles[i].lastrotate3, 0, 1, 0);
6595
6596                     for (unsigned j = 0; j < skeleton.muscles[i].verticesclothes.size(); j++) {
6597                         XYZ& v0 = skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]];
6598                         glMatrixMode(GL_MODELVIEW);
6599                         glPushMatrix();
6600                         if (p1 == abdomen || p2 == abdomen) {
6601                             glTranslatef(v0.x * getProportionXYZ(1).x,
6602                                          v0.y * getProportionXYZ(1).y,
6603                                          v0.z * getProportionXYZ(1).z);
6604                         }
6605                         if (p1 == lefthand || p1 == righthand || p1 == leftwrist || p1 == rightwrist || p1 == leftelbow || p1 == rightelbow || p2 == leftelbow || p2 == rightelbow) {
6606                             glTranslatef(v0.x * getProportionXYZ(2).x,
6607                                          v0.y * getProportionXYZ(2).y,
6608                                          v0.z * getProportionXYZ(2).z);
6609                         }
6610                         if (p1 == leftfoot || p1 == rightfoot || p1 == leftankle || p1 == rightankle || p1 == leftknee || p1 == rightknee || p2 == leftknee || p2 == rightknee) {
6611                             glTranslatef(v0.x * getProportionXYZ(3).x,
6612                                          v0.y * getProportionXYZ(3).y,
6613                                          v0.z * getProportionXYZ(3).z);
6614                         }
6615                         if (p1 == head || p2 == head) {
6616                             glTranslatef(v0.x * getProportionXYZ(0).x,
6617                                          v0.y * getProportionXYZ(0).y,
6618                                          v0.z * getProportionXYZ(0).z);
6619                         }
6620                         glGetFloatv(GL_MODELVIEW_MATRIX, M);
6621                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x = M[12] * scale;
6622                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y = M[13] * scale;
6623                         skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z = M[14] * scale;
6624                         glPopMatrix();
6625                     }
6626                     glPopMatrix();
6627                 }
6628                 updatedelay = 1 + (float)(Random() % 100) / 1000;
6629             }
6630             if (skeleton.free != 2 && (skeleton.free == 1 || skeleton.free == 3 || id == 0 || (normalsupdatedelay <= 0) || animTarget == getupfromfrontanim || animTarget == getupfrombackanim || animCurrent == getupfromfrontanim || animCurrent == getupfrombackanim)) {
6631                 normalsupdatedelay = 1;
6632                 if (playerdetail || skeleton.free == 3) {
6633                     skeleton.drawmodel.CalculateNormals(0);
6634                 }
6635                 if (!playerdetail || skeleton.free == 3) {
6636                     skeleton.drawmodellow.CalculateNormals(0);
6637                 }
6638                 if (skeleton.clothes) {
6639                     skeleton.drawmodelclothes.CalculateNormals(0);
6640                 }
6641             } else {
6642                 if (playerdetail || skeleton.free == 3) {
6643                     skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
6644                 }
6645                 if (!playerdetail || skeleton.free == 3) {
6646                     skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
6647                 }
6648                 if (skeleton.clothes) {
6649                     skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
6650                 }
6651             }
6652         }
6653         framemult = .01;
6654         updatedelaychange = -framemult * 4 * (45 - findDistance(&viewer, &coords) * 1);
6655         if (updatedelaychange > -realmultiplier * 30) {
6656             updatedelaychange = -realmultiplier * 30;
6657         }
6658         if (updatedelaychange > -framemult * 4) {
6659             updatedelaychange = -framemult * 4;
6660         }
6661         if (skeleton.free == 1) {
6662             updatedelaychange *= 6;
6663         }
6664         if (id == 0) {
6665             updatedelaychange *= 8;
6666         }
6667         updatedelay += updatedelaychange;
6668
6669         glMatrixMode(GL_MODELVIEW);
6670         glPushMatrix();
6671         glTranslatef(coords.x, coords.y - .02, coords.z);
6672         if (!skeleton.free) {
6673             glTranslatef(offset.x * scale, offset.y * scale, offset.z * scale);
6674             glRotatef(yaw, 0, 1, 0);
6675         }
6676         if (showpoints) {
6677             glPointSize(5);
6678             glColor4f(.4, 1, .4, 1);
6679             glDisable(GL_LIGHTING);
6680             glDisable(GL_TEXTURE_2D);
6681             glBegin(GL_POINTS);
6682             if (playerdetail) {
6683                 for (int i = 0; i < skeleton.drawmodel.vertexNum; i++) {
6684                     XYZ& v0 = skeleton.drawmodel.vertex[i];
6685                     glVertex3f(v0.x, v0.y, v0.z);
6686                 }
6687             }
6688             glEnd();
6689             glBegin(GL_LINES);
6690
6691             if (playerdetail) {
6692                 for (unsigned int i = 0; i < skeleton.drawmodel.Triangles.size(); i++) {
6693                     const XYZ& v0 = skeleton.drawmodel.getTriangleVertex(i, 0);
6694                     const XYZ& v1 = skeleton.drawmodel.getTriangleVertex(i, 1);
6695                     const XYZ& v2 = skeleton.drawmodel.getTriangleVertex(i, 2);
6696                     glVertex3f(v0.x, v0.y, v0.z);
6697                     glVertex3f(v1.x, v1.y, v1.z);
6698                     glVertex3f(v1.x, v1.y, v1.z);
6699                     glVertex3f(v2.x, v2.y, v2.z);
6700                     glVertex3f(v2.x, v2.y, v2.z);
6701                     glVertex3f(v0.x, v0.y, v0.z);
6702                 }
6703             }
6704
6705             glEnd();
6706         }
6707
6708         terrainlight = terrain.getLighting(coords.x, coords.z);
6709         distance = distsq(&viewer, &coords);
6710         distance = (viewdistance * viewdistance - (distance - (viewdistance * viewdistance * fadestart)) * (1 / (1 - fadestart))) / viewdistance / viewdistance;
6711         if (distance > 1) {
6712             distance = 1;
6713         }
6714         if (distance > 0) {
6715             terrainheight = (coords.y - terrain.getHeight(coords.x, coords.z)) / 3 + 1;
6716             if (terrainheight < 1) {
6717                 terrainheight = 1;
6718             }
6719             if (terrainheight > 1.7) {
6720                 terrainheight = 1.7;
6721             }
6722
6723             glColor4f((1 - (1 - terrainlight.x) / terrainheight) - burnt, (1 - (1 - terrainlight.y) / terrainheight) - burnt, (1 - (1 - terrainlight.z) / terrainheight) - burnt, distance);
6724             glDisable(GL_BLEND);
6725             glAlphaFunc(GL_GREATER, 0.0001);
6726             glEnable(GL_TEXTURE_2D);
6727             if (cellophane) {
6728                 glDisable(GL_TEXTURE_2D);
6729                 glColor4f(.7, .35, 0, .5);
6730                 glDepthMask(0);
6731                 glEnable(GL_LIGHTING);
6732                 glEnable(GL_BLEND);
6733             }
6734             if (Tutorial::active && id != 0) {
6735                 glColor4f(.7, .7, .7, 0.6);
6736                 glDepthMask(0);
6737                 glEnable(GL_LIGHTING);
6738                 glEnable(GL_BLEND);
6739                 if (canattack && cananger) {
6740                     if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
6741                         glDisable(GL_TEXTURE_2D);
6742                         glColor4f(1, 0, 0, 0.8);
6743                     }
6744                 }
6745                 glMatrixMode(GL_TEXTURE);
6746                 glPushMatrix();
6747                 glTranslatef(0, -smoketex, 0);
6748                 glTranslatef(-smoketex, 0, 0);
6749             }
6750             if (playerdetail) {
6751                 if (!showpoints) {
6752                     if (Tutorial::active && (id != 0)) {
6753                         skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6754                     } else {
6755                         skeleton.drawmodel.draw();
6756                     }
6757                 }
6758             }
6759             if (!playerdetail) {
6760                 if (Tutorial::active && (id != 0)) {
6761                     skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6762                 } else {
6763                     skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6764                 }
6765             }
6766
6767             if (!(Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed)) {
6768                 if (Tutorial::active && id != 0) {
6769                     glPopMatrix();
6770                     glMatrixMode(GL_MODELVIEW);
6771                     glEnable(GL_TEXTURE_2D);
6772                     glColor4f(.7, .7, .7, 0.6);
6773                     glDepthMask(0);
6774                     glEnable(GL_LIGHTING);
6775                     glEnable(GL_BLEND);
6776                     if (canattack && cananger) {
6777                         if (Animation::animations[animTarget].attack == normalattack || Animation::animations[animTarget].attack == reversed) {
6778                             glDisable(GL_TEXTURE_2D);
6779                             glColor4f(1, 0, 0, 0.8);
6780                         }
6781                     }
6782                     glMatrixMode(GL_TEXTURE);
6783                     glPushMatrix();
6784                     glTranslatef(0, -smoketex * .6, 0);
6785                     glTranslatef(smoketex * .6, 0, 0);
6786                     if (playerdetail) {
6787                         if (!showpoints) {
6788                             if (Tutorial::active && (id != 0)) {
6789                                 skeleton.drawmodel.drawdifftex(Sprite::cloudimpacttexture);
6790                             } else {
6791                                 skeleton.drawmodel.draw();
6792                             }
6793                         }
6794                     }
6795                     if (!playerdetail) {
6796                         if (Tutorial::active && (id != 0)) {
6797                             skeleton.drawmodellow.drawdifftex(Sprite::cloudimpacttexture);
6798                         } else {
6799                             skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
6800                         }
6801                     }
6802                 }
6803             }
6804
6805             if (Tutorial::active && id != 0) {
6806                 glPopMatrix();
6807                 glMatrixMode(GL_MODELVIEW);
6808                 glEnable(GL_TEXTURE_2D);
6809             }
6810             if (skeleton.clothes) {
6811                 glDepthMask(0);
6812                 glEnable(GL_BLEND);
6813                 if (!immediate) {
6814                     skeleton.drawmodelclothes.draw();
6815                 }
6816                 if (immediate) {
6817                     skeleton.drawmodelclothes.drawimmediate();
6818                 }
6819                 glDepthMask(1);
6820             }
6821         }
6822         glPopMatrix();
6823
6824         if (num_weapons > 0) {
6825             for (k = 0; k < num_weapons; k++) {
6826                 int i = weaponids[k];
6827                 if (weaponactive == k) {
6828                     if (weapons[i].getType() != staff) {
6829                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6830                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
6831                                 weaponattachmuscle = j;
6832                             }
6833                         }
6834                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6835                             if ((skeleton.muscles[j].parent1->label == rightwrist || skeleton.muscles[j].parent2->label == rightwrist) && (skeleton.muscles[j].parent1->label != righthand && skeleton.muscles[j].parent2->label != righthand) && skeleton.muscles[j].vertices.size() > 0) {
6836                                 weaponrotatemuscle = j;
6837                             }
6838                         }
6839                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6840                         if (creature == wolftype) {
6841                             weaponpoint = (jointPos(rightwrist) * .7 + jointPos(righthand) * .3);
6842                         }
6843                     }
6844                     if (weapons[i].getType() == staff) {
6845                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6846                             if ((skeleton.muscles[j].parent1->label == righthand || skeleton.muscles[j].parent2->label == righthand) && skeleton.muscles[j].vertices.size() > 0) {
6847                                 weaponattachmuscle = j;
6848                             }
6849                         }
6850                         for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6851                             if ((skeleton.muscles[j].parent1->label == rightelbow || skeleton.muscles[j].parent2->label == rightelbow) && (skeleton.muscles[j].parent1->label != rightshoulder && skeleton.muscles[j].parent2->label != rightshoulder) && skeleton.muscles[j].vertices.size() > 0) {
6852                                 weaponrotatemuscle = j;
6853                             }
6854                         }
6855                         //weaponpoint=jointPos(rightwrist);
6856                         weaponpoint = (skeleton.muscles[weaponattachmuscle].parent1->position + skeleton.muscles[weaponattachmuscle].parent2->position) / 2;
6857                         //weaponpoint+=skeleton.specialforward[1]*.1+(jointPos(rightwrist)-jointPos(rightelbow));
6858                         XYZ tempnormthing, vec1, vec2;
6859                         vec1 = (jointPos(rightwrist) - jointPos(rightelbow));
6860                         vec2 = (jointPos(rightwrist) - jointPos(rightshoulder));
6861                         CrossProduct(&vec1, &vec2, &tempnormthing);
6862                         Normalise(&tempnormthing);
6863                         if (animTarget != staffhitanim && animCurrent != staffhitanim && animTarget != staffgroundsmashanim && animCurrent != staffgroundsmashanim && animTarget != staffspinhitanim && animCurrent != staffspinhitanim) {
6864                             weaponpoint += tempnormthing * .1 - skeleton.specialforward[1] * .3 + (jointPos(rightwrist) - jointPos(rightelbow));
6865                         }
6866                     }
6867                 }
6868                 if (weaponactive != k && weaponstuck != k) {
6869                     if (weapons[i].getType() == knife) {
6870                         weaponpoint = jointPos(abdomen) + (jointPos(righthip) - jointPos(lefthip)) * .1 + (jointPos(rightshoulder) - jointPos(leftshoulder)) * .35;
6871                     }
6872                     if (weapons[i].getType() == sword) {
6873                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6874                     }
6875                     if (weapons[i].getType() == staff) {
6876                         weaponpoint = jointPos(abdomen) + (jointPos(lefthip) - jointPos(righthip)) * .09 + (jointPos(leftshoulder) - jointPos(rightshoulder)) * .33;
6877                     }
6878                     for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6879                         if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
6880                             weaponrotatemuscle = j;
6881                         }
6882                     }
6883                 }
6884                 if (weaponstuck == k) {
6885                     if (weaponstuckwhere == 0) {
6886                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 - skeleton.forward * .8;
6887                     } else {
6888                         weaponpoint = jointPos(abdomen) * .5 + jointPos(neck) * .5 + skeleton.forward * .8;
6889                     }
6890                     for (unsigned j = 0; j < skeleton.muscles.size(); j++) {
6891                         if ((skeleton.muscles[j].parent1->label == abdomen || skeleton.muscles[j].parent2->label == abdomen) && (skeleton.muscles[j].parent1->label == neck || skeleton.muscles[j].parent2->label == neck) && skeleton.muscles[j].vertices.size() > 0) {
6892                             weaponrotatemuscle = j;
6893                         }
6894                     }
6895                 }
6896                 if (skeleton.free) {
6897                     weapons[i].position = weaponpoint * scale + coords;
6898                     weapons[i].bigrotation = 0;
6899                     weapons[i].bigtilt = 0;
6900                     weapons[i].bigtilt2 = 0;
6901                 } else {
6902                     weapons[i].position = DoRotation(DoRotation(DoRotation(weaponpoint, 0, 0, tilt), tilt2, 0, 0), 0, yaw, 0) * scale + coords + currentoffset * (1 - target) * scale + targetoffset * target * scale;
6903                     weapons[i].bigrotation = yaw;
6904                     weapons[i].bigtilt = tilt;
6905                     weapons[i].bigtilt2 = tilt2;
6906                 }
6907                 weapons[i].rotation1 = skeleton.muscles[weaponrotatemuscle].lastrotate1;
6908                 weapons[i].rotation2 = skeleton.muscles[weaponrotatemuscle].lastrotate2;
6909                 weapons[i].rotation3 = skeleton.muscles[weaponrotatemuscle].lastrotate3;
6910                 if (weaponactive == k) {
6911                     if (weapons[i].getType() == knife) {
6912                         weapons[i].smallrotation = 180;
6913                         weapons[i].smallrotation2 = 0;
6914                         if (isCrouch() || wasCrouch()) {
6915                             weapons[i].smallrotation2 = 20;
6916                         }
6917                         if (animTarget == hurtidleanim) {
6918                             weapons[i].smallrotation2 = 50;
6919                         }
6920                         if ((animCurrent == crouchstabanim && animTarget == crouchstabanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
6921                             XYZ temppoint1, temppoint2;
6922                             float distance;
6923
6924                             temppoint1 = jointPos(righthand);
6925                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6926                             distance = findDistance(&temppoint1, &temppoint2);
6927                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6928                             weapons[i].rotation2 *= 360 / 6.28;
6929                             temppoint1.y = 0;
6930                             temppoint2.y = 0;
6931                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6932                             weapons[i].rotation1 *= 360 / 6.28;
6933                             weapons[i].rotation3 = 0;
6934                             weapons[i].smallrotation = -90;
6935                             weapons[i].smallrotation2 = 0;
6936                             if (temppoint1.x > temppoint2.x) {
6937                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6938                             }
6939                         }
6940                         if ((animCurrent == knifeslashreversalanim && animTarget == knifeslashreversalanim) || (animCurrent == knifeslashreversedanim && animTarget == knifeslashreversedanim)) {
6941                             XYZ temppoint1, temppoint2;
6942                             float distance;
6943
6944                             temppoint1 = jointPos(righthand);
6945                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6946                             distance = findDistance(&temppoint1, &temppoint2);
6947                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6948                             weapons[i].rotation2 *= 360 / 6.28;
6949                             temppoint1.y = 0;
6950                             temppoint2.y = 0;
6951                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6952                             weapons[i].rotation1 *= 360 / 6.28;
6953                             weapons[i].rotation3 = 0;
6954                             weapons[i].smallrotation = 90;
6955                             weapons[i].smallrotation2 = 0;
6956                             if (temppoint1.x > temppoint2.x) {
6957                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
6958                             }
6959                         }
6960                         if (animTarget == knifethrowanim) {
6961                             weapons[i].smallrotation = 90;
6962                             //weapons[i].smallrotation2=-90;
6963                             weapons[i].smallrotation2 = 0;
6964                             weapons[i].rotation1 = 0;
6965                             weapons[i].rotation2 = 0;
6966                             weapons[i].rotation3 = 0;
6967                         }
6968                         if (animTarget == knifesneakattackanim && frameTarget < 5) {
6969                             weapons[i].smallrotation = -90;
6970                             weapons[i].rotation1 = 0;
6971                             weapons[i].rotation2 = 0;
6972                             weapons[i].rotation3 = 0;
6973                         }
6974                     }
6975                     if (weapons[i].getType() == sword) {
6976                         weapons[i].smallrotation = 0;
6977                         weapons[i].smallrotation2 = 0;
6978                         if (animTarget == knifethrowanim) {
6979                             weapons[i].smallrotation = -90;
6980                             weapons[i].smallrotation2 = 0;
6981                             weapons[i].rotation1 = 0;
6982                             weapons[i].rotation2 = 0;
6983                             weapons[i].rotation3 = 0;
6984                         }
6985                         if ((animTarget == swordgroundstabanim && animCurrent == swordgroundstabanim) || (animTarget == swordsneakattackanim && animCurrent == swordsneakattackanim) || (animTarget == swordslashparryanim && animCurrent == swordslashparryanim) || (animTarget == swordslashparriedanim && animCurrent == swordslashparriedanim) || (animTarget == swordslashreversalanim && animCurrent == swordslashreversalanim) || (animTarget == swordslashreversedanim && animCurrent == swordslashreversedanim) || (animTarget == knifeslashreversalanim && animCurrent == knifeslashreversalanim) || (animTarget == knifeslashreversedanim && animCurrent == knifeslashreversedanim) || (animTarget == swordslashanim && animCurrent == swordslashanim) || (animTarget == drawleftanim && animCurrent == drawleftanim) || (animCurrent == backhandspringanim && animTarget == backhandspringanim)) {
6986                             XYZ temppoint1, temppoint2;
6987                             float distance;
6988
6989                             temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
6990                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
6991                             distance = findDistance(&temppoint1, &temppoint2);
6992                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
6993                             weapons[i].rotation2 *= 360 / 6.28;
6994                             temppoint1.y = 0;
6995                             temppoint2.y = 0;
6996                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
6997                             weapons[i].rotation1 *= 360 / 6.28;
6998                             weapons[i].rotation3 = 0;
6999                             weapons[i].smallrotation = 90;
7000                             weapons[i].smallrotation2 = 0;
7001                             if (temppoint1.x > temppoint2.x) {
7002                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
7003                             }
7004                         }
7005                     }
7006                     if (weapons[i].getType() == staff) {
7007                         weapons[i].smallrotation = 100;
7008                         weapons[i].smallrotation2 = 0;
7009                         if ((animTarget == staffhitanim && animCurrent == staffhitanim) || (animTarget == staffhitreversedanim && animCurrent == staffhitreversedanim) || (animTarget == staffspinhitreversedanim && animCurrent == staffspinhitreversedanim) || (animTarget == staffgroundsmashanim && animCurrent == staffgroundsmashanim) || (animTarget == staffspinhitanim && animCurrent == staffspinhitanim)) {
7010                             XYZ temppoint1, temppoint2;
7011                             float distance;
7012
7013                             temppoint1 = currentFrame().joints[skeleton.jointlabels[righthand]].position * (1 - target) + targetFrame().joints[skeleton.jointlabels[righthand]].position * (target); //jointPos(righthand);
7014                             temppoint2 = currentFrame().weapontarget * (1 - target) + targetFrame().weapontarget * (target);
7015                             distance = findDistance(&temppoint1, &temppoint2);
7016                             weapons[i].rotation2 = asin((temppoint1.y - temppoint2.y) / distance);
7017                             weapons[i].rotation2 *= 360 / 6.28;
7018                             temppoint1.y = 0;
7019                             temppoint2.y = 0;
7020                             weapons[i].rotation1 = acos((temppoint1.z - temppoint2.z) / findDistance(&temppoint1, &temppoint2));
7021                             weapons[i].rotation1 *= 360 / 6.28;
7022                             weapons[i].rotation3 = 0;
7023                             weapons[i].smallrotation = 90;
7024                             weapons[i].smallrotation2 = 0;
7025                             if (temppoint1.x > temppoint2.x) {
7026                                 weapons[i].rotation1 = 360 - weapons[i].rotation1;
7027                             }
7028                         }
7029                     }
7030                 }
7031                 if (weaponactive != k && weaponstuck != k) {
7032                     if (weapons[i].getType() == knife) {
7033                         weapons[i].smallrotation = -70;
7034                         weapons[i].smallrotation2 = 10;
7035                     }
7036                     if (weapons[i].getType() == sword) {
7037                         weapons[i].smallrotation = -100;
7038                         weapons[i].smallrotation2 = -8;
7039                     }
7040                     if (weapons[i].getType() == staff) {
7041                         weapons[i].smallrotation = -100;
7042                         weapons[i].smallrotation2 = -8;
7043                     }
7044                 }
7045                 if (weaponstuck == k) {
7046                     if (weaponstuckwhere == 0) {
7047                         weapons[i].smallrotation = 180;
7048                     } else {
7049                         weapons[i].smallrotation = 0;
7050                     }
7051                     weapons[i].smallrotation2 = 10;
7052                 }
7053             }
7054         }
7055     }
7056
7057     calcrot = 0;
7058     if (skeleton.free) {
7059         calcrot = 1;
7060     }
7061     if (Animation::animations[animTarget].attack || isRun() || animTarget == staggerbackhardanim || isFlip() || animTarget == climbanim || animTarget == sneakanim || animTarget == rollanim || animTarget == walkanim || animTarget == backhandspringanim || isWallJump()) {
7062         calcrot = 1;
7063     }
7064     if (animCurrent != animTarget) {
7065         calcrot = 1;
7066     }
7067     if (skeleton.free == 2) {
7068         calcrot = 0;
7069     }
7070
7071     return 0;
7072 }
7073
7074 /* FUNCTION?
7075  */
7076 int Person::SphereCheck(XYZ* p1, float radius, XYZ* p, XYZ* move, float* rotate, Model* model)
7077 {
7078     static float distance;
7079     static float olddistance;
7080     static int intersecting;
7081     static int firstintersecting;
7082     static XYZ point;
7083     static XYZ oldp1;
7084     static XYZ start, end;
7085     static float slopethreshold = -.4;
7086
7087     firstintersecting = -1;
7088
7089     oldp1 = *p1;
7090     *p1 = *p1 - *move;
7091     if (distsq(p1, &model->boundingspherecenter) > radius * radius + model->boundingsphereradius * model->boundingsphereradius) {
7092         return -1;
7093     }
7094     if (*rotate) {
7095         *p1 = DoRotation(*p1, 0, -*rotate, 0);
7096     }
7097     for (int i = 0; i < 4; i++) {
7098         for (unsigned int j = 0; j < model->Triangles.size(); j++) {
7099             if (model->Triangles[j].facenormal.y <= slopethreshold) {
7100                 intersecting = 0;
7101                 distance = abs((model->Triangles[j].facenormal.x * p1->x) + (model->Triangles[j].facenormal.y * p1->y) + (model->Triangles[j].facenormal.z * p1->z) - ((model->Triangles[j].facenormal.x * model->vertex[model->Triangles[j].vertex[0]].x) + (model->Triangles[j].facenormal.y * model->vertex[model->Triangles[j].vertex[0]].y) + (model->Triangles[j].facenormal.z * model->vertex[model->Triangles[j].vertex[0]].z)));
7102                 if (distance < radius) {
7103                     point = *p1 - model->Triangles[j].facenormal * distance;
7104                     if (PointInTriangle(&point, model->Triangles[j].facenormal, &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]])) {
7105                         intersecting = 1;
7106                     }
7107                     if (!intersecting) {
7108                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
7109                                                                 &model->vertex[model->Triangles[j].vertex[1]],
7110                                                                 p1, &radius);
7111                     }
7112                     if (!intersecting) {
7113                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
7114                                                                 &model->vertex[model->Triangles[j].vertex[2]],
7115                                                                 p1, &radius);
7116                     }
7117                     if (!intersecting) {
7118                         intersecting = sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
7119                                                                 &model->vertex[model->Triangles[j].vertex[2]],
7120                                                                 p1, &radius);
7121                     }
7122                     end = *p1 - point;
7123                     if (dotproduct(&model->Triangles[j].facenormal, &end) > 0 && intersecting) {
7124                         start = *p1;
7125                         end = *p1;
7126                         end.y -= radius;
7127                         if (LineFacetd(&start, &end, &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]], &model->Triangles[j].facenormal, &point)) {
7128                             p1->y = point.y + radius;
7129                             if ((animTarget == jumpdownanim || isFlip())) {
7130                                 if (isFlip() && (frameTarget < 5 || targetFrame().label == 7 || targetFrame().label == 4)) {
7131                                     RagDoll(0);
7132                                 }
7133
7134                                 if (animTarget == jumpupanim) {
7135                                     jumppower = -4;
7136                                     animTarget = getIdle();
7137                                 }
7138                                 target = 0;
7139                                 frameTarget = 0;
7140                                 onterrain = 1;
7141
7142                                 if (id == 0) {
7143                                     pause_sound(whooshsound);
7144                                     OPENAL_SetVolume(channels[whooshsound], 0);
7145                                 }
7146
7147                                 if ((animTarget == jumpdownanim || isFlip()) && !wasLanding() && !wasLandhard()) {
7148                                     if (isFlip()) {
7149                                         jumppower = -4;
7150                                     }
7151                                     animTarget = getLanding();
7152                                     emit_sound_at(landsound, coords, 128.);
7153
7154                                     if (id == 0) {
7155                                         addEnvSound(coords);
7156                                     }
7157                                 }
7158                             }
7159                         }
7160                     }
7161                 }
7162                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
7163                     olddistance = distance;
7164                     firstintersecting = j;
7165                     *p = point;
7166                 }
7167             }
7168         }
7169         for (unsigned int j = 0; j < model->Triangles.size(); j++) {
7170             if (model->Triangles[j].facenormal.y > slopethreshold) {
7171                 intersecting = 0;
7172                 start = *p1;
7173                 start.y -= radius / 4;
7174                 XYZ& v0 = model->vertex[model->Triangles[j].vertex[0]];
7175                 XYZ& v1 = model->vertex[model->Triangles[j].vertex[1]];
7176                 XYZ& v2 = model->vertex[model->Triangles[j].vertex[2]];
7177                 distance = abs((model->Triangles[j].facenormal.x * start.x) + (model->Triangles[j].facenormal.y * start.y) + (model->Triangles[j].facenormal.z * start.z) - ((model->Triangles[j].facenormal.x * v0.x) + (model->Triangles[j].facenormal.y * v0.y) + (model->Triangles[j].facenormal.z * v0.z)));
7178                 if (distance < radius * .5) {
7179                     point = start - model->Triangles[j].facenormal * distance;
7180                     if (PointInTriangle(&point, model->Triangles[j].facenormal, &v0, &v1, &v2)) {
7181                         intersecting = 1;
7182                     }
7183                     if (!intersecting) {
7184                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, p1->x, p1->y, p1->z, radius / 2);
7185                     }
7186                     if (!intersecting) {
7187                         intersecting = sphere_line_intersection(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
7188                     }
7189                     if (!intersecting) {
7190                         intersecting = sphere_line_intersection(v0.x, v0.y, v0.z, v2.x, v2.y, v2.z, p1->x, p1->y, p1->z, radius / 2);
7191                     }
7192                     end = *p1 - point;
7193                     if (dotproduct(&model->Triangles[j].facenormal, &end) > 0 && intersecting) {
7194                         if ((animTarget == jumpdownanim || animTarget == jumpupanim || isFlip())) {
7195                             start = velocity;
7196                             velocity -= DoRotation(model->Triangles[j].facenormal, 0, *rotate, 0) * findLength(&velocity) * abs(normaldotproduct(velocity, DoRotation(model->Triangles[j].facenormal, 0, *rotate, 0))); //(distance-radius*.5)/multiplier;
7197                             if (findLengthfast(&start) < findLengthfast(&velocity)) {
7198                                 velocity = start;
7199                             }
7200                         }
7201                         *p1 += model->Triangles[j].facenormal * (distance - radius * .5);
7202                     }
7203                 }
7204                 if ((distance < olddistance || firstintersecting == -1) && intersecting) {
7205                     olddistance = distance;
7206                     firstintersecting = j;
7207                     *p = point;
7208                 }
7209             }
7210         }
7211     }
7212     if (*rotate) {
7213         *p = DoRotation(*p, 0, *rotate, 0);
7214     }
7215     *p = *p + *move;
7216     if (*rotate) {
7217         *p1 = DoRotation(*p1, 0, *rotate, 0);
7218     }
7219     *p1 += *move;
7220     return firstintersecting;
7221 }
7222
7223 int findPathDist(int start, int end)
7224 {
7225     int connected;
7226     int closest;
7227
7228     unsigned int smallestcount = 1000;
7229     for (char i = 0; i < 50; i++) {
7230         unsigned int count = 0;
7231         int last = start;
7232         int last2 = -1;
7233         int last3 = -1;
7234         int last4 = -1;
7235         while (last != end && count < 30) {
7236             closest = -1;
7237             for (int j = 0; j < Game::numpathpoints; j++) {
7238                 if (j != last && j != last2 && j != last3 && j != last4) {
7239                     connected = 0;
7240                     if (Game::numpathpointconnect[j]) {
7241                         for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7242                             if (Game::pathpointconnect[j][k] == last) {
7243                                 connected = 1;
7244                             }
7245                         }
7246                     }
7247                     if (!connected) {
7248                         if (Game::numpathpointconnect[last]) {
7249                             for (int k = 0; k < Game::numpathpointconnect[last]; k++) {
7250                                 if (Game::pathpointconnect[last][k] == j) {
7251                                     connected = 1;
7252                                 }
7253                             }
7254                         }
7255                     }
7256                     if (connected) {
7257                         if (closest == -1 || Random() % 2 == 0) {
7258                             closest = j;
7259                         }
7260                     }
7261                 }
7262             }
7263             last4 = last3;
7264             last3 = last2;
7265             last2 = last;
7266             last = closest;
7267             count++;
7268         }
7269         if (count < smallestcount) {
7270             smallestcount = count;
7271         }
7272     }
7273     return smallestcount;
7274 }
7275
7276 void Person::takeWeapon(int weaponId)
7277 {
7278     weaponactive = 0;
7279     weapons[weaponId].owner = id;
7280     if (num_weapons > 0) {
7281         weaponids[num_weapons] = weaponids[0];
7282     }
7283     num_weapons++;
7284     weaponids[0] = weaponId;
7285 }
7286
7287 void Person::addClothes()
7288 {
7289     if (numclothes > 0) {
7290         for (int i = 0; i < numclothes; i++) {
7291             addClothes(i);
7292         }
7293         DoMipmaps();
7294     }
7295 }
7296
7297 bool Person::addClothes(const int& clothesId)
7298 {
7299     LOGFUNC;
7300     const std::string fileName = clothes[clothesId];
7301
7302     GLubyte* array = &skeleton.skinText[0];
7303
7304     //Load Image
7305     ImageRec texture;
7306     bool opened = load_image(Folders::getResourcePath(fileName).c_str(), texture);
7307
7308     float alphanum;
7309     //Is it valid?
7310     if (opened) {
7311         float tintr = clothestintr[clothesId];
7312         float tintg = clothestintg[clothesId];
7313         float tintb = clothestintb[clothesId];
7314
7315         if (tintr > 1) {
7316             tintr = 1;
7317         }
7318         if (tintg > 1) {
7319             tintg = 1;
7320         }
7321         if (tintb > 1) {
7322             tintb = 1;
7323         }
7324
7325         if (tintr < 0) {
7326             tintr = 0;
7327         }
7328         if (tintg < 0) {
7329             tintg = 0;
7330         }
7331         if (tintb < 0) {
7332             tintb = 0;
7333         }
7334
7335         int bytesPerPixel = texture.bpp / 8;
7336
7337         int tempnum = 0;
7338         alphanum = 255;
7339         for (int i = 0; i < (int)(texture.sizeY * texture.sizeX * bytesPerPixel); i++) {
7340             if (bytesPerPixel == 3) {
7341                 alphanum = 255;
7342             } else if ((i + 1) % 4 == 0) {
7343                 alphanum = texture.data[i];
7344             }
7345             if ((i + 1) % 4 || bytesPerPixel == 3) {
7346                 if ((i % 4) == 0) {
7347                     texture.data[i] *= tintr;
7348                 }
7349                 if ((i % 4) == 1) {
7350                     texture.data[i] *= tintg;
7351                 }
7352                 if ((i % 4) == 2) {
7353                     texture.data[i] *= tintb;
7354                 }
7355                 array[tempnum] = (float)array[tempnum] * (1 - alphanum / 255) + (float)texture.data[i] * (alphanum / 255);
7356                 tempnum++;
7357             }
7358         }
7359         return 1;
7360     } else {
7361         return 0;
7362     }
7363 }
7364
7365 void Person::doAI()
7366 {
7367     if (aitype != playercontrolled && !Dialog::inDialog()) {
7368         jumpclimb = 0;
7369         //disable movement in editor
7370         if (Game::editorenabled) {
7371             stunned = 1;
7372         }
7373
7374         pause = 0;
7375         if (distsqflat(&Person::players[0]->coords, &coords) < 30 &&
7376             Person::players[0]->coords.y > coords.y + 2 &&
7377             !Person::players[0]->onterrain) {
7378             pause = 1;
7379         }
7380
7381         //pathfinding
7382         if (aitype == pathfindtype) {
7383             if (finalpathfindpoint == -1) {
7384                 float closestdistance;
7385                 float tempdist = 0.0f;
7386                 int closest;
7387                 XYZ colpoint;
7388                 closest = -1;
7389                 closestdistance = -1;
7390                 for (int j = 0; j < Game::numpathpoints; j++) {
7391                     if (closest == -1 || distsq(&finalfinaltarget, &Game::pathpoint[j]) < closestdistance) {
7392                         closestdistance = distsq(&finalfinaltarget, &Game::pathpoint[j]);
7393                         closest = j;
7394                         finaltarget = Game::pathpoint[j];
7395                     }
7396                 }
7397                 finalpathfindpoint = closest;
7398                 for (int j = 0; j < Game::numpathpoints; j++) {
7399                     for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7400                         DistancePointLine(&finalfinaltarget, &Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]], &tempdist, &colpoint);
7401                         if (sq(tempdist) < closestdistance) {
7402                             if (findDistance(&colpoint, &Game::pathpoint[j]) + findDistance(&colpoint, &Game::pathpoint[Game::pathpointconnect[j][k]]) <
7403                                 findDistance(&Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]]) + .1) {
7404                                 closestdistance = sq(tempdist);
7405                                 closest = j;
7406                                 finaltarget = colpoint;
7407                             }
7408                         }
7409                     }
7410                 }
7411                 finalpathfindpoint = closest;
7412             }
7413             if (targetpathfindpoint == -1) {
7414                 float closestdistance;
7415                 float tempdist = 0.0f;
7416                 int closest;
7417                 XYZ colpoint;
7418                 closest = -1;
7419                 closestdistance = -1;
7420                 if (lastpathfindpoint == -1) {
7421                     for (int j = 0; j < Game::numpathpoints; j++) {
7422                         if (j != lastpathfindpoint) {
7423                             if (closest == -1 || (distsq(&coords, &Game::pathpoint[j]) < closestdistance)) {
7424                                 closestdistance = distsq(&coords, &Game::pathpoint[j]);
7425                                 closest = j;
7426                             }
7427                         }
7428                     }
7429                     targetpathfindpoint = closest;
7430                     for (int j = 0; j < Game::numpathpoints; j++) {
7431                         if (j != lastpathfindpoint) {
7432                             for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7433                                 DistancePointLine(&coords, &Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]], &tempdist, &colpoint);
7434                                 if (sq(tempdist) < closestdistance) {
7435                                     if (findDistance(&colpoint, &Game::pathpoint[j]) + findDistance(&colpoint, &Game::pathpoint[Game::pathpointconnect[j][k]]) <
7436                                         findDistance(&Game::pathpoint[j], &Game::pathpoint[Game::pathpointconnect[j][k]]) + .1) {
7437                                         closestdistance = sq(tempdist);
7438                                         closest = j;
7439                                     }
7440                                 }
7441                             }
7442                         }
7443                     }
7444                     targetpathfindpoint = closest;
7445                 } else {
7446                     for (int j = 0; j < Game::numpathpoints; j++) {
7447                         if (j != lastpathfindpoint &&
7448                             j != lastpathfindpoint2 &&
7449                             j != lastpathfindpoint3 &&
7450                             j != lastpathfindpoint4) {
7451                             bool connected = 0;
7452                             if (Game::numpathpointconnect[j]) {
7453                                 for (int k = 0; k < Game::numpathpointconnect[j]; k++) {
7454                                     if (Game::pathpointconnect[j][k] == lastpathfindpoint) {
7455                                         connected = 1;
7456                                     }
7457                                 }
7458                             }
7459                             if (!connected) {
7460                                 if (Game::numpathpointconnect[lastpathfindpoint]) {
7461                                     for (int k = 0; k < Game::numpathpointconnect[lastpathfindpoint]; k++) {
7462                                         if (Game::pathpointconnect[lastpathfindpoint][k] == j) {
7463                                             connected = 1;
7464                                         }
7465                                     }
7466                                 }
7467                             }
7468                             if (connected) {
7469                                 tempdist = findPathDist(j, finalpathfindpoint);
7470                                 if (closest == -1 || tempdist < closestdistance) {
7471                                     closestdistance = tempdist;
7472                                     closest = j;
7473                                 }
7474                             }
7475                         }
7476                     }
7477                     targetpathfindpoint = closest;
7478                 }
7479             }
7480             losupdatedelay -= multiplier;
7481
7482             targetyaw = roughDirectionTo(coords, Game::pathpoint[targetpathfindpoint]);
7483             lookyaw = targetyaw;
7484
7485             //reached target point
7486             if (distsqflat(&coords, &Game::pathpoint[targetpathfindpoint]) < .6) {
7487                 lastpathfindpoint4 = lastpathfindpoint3;
7488                 lastpathfindpoint3 = lastpathfindpoint2;
7489                 lastpathfindpoint2 = lastpathfindpoint;
7490                 lastpathfindpoint = targetpathfindpoint;
7491                 if (lastpathfindpoint2 == -1) {
7492                     lastpathfindpoint2 = lastpathfindpoint;
7493                 }
7494                 if (lastpathfindpoint3 == -1) {
7495                     lastpathfindpoint3 = lastpathfindpoint2;
7496                 }
7497                 if (lastpathfindpoint4 == -1) {
7498                     lastpathfindpoint4 = lastpathfindpoint3;
7499                 }
7500                 targetpathfindpoint = -1;
7501             }
7502             if (distsqflat(&coords, &finalfinaltarget) <
7503                     distsqflat(&coords, &finaltarget) ||
7504                 distsqflat(&coords, &finaltarget) < .6 * sq(scale * 5) ||
7505                 lastpathfindpoint == finalpathfindpoint) {
7506                 aitype = passivetype;
7507             }
7508
7509             forwardkeydown = 1;
7510             leftkeydown = 0;
7511             backkeydown = 0;
7512             rightkeydown = 0;
7513             crouchkeydown = 0;
7514             attackkeydown = 0;
7515             throwkeydown = 0;
7516
7517             if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7518                 targetyaw += 90 * (whichdirection * 2 - 1);
7519             }
7520
7521             if (collided < 1 || animTarget != jumpupanim) {
7522                 jumpkeydown = 0;
7523             }
7524             if ((collided > .8 && jumppower >= 5)) {
7525                 jumpkeydown = 1;
7526             }
7527
7528             if ((!Tutorial::active || cananger) &&
7529                 hostile &&
7530                 !Person::players[0]->dead &&
7531                 distsq(&coords, &Person::players[0]->coords) < 400 &&
7532                 occluded < 25) {
7533                 if (distsq(&coords, &Person::players[0]->coords) < 12 &&
7534                     Animation::animations[Person::players[0]->animTarget].height != lowheight &&
7535                     !Game::editorenabled &&
7536                     (Person::players[0]->coords.y < coords.y + 5 || Person::players[0]->onterrain)) {
7537                     aitype = attacktypecutoff;
7538                 }
7539                 if (distsq(&coords, &Person::players[0]->coords) < 30 &&
7540                     Animation::animations[Person::players[0]->animTarget].height == highheight &&
7541                     !Game::editorenabled) {
7542                     aitype = attacktypecutoff;
7543                 }
7544
7545                 if (losupdatedelay < 0 && !Game::editorenabled && occluded < 2) {
7546                     losupdatedelay = .2;
7547                     for (unsigned j = 0; j < Person::players.size(); j++) {
7548                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
7549                             if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0) {
7550                                 if (distsq(&coords, &Person::players[j]->coords) < 400) {
7551                                     if (normaldotproduct(facing, Person::players[j]->coords - coords) > 0) {
7552                                         if (Person::players[j]->coords.y < coords.y + 5 || Person::players[j]->onterrain) {
7553                                             if (!Person::players[j]->isWallJump() && -1 == Object::checkcollide(DoRotation(jointPos(head), 0, yaw, 0) * scale + coords, DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0) * Person::players[j]->scale + Person::players[j]->coords) ||
7554                                                 (Person::players[j]->animTarget == hanganim &&
7555                                                  normaldotproduct(Person::players[j]->facing, coords - Person::players[j]->coords) < 0)) {
7556                                                 aitype = searchtype;
7557                                                 lastchecktime = 12;
7558                                                 lastseen = Person::players[j]->coords;
7559                                                 lastseentime = 12;
7560                                             }
7561                                         }
7562                                     }
7563                                 }
7564                             }
7565                         }
7566                     }
7567                 }
7568             }
7569             if (aitype == attacktypecutoff && Game::musictype != 2) {
7570                 if (creature != wolftype) {
7571                     stunned = .6;
7572                     surprised = .6;
7573                 }
7574             }
7575         }
7576
7577         if (aitype != passivetype && Game::leveltime > .5) {
7578             howactive = typeactive;
7579         }
7580
7581         if (aitype == passivetype) {
7582             aiupdatedelay -= multiplier;
7583             losupdatedelay -= multiplier;
7584             lastseentime += multiplier;
7585             pausetime -= multiplier;
7586             if (lastseentime > 1) {
7587                 lastseentime = 1;
7588             }
7589
7590             if (aiupdatedelay < 0) {
7591                 if (numwaypoints > 1 && howactive == typeactive && pausetime <= 0) {
7592                     targetyaw = roughDirectionTo(coords, waypoints[waypoint]);
7593                     lookyaw = targetyaw;
7594                     aiupdatedelay = .05;
7595
7596                     if (distsqflat(&coords, &waypoints[waypoint]) < 1) {
7597                         if (waypointtype[waypoint] == wppause) {
7598                             pausetime = 4;
7599                         }
7600                         waypoint++;
7601                         if (waypoint > numwaypoints - 1) {
7602                             waypoint = 0;
7603                         }
7604                     }
7605                 }
7606
7607                 if (numwaypoints > 1 && howactive == typeactive && pausetime <= 0) {
7608                     forwardkeydown = 1;
7609                 } else {
7610                     forwardkeydown = 0;
7611                 }
7612                 leftkeydown = 0;
7613                 backkeydown = 0;
7614                 rightkeydown = 0;
7615                 crouchkeydown = 0;
7616                 attackkeydown = 0;
7617                 throwkeydown = 0;
7618
7619                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7620                     if (!avoidsomething) {
7621                         targetyaw += 90 * (whichdirection * 2 - 1);
7622                     } else {
7623                         XYZ leftpos, rightpos;
7624                         float leftdist, rightdist;
7625                         leftpos = coords + DoRotation(facing, 0, 90, 0);
7626                         rightpos = coords - DoRotation(facing, 0, 90, 0);
7627                         leftdist = distsq(&leftpos, &avoidwhere);
7628                         rightdist = distsq(&rightpos, &avoidwhere);
7629                         if (leftdist < rightdist) {
7630                             targetyaw += 90;
7631                         } else {
7632                             targetyaw -= 90;
7633                         }
7634                     }
7635                 }
7636             }
7637             if (collided < 1 || animTarget != jumpupanim) {
7638                 jumpkeydown = 0;
7639             }
7640             if ((collided > .8 && jumppower >= 5)) {
7641                 jumpkeydown = 1;
7642             }
7643
7644             //hearing sounds
7645             if (!Game::editorenabled) {
7646                 if (howactive <= typesleeping) {
7647                     if (numenvsounds > 0 && (!Tutorial::active || cananger) && hostile) {
7648                         for (int j = 0; j < numenvsounds; j++) {
7649                             float vol = howactive == typesleeping ? envsoundvol[j] - 14 : envsoundvol[j];
7650                             if (vol > 0 && distsq(&coords, &envsound[j]) < 2 * (vol + vol * (creature == rabbittype) * 3)) {
7651                                 aitype = attacktypecutoff;
7652                             }
7653                         }
7654                     }
7655                 }
7656
7657                 if (aitype != passivetype) {
7658                     if (howactive == typesleeping) {
7659                         setTargetAnimation(getupfromfrontanim);
7660                     }
7661                     howactive = typeactive;
7662                 }
7663             }
7664
7665             if (howactive < typesleeping &&
7666                 ((!Tutorial::active || cananger) && hostile) &&
7667                 !Person::players[0]->dead &&
7668                 distsq(&coords, &Person::players[0]->coords) < 400 &&
7669                 occluded < 25) {
7670                 if (distsq(&coords, &Person::players[0]->coords) < 12 &&
7671                     Animation::animations[Person::players[0]->animTarget].height != lowheight && !Game::editorenabled) {
7672                     aitype = attacktypecutoff;
7673                 }
7674                 if (distsq(&coords, &Person::players[0]->coords) < 30 &&
7675                     Animation::animations[Person::players[0]->animTarget].height == highheight && !Game::editorenabled) {
7676                     aitype = attacktypecutoff;
7677                 }
7678
7679                 //wolf smell
7680                 if (creature == wolftype) {
7681                     XYZ windsmell;
7682                     for (unsigned j = 0; j < Person::players.size(); j++) {
7683                         if (j == 0 || (Person::players[j]->dead && Person::players[j]->bloodloss > 0)) {
7684                             float smelldistance = 50;
7685                             if (j == 0 && Person::players[j]->num_weapons > 0) {
7686                                 if (weapons[Person::players[j]->weaponids[0]].bloody) {
7687                                     smelldistance = 100;
7688                                 }
7689                                 if (Person::players[j]->num_weapons == 2) {
7690                                     if (weapons[Person::players[j]->weaponids[1]].bloody) {
7691                                         smelldistance = 100;
7692                                     }
7693                                 }
7694                             }
7695                             if (j != 0) {
7696                                 smelldistance = 100;
7697                             }
7698                             windsmell = windvector;
7699                             Normalise(&windsmell);
7700                             windsmell = windsmell * 2 + Person::players[j]->coords;
7701                             if (distsq(&coords, &windsmell) < smelldistance && !Game::editorenabled) {
7702                                 aitype = attacktypecutoff;
7703                             }
7704                         }
7705                     }
7706                 }
7707
7708                 if (howactive < typesleeping && losupdatedelay < 0 && !Game::editorenabled && occluded < 2) {
7709                     losupdatedelay = .2;
7710                     for (unsigned j = 0; j < Person::players.size(); j++) {
7711                         if (j == 0 || Person::players[j]->skeleton.free || Person::players[j]->aitype != passivetype) {
7712                             if (abs(Random() % 2) || Animation::animations[Person::players[j]->animTarget].height != lowheight || j != 0) {
7713                                 if (distsq(&coords, &Person::players[j]->coords) < 400) {
7714                                     if (normaldotproduct(facing, Person::players[j]->coords - coords) > 0) {
7715                                         if ((-1 == Object::checkcollide(
7716                                                        DoRotation(jointPos(head), 0, yaw, 0) *
7717                                                                scale +
7718                                                            coords,
7719                                                        DoRotation(Person::players[j]->jointPos(head), 0, Person::players[j]->yaw, 0) *
7720                                                                Person::players[j]->scale +
7721                                                            Person::players[j]->coords) &&
7722                                              !Person::players[j]->isWallJump()) ||
7723                                             (Person::players[j]->animTarget == hanganim &&
7724                                              normaldotproduct(Person::players[j]->facing, coords - Person::players[j]->coords) < 0)) {
7725                                             lastseentime -= .2;
7726                                             if (j == 0 && Animation::animations[Person::players[j]->animTarget].height == lowheight) {
7727                                                 lastseentime -= .4;
7728                                             } else {
7729                                                 lastseentime -= .6;
7730                                             }
7731                                         }
7732                                     }
7733                                 }
7734                             }
7735                             if (lastseentime <= 0) {
7736                                 aitype = searchtype;
7737                                 lastchecktime = 12;
7738                                 lastseen = Person::players[j]->coords;
7739                                 lastseentime = 12;
7740                             }
7741                         }
7742                     }
7743                 }
7744             }
7745             //alerted surprise
7746             if (aitype == attacktypecutoff && Game::musictype != 2) {
7747                 if (creature != wolftype) {
7748                     stunned = .6;
7749                     surprised = .6;
7750                 }
7751                 if (creature == wolftype) {
7752                     stunned = .47;
7753                     surprised = .47;
7754                 }
7755                 numseen++;
7756             }
7757         }
7758
7759         //search for player
7760         int j;
7761         if (aitype == searchtype) {
7762             aiupdatedelay -= multiplier;
7763             losupdatedelay -= multiplier;
7764             if (!pause) {
7765                 lastseentime -= multiplier;
7766             }
7767             lastchecktime -= multiplier;
7768
7769             if (isRun() && !onground) {
7770                 if (coords.y > terrain.getHeight(coords.x, coords.z) + 10) {
7771                     XYZ test2 = coords + facing;
7772                     test2.y += 5;
7773                     XYZ test = coords + facing;
7774                     test.y -= 10;
7775                     j = Object::checkcollide(test2, test, laststanding);
7776                     if (j == -1) {
7777                         j = Object::checkcollide(test2, test);
7778                     }
7779                     if (j == -1) {
7780                         velocity = 0;
7781                         setTargetAnimation(getStop());
7782                         targetyaw += 180;
7783                         stunned = .5;
7784                         //aitype=passivetype;
7785                         aitype = pathfindtype;
7786                         finalfinaltarget = waypoints[waypoint];
7787                         finalpathfindpoint = -1;
7788                         targetpathfindpoint = -1;
7789                         lastpathfindpoint = -1;
7790                         lastpathfindpoint2 = -1;
7791                         lastpathfindpoint3 = -1;
7792                         lastpathfindpoint4 = -1;
7793                     } else {
7794                         laststanding = j;
7795                     }
7796                 }
7797             }
7798             //check out last seen location
7799             if (aiupdatedelay < 0) {
7800                 targetyaw = roughDirectionTo(coords, lastseen);
7801                 lookyaw = targetyaw;
7802                 aiupdatedelay = .05;
7803                 forwardkeydown = 1;
7804
7805                 if (distsqflat(&coords, &lastseen) < 1 * sq(scale * 5) || lastchecktime < 0) {
7806                     forwardkeydown = 0;
7807                     aiupdatedelay = 1;
7808                     lastseen.x += (float(Random() % 100) - 50) / 25;
7809                     lastseen.z += (float(Random() % 100) - 50) / 25;
7810                     lastchecktime = 3;
7811                 }
7812
7813                 leftkeydown = 0;
7814                 backkeydown = 0;
7815                 rightkeydown = 0;
7816                 crouchkeydown = 0;
7817                 attackkeydown = 0;
7818                 throwkeydown = 0;
7819
7820                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7821                     if (!avoidsomething) {
7822                         targetyaw += 90 * (whichdirection * 2 - 1);
7823                     } else {
7824                         XYZ leftpos, rightpos;
7825                         float leftdist, rightdist;
7826                         leftpos = coords + DoRotation(facing, 0, 90, 0);
7827                         rightpos = coords - DoRotation(facing, 0, 90, 0);
7828                         leftdist = distsq(&leftpos, &avoidwhere);
7829                         rightdist = distsq(&rightpos, &avoidwhere);
7830                         if (leftdist < rightdist) {
7831                             targetyaw += 90;
7832                         } else {
7833                             targetyaw -= 90;
7834                         }
7835                     }
7836                 }
7837             }
7838             if (collided < 1 || animTarget != jumpupanim) {
7839                 jumpkeydown = 0;
7840             }
7841             if ((collided > .8 && jumppower >= 5)) {
7842                 jumpkeydown = 1;
7843             }
7844
7845             if (numenvsounds > 0 && ((!Tutorial::active || cananger) && hostile)) {
7846                 for (int k = 0; k < numenvsounds; k++) {
7847                     if (distsq(&coords, &envsound[k]) < 2 * (envsoundvol[k] + envsoundvol[k] * (creature == rabbittype) * 3)) {
7848                         aitype = attacktypecutoff;
7849                     }
7850                 }
7851             }
7852
7853             if (!Person::players[0]->dead &&
7854                 losupdatedelay < 0 &&
7855                 !Game::editorenabled &&
7856                 occluded < 2 &&
7857                 ((!Tutorial::active || cananger) && hostile)) {
7858                 losupdatedelay = .2;
7859                 if (distsq(&coords, &Person::players[0]->coords) < 4 && Animation::animations[animTarget].height != lowheight) {
7860                     aitype = attacktypecutoff;
7861                     lastseentime = 1;
7862                 }
7863                 if (abs(Random() % 2) || Animation::animations[animTarget].height != lowheight) {
7864                     //TODO: factor out canSeePlayer()
7865                     if (distsq(&coords, &Person::players[0]->coords) < 400) {
7866                         if (normaldotproduct(facing, Person::players[0]->coords - coords) > 0) {
7867                             if ((Object::checkcollide(
7868                                      DoRotation(jointPos(head), 0, yaw, 0) *
7869                                              scale +
7870                                          coords,
7871                                      DoRotation(Person::players[0]->jointPos(head), 0, Person::players[0]->yaw, 0) *
7872                                              Person::players[0]->scale +
7873                                          Person::players[0]->coords) == -1) ||
7874                                 (Person::players[0]->animTarget == hanganim && normaldotproduct(Person::players[0]->facing, coords - Person::players[0]->coords) < 0)) {
7875                                 /* //TODO: changed j to 0 on a whim, make sure this is correct
7876                                 (Person::players[j]->animTarget==hanganim&&normaldotproduct(
7877                                     Person::players[j]->facing,coords-Person::players[j]->coords)<0)
7878                                 */
7879                                 aitype = attacktypecutoff;
7880                                 lastseentime = 1;
7881                             }
7882                         }
7883                     }
7884                 }
7885             }
7886             //player escaped
7887             if (lastseentime < 0) {
7888                 //aitype=passivetype;
7889                 numescaped++;
7890                 aitype = pathfindtype;
7891                 finalfinaltarget = waypoints[waypoint];
7892                 finalpathfindpoint = -1;
7893                 targetpathfindpoint = -1;
7894                 lastpathfindpoint = -1;
7895                 lastpathfindpoint2 = -1;
7896                 lastpathfindpoint3 = -1;
7897                 lastpathfindpoint4 = -1;
7898             }
7899         }
7900
7901         if (aitype != gethelptype) {
7902             runninghowlong = 0;
7903         }
7904
7905         //get help from buddies
7906         if (aitype == gethelptype) {
7907             runninghowlong += multiplier;
7908             aiupdatedelay -= multiplier;
7909
7910             if (aiupdatedelay < 0 || ally == 0) {
7911                 aiupdatedelay = .2;
7912
7913                 //find closest ally
7914                 //TODO: factor out closest search somehow
7915                 if (!ally) {
7916                     int closest = -1;
7917                     float closestdist = -1;
7918                     for (unsigned k = 0; k < Person::players.size(); k++) {
7919                         if ((k != id) && (k != 0) && !Person::players[k]->dead &&
7920                             (Person::players[k]->howactive < typedead1) &&
7921                             !Person::players[k]->skeleton.free &&
7922                             (Person::players[k]->aitype == passivetype)) {
7923                             float distance = distsq(&coords, &Person::players[k]->coords);
7924                             if (closestdist == -1 || distance < closestdist) {
7925                                 closestdist = distance;
7926                                 closest = k;
7927                             }
7928                         }
7929                     }
7930                     if (closest != -1) {
7931                         ally = closest;
7932                     } else {
7933                         ally = 0;
7934                     }
7935                     lastseen = Person::players[0]->coords;
7936                     lastseentime = 12;
7937                 }
7938
7939                 lastchecktime = 12;
7940
7941                 XYZ facing = coords;
7942                 XYZ flatfacing = Person::players[ally]->coords;
7943                 facing.y += jointPos(head).y * scale;
7944                 flatfacing.y += Person::players[ally]->jointPos(head).y * Person::players[ally]->scale;
7945                 if (-1 != Object::checkcollide(facing, flatfacing)) {
7946                     lastseentime -= .1;
7947                 }
7948
7949                 //no available ally, run back to player
7950                 if (ally <= 0 ||
7951                     Person::players[ally]->skeleton.free ||
7952                     Person::players[ally]->aitype != passivetype ||
7953                     lastseentime <= 0) {
7954                     aitype = searchtype;
7955                     lastseentime = 12;
7956                 }
7957
7958                 //seek out ally
7959                 if (ally > 0) {
7960                     targetyaw = roughDirectionTo(coords, Person::players[ally]->coords);
7961                     lookyaw = targetyaw;
7962                     aiupdatedelay = .05;
7963                     forwardkeydown = 1;
7964
7965                     if (distsqflat(&coords, &Person::players[ally]->coords) < 3) {
7966                         aitype = searchtype;
7967                         lastseentime = 12;
7968                         Person::players[ally]->aitype = searchtype;
7969                         if (Person::players[ally]->lastseentime < lastseentime) {
7970                             Person::players[ally]->lastseen = lastseen;
7971                             Person::players[ally]->lastseentime = lastseentime;
7972                             Person::players[ally]->lastchecktime = lastchecktime;
7973                         }
7974                     }
7975
7976                     if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
7977                         if (!avoidsomething) {
7978                             targetyaw += 90 * (whichdirection * 2 - 1);
7979                         } else {
7980                             XYZ leftpos, rightpos;
7981                             float leftdist, rightdist;
7982                             leftpos = coords + DoRotation(facing, 0, 90, 0);
7983                             rightpos = coords - DoRotation(facing, 0, 90, 0);
7984                             leftdist = distsq(&leftpos, &avoidwhere);
7985                             rightdist = distsq(&rightpos, &avoidwhere);
7986                             if (leftdist < rightdist) {
7987                                 targetyaw += 90;
7988                             } else {
7989                                 targetyaw -= 90;
7990                             }
7991                         }
7992                     }
7993                 }
7994
7995                 leftkeydown = 0;
7996                 backkeydown = 0;
7997                 rightkeydown = 0;
7998                 crouchkeydown = 0;
7999                 attackkeydown = 0;
8000             }
8001             if (collided < 1 || animTarget != jumpupanim) {
8002                 jumpkeydown = 0;
8003             }
8004             if (collided > .8 && jumppower >= 5) {
8005                 jumpkeydown = 1;
8006             }
8007         }
8008
8009         //retreiving a weapon on the ground
8010         if (aitype == getweapontype) {
8011             aiupdatedelay -= multiplier;
8012             lastchecktime -= multiplier;
8013
8014             if (aiupdatedelay < 0) {
8015                 aiupdatedelay = .2;
8016
8017                 //ALLY IS WEPON
8018                 if (ally < 0) {
8019                     int closest = -1;
8020                     float closestdist = -1;
8021                     for (unsigned k = 0; k < weapons.size(); k++) {
8022                         if (weapons[k].owner == -1) {
8023                             float distance = distsq(&coords, &weapons[k].position);
8024                             if (closestdist == -1 || distance < closestdist) {
8025                                 closestdist = distance;
8026                                 closest = k;
8027                             }
8028                         }
8029                     }
8030                     if (closest != -1) {
8031                         ally = closest;
8032                     } else {
8033                         ally = -1;
8034                     }
8035                 }
8036
8037                 lastseentime = 12;
8038
8039                 if (!Person::players[0]->dead && ((!Tutorial::active || cananger) && hostile)) {
8040                     if (ally < 0 || weaponactive != -1 || lastchecktime <= 0) {
8041                         aitype = attacktypecutoff;
8042                         lastseentime = 1;
8043                     }
8044                 }
8045                 if (!Person::players[0]->dead) {
8046                     if (ally >= 0) {
8047                         if (weapons[ally].owner != -1 ||
8048                             distsq(&coords, &weapons[ally].position) > 16) {
8049                             aitype = attacktypecutoff;
8050                             lastseentime = 1;
8051                         }
8052                         //TODO: factor these out as moveToward()
8053                         targetyaw = roughDirectionTo(coords, weapons[ally].position);
8054                         lookyaw = targetyaw;
8055                         aiupdatedelay = .05;
8056                         forwardkeydown = 1;
8057
8058                         if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
8059                             if (!avoidsomething) {
8060                                 targetyaw += 90 * (whichdirection * 2 - 1);
8061                             } else {
8062                                 XYZ leftpos, rightpos;
8063                                 float leftdist, rightdist;
8064                                 leftpos = coords + DoRotation(facing, 0, 90, 0);
8065                                 rightpos = coords - DoRotation(facing, 0, 90, 0);
8066                                 leftdist = distsq(&leftpos, &avoidwhere);
8067                                 rightdist = distsq(&rightpos, &avoidwhere);
8068                                 if (leftdist < rightdist) {
8069                                     targetyaw += 90;
8070                                 } else {
8071                                     targetyaw -= 90;
8072                                 }
8073                             }
8074                         }
8075                     }
8076                 }
8077
8078                 leftkeydown = 0;
8079                 backkeydown = 0;
8080                 rightkeydown = 0;
8081                 attackkeydown = 0;
8082                 throwkeydown = 1;
8083                 crouchkeydown = 0;
8084                 if (animTarget != crouchremoveknifeanim &&
8085                     animTarget != removeknifeanim) {
8086                     throwtogglekeydown = 0;
8087                 }
8088                 drawkeydown = 0;
8089             }
8090             if (collided < 1 || animTarget != jumpupanim) {
8091                 jumpkeydown = 0;
8092             }
8093             if ((collided > .8 && jumppower >= 5)) {
8094                 jumpkeydown = 1;
8095             }
8096         }
8097
8098         if (aitype == attacktypecutoff) {
8099             aiupdatedelay -= multiplier;
8100             //dodge or reverse rabbit kicks, knife throws, flips
8101             if (damage < damagetolerance * 2 / 3) {
8102                 if ((Person::players[0]->animTarget == rabbitkickanim ||
8103                      Person::players[0]->animTarget == knifethrowanim ||
8104                      (Person::players[0]->isFlip() &&
8105                       normaldotproduct(Person::players[0]->facing, Person::players[0]->coords - coords) < 0)) &&
8106                     !Person::players[0]->skeleton.free &&
8107                     (aiupdatedelay < .1)) {
8108                     attackkeydown = 0;
8109                     if (isIdle()) {
8110                         crouchkeydown = 1;
8111                     }
8112                     if (Person::players[0]->animTarget != rabbitkickanim && Person::players[0]->weaponactive != -1) {
8113                         if (weapons[Person::players[0]->weaponids[0]].getType() == knife) {
8114                             if (isIdle() || isCrouch() || isRun() || isFlip()) {
8115                                 if (abs(Random() % 2) == 0) {
8116                                     setTargetAnimation(backhandspringanim);
8117                                 } else {
8118                                     setTargetAnimation(rollanim);
8119                                 }
8120                                 targetyaw += 90 * (abs(Random() % 2) * 2 - 1);
8121                                 wentforweapon = 0;
8122                             }
8123                             if (animTarget == jumpupanim || animTarget == jumpdownanim) {
8124                                 setTargetAnimation(flipanim);
8125                             }
8126                         }
8127                     }
8128                     forwardkeydown = 0;
8129                     aiupdatedelay = .02;
8130                 }
8131             }
8132             //get confused by flips
8133             if (Person::players[0]->isFlip() &&
8134                 !Person::players[0]->skeleton.free &&
8135                 Person::players[0]->animTarget != walljumprightkickanim &&
8136                 Person::players[0]->animTarget != walljumpleftkickanim) {
8137                 if (distsq(&Person::players[0]->coords, &coords) < 25) {
8138                     if ((1 - damage / damagetolerance) > .5) {
8139                         stunned = 1;
8140                     }
8141                 }
8142             }
8143             //go for weapon on the ground
8144             if (wentforweapon < 3) {
8145                 for (unsigned k = 0; k < weapons.size(); k++) {
8146                     if (creature != wolftype) {
8147                         if (num_weapons == 0 &&
8148                             weapons[k].owner == -1 &&
8149                             weapons[k].velocity.x == 0 &&
8150                             weapons[k].velocity.z == 0 &&
8151                             weapons[k].velocity.y == 0) {
8152                             if (distsq(&coords, &weapons[k].position) < 16) {
8153                                 wentforweapon++;
8154                                 lastchecktime = 6;
8155                                 aitype = getweapontype;
8156                                 ally = -1;
8157                             }
8158                         }
8159                     }
8160                 }
8161             }
8162             //dodge/reverse walljump kicks
8163             if (damage < damagetolerance / 2) {
8164                 if (Animation::animations[animTarget].height != highheight) {
8165                     if (damage < damagetolerance * .5 &&
8166                         ((Person::players[0]->animTarget == walljumprightkickanim ||
8167                           Person::players[0]->animTarget == walljumpleftkickanim) &&
8168                          ((aiupdatedelay < .15 &&
8169                            difficulty == 2) ||
8170                           (aiupdatedelay < .08 &&
8171                            difficulty != 2)))) {
8172                         crouchkeydown = 1;
8173                     }
8174                 }
8175             }
8176             //walked off a ledge (?)
8177             if (isRun() && !onground) {
8178                 if (coords.y > terrain.getHeight(coords.x, coords.z) + 10) {
8179                     XYZ test2 = coords + facing;
8180                     test2.y += 5;
8181                     XYZ test = coords + facing;
8182                     test.y -= 10;
8183                     j = Object::checkcollide(test2, test, laststanding);
8184                     if (j == -1) {
8185                         j = Object::checkcollide(test2, test);
8186                     }
8187                     if (j == -1) {
8188                         velocity = 0;
8189                         setTargetAnimation(getStop());
8190                         targetyaw += 180;
8191                         stunned = .5;
8192                         aitype = pathfindtype;
8193                         finalfinaltarget = waypoints[waypoint];
8194                         finalpathfindpoint = -1;
8195                         targetpathfindpoint = -1;
8196                         lastpathfindpoint = -1;
8197                         lastpathfindpoint2 = -1;
8198                         lastpathfindpoint3 = -1;
8199                         lastpathfindpoint4 = -1;
8200                     } else {
8201                         laststanding = j;
8202                     }
8203                 }
8204             }
8205             //lose sight of player in the air (?)
8206             if (Person::players[0]->coords.y > coords.y + 5 &&
8207                 Animation::animations[Person::players[0]->animTarget].height != highheight &&
8208                 !Person::players[0]->onterrain) {
8209                 aitype = pathfindtype;
8210                 finalfinaltarget = waypoints[waypoint];
8211                 finalpathfindpoint = -1;
8212                 targetpathfindpoint = -1;
8213                 lastpathfindpoint = -1;
8214                 lastpathfindpoint2 = -1;
8215                 lastpathfindpoint3 = -1;
8216                 lastpathfindpoint4 = -1;
8217             }
8218             //it's time to think (?)
8219             if (aiupdatedelay < 0 &&
8220                 !Animation::animations[animTarget].attack &&
8221                 animTarget != staggerbackhighanim &&
8222                 animTarget != staggerbackhardanim &&
8223                 animTarget != backhandspringanim &&
8224                 animTarget != dodgebackanim) {
8225                 //draw weapon
8226                 if (weaponactive == -1 && num_weapons > 0) {
8227                     drawkeydown = Random() % 2;
8228                 } else {
8229                     drawkeydown = 0;
8230                 }
8231                 rabbitkickenabled = Random() % 2;
8232                 //chase player
8233                 XYZ rotatetarget = Person::players[0]->coords + Person::players[0]->velocity;
8234                 XYZ targetpoint = Person::players[0]->coords;
8235                 float vellength = findLength(&velocity);
8236                 if (vellength != 0 &&
8237                     distsq(&Person::players[0]->coords, &coords) < distsq(&rotatetarget, &coords)) {
8238                     targetpoint += Person::players[0]->velocity *
8239                                    findDistance(&Person::players[0]->coords, &coords) / vellength;
8240                 }
8241                 targetyaw = roughDirectionTo(coords, targetpoint);
8242                 lookyaw = targetyaw;
8243                 aiupdatedelay = .2 + fabs((float)(Random() % 100) / 1000);
8244
8245                 if (distsq(&coords, &Person::players[0]->coords) > 5 && (Person::players[0]->weaponactive == -1 || weaponactive != -1)) {
8246                     forwardkeydown = 1;
8247                 } else if ((distsq(&coords, &Person::players[0]->coords) > 16 ||
8248                             distsq(&coords, &Person::players[0]->coords) < 9) &&
8249                            Person::players[0]->weaponactive != -1) {
8250                     forwardkeydown = 1;
8251                 } else if (Random() % 6 == 0 || (creature == wolftype && Random() % 3 == 0)) {
8252                     forwardkeydown = 1;
8253                 } else {
8254                     forwardkeydown = 0;
8255                 }
8256                 //chill out around the corpse
8257                 if (Person::players[0]->dead) {
8258                     forwardkeydown = 0;
8259                     if (Random() % 10 == 0) {
8260                         forwardkeydown = 1;
8261                     }
8262                     if (Random() % 100 == 0) {
8263                         aitype = pathfindtype;
8264                         finalfinaltarget = waypoints[waypoint];
8265                         finalpathfindpoint = -1;
8266                         targetpathfindpoint = -1;
8267                         lastpathfindpoint = -1;
8268                         lastpathfindpoint2 = -1;
8269                         lastpathfindpoint3 = -1;
8270                         lastpathfindpoint4 = -1;
8271                     }
8272                 }
8273                 leftkeydown = 0;
8274                 backkeydown = 0;
8275                 rightkeydown = 0;
8276                 crouchkeydown = 0;
8277                 throwkeydown = 0;
8278
8279                 if (avoidcollided > .8 && !jumpkeydown && collided < .8) {
8280                     targetyaw += 90 * (whichdirection * 2 - 1);
8281                 }
8282                 //attack!!!
8283                 if (Random() % 2 == 0 || weaponactive != -1 || creature == wolftype) {
8284                     attackkeydown = 1;
8285                 } else {
8286                     attackkeydown = 0;
8287                 }
8288                 if (isRun() && Random() % 6 && distsq(&coords, &Person::players[0]->coords) > 7) {
8289                     attackkeydown = 0;
8290                 }
8291
8292                 //TODO: wat
8293                 if (aitype != playercontrolled &&
8294                     (isIdle() ||
8295                      isCrouch() ||
8296                      isRun())) {
8297                     int target = -2;
8298                     for (unsigned j = 0; j < Person::players.size(); j++) {
8299                         if (j != id && !Person::players[j]->skeleton.free &&
8300                             Person::players[j]->hasvictim &&
8301                             (Tutorial::active && reversaltrain ||
8302                              Random() % 2 == 0 && difficulty == 2 ||
8303                              Random() % 4 == 0 && difficulty == 1 ||
8304                              Random() % 8 == 0 && difficulty == 0 ||
8305                              Person::players[j]->lastattack2 == Person::players[j]->animTarget &&
8306                                  Person::players[j]->lastattack3 == Person::players[j]->animTarget &&
8307                                  (Random() % 2 == 0 || difficulty == 2) ||
8308                              (isIdle() || isRun()) &&
8309                                  Person::players[j]->weaponactive != -1 ||
8310                              Person::players[j]->animTarget == swordslashanim &&
8311                                  weaponactive != -1 ||
8312                              Person::players[j]->animTarget == staffhitanim ||
8313                              Person::players[j]->animTarget == staffspinhitanim)) {
8314                             if (distsq(&Person::players[j]->coords, &Person::players[j]->victim->coords) < 4 &&
8315                                 Person::players[j]->victim == Person::players[id] &&
8316                                 (Person::players[j]->animTarget == sweepanim ||
8317                                  Person::players[j]->animTarget == spinkickanim ||
8318                                  Person::players[j]->animTarget == staffhitanim ||
8319                                  Person::players[j]->animTarget == staffspinhitanim ||
8320                                  Person::players[j]->animTarget == winduppunchanim ||
8321                                  Person::players[j]->animTarget == upunchanim ||
8322                                  Person::players[j]->animTarget == wolfslapanim ||
8323                                  Person::players[j]->animTarget == knifeslashstartanim ||
8324                                  Person::players[j]->animTarget == swordslashanim &&
8325                                      (distsq(&Person::players[j]->coords, &coords) < 2 ||
8326                                       weaponactive != -1))) {
8327                                 if (target >= 0) {
8328                                     target = -1;
8329                                 } else {
8330                                     target = j;
8331                                 }
8332                             }
8333                         }
8334                     }
8335                     if (target >= 0) {
8336                         Person::players[target]->Reverse();
8337                     }
8338                 }
8339
8340                 if (collided < 1) {
8341                     jumpkeydown = 0;
8342                 }
8343                 if (collided > .8 && jumppower >= 5 ||
8344                     distsq(&coords, &Person::players[0]->coords) > 400 &&
8345                         onterrain &&
8346                         creature == rabbittype) {
8347                     jumpkeydown = 1;
8348                 }
8349                 //TODO: why are we controlling the human?
8350                 if (normaldotproduct(facing, Person::players[0]->coords - coords) > 0) {
8351                     Person::players[0]->jumpkeydown = 0;
8352                 }
8353                 if (Person::players[0]->animTarget == jumpdownanim &&
8354                     distsq(&Person::players[0]->coords, &coords) < 40) {
8355                     crouchkeydown = 1;
8356                 }
8357                 if (jumpkeydown) {
8358                     attackkeydown = 0;
8359                 }
8360
8361                 if (Tutorial::active) {
8362                     if (!canattack) {
8363                         attackkeydown = 0;
8364                     }
8365                 }
8366
8367                 XYZ facing = coords;
8368                 XYZ flatfacing = Person::players[0]->coords;
8369                 facing.y += jointPos(head).y * scale;
8370                 flatfacing.y += Person::players[0]->jointPos(head).y * Person::players[0]->scale;
8371                 if (occluded >= 2) {
8372                     if (-1 != Object::checkcollide(facing, flatfacing)) {
8373                         if (!pause) {
8374                             lastseentime -= .2;
8375                         }
8376                         if (lastseentime <= 0 &&
8377                             (creature != wolftype ||
8378                              weaponstuck == -1)) {
8379                             aitype = searchtype;
8380                             lastchecktime = 12;
8381                             lastseen = Person::players[0]->coords;
8382                             lastseentime = 12;
8383                         }
8384                     } else {
8385                         lastseentime = 1;
8386                     }
8387                 }
8388             }
8389         }
8390         if (Animation::animations[Person::players[0]->animTarget].height == highheight &&
8391             (aitype == attacktypecutoff ||
8392              aitype == searchtype)) {
8393             if (Person::players[0]->coords.y > terrain.getHeight(Person::players[0]->coords.x, Person::players[0]->coords.z) + 10) {
8394                 XYZ test = Person::players[0]->coords;
8395                 test.y -= 40;
8396                 if (-1 == Object::checkcollide(Person::players[0]->coords, test)) {
8397                     stunned = 1;
8398                 }
8399             }
8400         }
8401         //stunned
8402         if (aitype == passivetype && !(numwaypoints > 1) ||
8403             stunned > 0 ||
8404             pause && damage > superpermanentdamage) {
8405             if (pause) {
8406                 lastseentime = 1;
8407             }
8408             targetyaw = yaw;
8409             forwardkeydown = 0;
8410             leftkeydown = 0;
8411             backkeydown = 0;
8412             rightkeydown = 0;
8413             jumpkeydown = 0;
8414             attackkeydown = 0;
8415             crouchkeydown = 0;
8416             throwkeydown = 0;
8417         }
8418
8419         XYZ facing;
8420         facing = 0;
8421         facing.z = -1;
8422
8423         XYZ flatfacing = DoRotation(facing, 0, yaw + 180, 0);
8424         facing = flatfacing;
8425
8426         if (aitype == attacktypecutoff) {
8427             targetheadyaw = 180 - roughDirectionTo(coords, Person::players[0]->coords);
8428             targetheadpitch = pitchTo(coords, Person::players[0]->coords);
8429         } else if (howactive >= typesleeping) {
8430             targetheadyaw = targetyaw;
8431             targetheadpitch = 0;
8432         } else {
8433             if (interestdelay <= 0) {
8434                 interestdelay = .7 + (float)(abs(Random() % 100)) / 100;
8435                 headtarget = coords;
8436                 headtarget.x += (float)(abs(Random() % 200) - 100) / 100;
8437                 headtarget.z += (float)(abs(Random() % 200) - 100) / 100;
8438                 headtarget.y += (float)(abs(Random() % 200) - 100) / 300;
8439                 headtarget += facing * 1.5;
8440             }
8441             targetheadyaw = 180 - roughDirectionTo(coords, headtarget);
8442             targetheadpitch = pitchTo(coords, headtarget);
8443         }
8444     }
8445 }