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