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