// Person simulation and visualization // Copyright (C) 2002 David Rosen // Copyright (C) 2021 Nguyễn Gia Phong // // This file is part of Black Shades. // // Black Shades is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published // by the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Black Shades is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Black Shades. If not, see . #include #include #include "Person.h" #include "config.h" #include "misc.h" extern float multiplier; extern unsigned int gSourceID[37]; extern Animation animation[30]; extern int thirdperson; extern bool visions; extern Camera camera; extern float rad2deg; extern Model gunmodels[10]; extern Model skeletonmodels[10]; extern Sprites sprites; extern float soundscalefactor; extern int slomo; extern struct Key keymap; extern Model skeletonmodels[10]; extern Costume costume[10]; HitStruct Person::BulletCollideWithPlayer(int who, XYZ start, XYZ end){ XYZ tempbulletloc[2]; XYZ collisionpoint; GLfloat M[16]; int collide; HitStruct hitstruct; hitstruct.collision=0; //Make bounding sphere XYZ average {}; for (auto& joint : skeleton.joints) average += joint.position; average /= max_joints; float distancemax = 0.0f; for (auto& joint : skeleton.joints) distancemax = std::max(distancemax, sqrlen(average - joint.position)); distancemax = sqrt(distancemax); //Collide with player if(skeleton.free<1){ start=start-playercoords; end=end-playercoords; if(playerrotation)start=rotate(start,0,-playerrotation,0); if(playerrotation)end=rotate(end,0,-playerrotation,0); } tempbulletloc[0]=start; tempbulletloc[1]=end; if (segCrossSphere(start, end, average, distancemax)) { for (auto& joint : skeleton.joints) { if (joint.hasparent && joint.visible) { tempbulletloc[0] = start; tempbulletloc[1] = end; glPushMatrix(); glLoadIdentity(); glScalef(1, 1 / joint.length, 1); glRotatef(joint.rotate2 - 90, 0, 0, 1); glRotatef(joint.rotate1 - 90, 0, 1, 0); glTranslatef(-(joint.position.x + joint.parent->position.x) / 2, -(joint.position.y + joint.parent->position.y) / 2, -(joint.position.z + joint.parent->position.z) / 2); glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z); glGetFloatv(GL_MODELVIEW_MATRIX,M); tempbulletloc[0].x=M[12]; tempbulletloc[0].y=M[13]; tempbulletloc[0].z=M[14]; glPopMatrix(); glPushMatrix(); glLoadIdentity(); glScalef(1, 1 / joint.length, 1); glRotatef(joint.rotate2 - 90, 0, 0, 1); glRotatef(joint.rotate1 - 90, 0, 1, 0); glTranslatef(-(joint.position.x + joint.parent->position.x) / 2, -(joint.position.y + joint.parent->position.y) / 2, -(joint.position.z + joint.parent->position.z) / 2); glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z); glGetFloatv(GL_MODELVIEW_MATRIX,M); tempbulletloc[1].x=M[12]; tempbulletloc[1].y=M[13]; tempbulletloc[1].z=M[14]; glPopMatrix(); collide = segCrossModel(tempbulletloc[0], tempbulletloc[1], skeletonmodels + joint.modelnum, &collisionpoint); if (collide > -1) { glPushMatrix(); glLoadIdentity(); glTranslatef((joint.position.x + joint.parent->position.x) / 2, (joint.position.y + joint.parent->position.y) / 2, (joint.position.z + joint.parent->position.z) / 2); glRotatef(90 - joint.rotate1, 0, 1, 0); glRotatef(90 - joint.rotate2, 0, 0, 1); glScalef(1, joint.length, 1); glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z); glGetFloatv(GL_MODELVIEW_MATRIX,M); collisionpoint.x=M[12]; collisionpoint.y=M[13]; collisionpoint.z=M[14]; glPopMatrix(); hitstruct.collision=1; hitstruct.hitlocation=collisionpoint; hitstruct.joint1 = &joint; hitstruct.joint2 = joint.parent; } } } for(int j=0;jposition.x+skeleton.muscles[j].parent2->position.x)/2), (-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2), (-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2)); glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z); glGetFloatv(GL_MODELVIEW_MATRIX,M); tempbulletloc[0].x=M[12]; tempbulletloc[0].y=M[13]; tempbulletloc[0].z=M[14]; glPopMatrix(); glPushMatrix(); glLoadIdentity(); glScalef(1,1/skeleton.muscles[j].length,1); glRotatef(skeleton.muscles[j].rotate3,0,1,0); glRotatef(skeleton.muscles[j].rotate2-90,0,0,1); glRotatef(skeleton.muscles[j].rotate1-90,0,1,0); glTranslatef( (-(skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2), (-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2), (-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2)); glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z); glGetFloatv(GL_MODELVIEW_MATRIX,M); tempbulletloc[1].x=M[12]; tempbulletloc[1].y=M[13]; tempbulletloc[1].z=M[14]; glPopMatrix(); collide = segCrossModel(tempbulletloc[0], tempbulletloc[1], skeletonmodels + skeleton.muscles[j].parent1->modelnum, &collisionpoint); if (collide > -1) { glPushMatrix(); glLoadIdentity(); glTranslatef( (skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2, (skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2, (skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2); glRotatef(-skeleton.muscles[j].rotate1+90,0,1,0); glRotatef(-skeleton.muscles[j].rotate2+90,0,0,1); glRotatef(-skeleton.muscles[j].rotate3,0,1,0); glScalef(1, len(skeleton.muscles[j].parent1->position - skeleton.muscles[j].parent2->position), 1); glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z); glGetFloatv(GL_MODELVIEW_MATRIX,M); collisionpoint.x=M[12]; collisionpoint.y=M[13]; collisionpoint.z=M[14]; glPopMatrix(); hitstruct.collision=1; hitstruct.hitlocation=collisionpoint; hitstruct.joint1=skeleton.muscles[j].parent1; hitstruct.joint2=skeleton.muscles[j].parent2; } } } } if(skeleton.free<1){ if(playerrotation)hitstruct.hitlocation=rotate(hitstruct.hitlocation,0,playerrotation,0); hitstruct.hitlocation=hitstruct.hitlocation+playercoords; } return hitstruct; } void Person::DoAnimations(int who) { if (target > 1 && !skeleton.free) { // Footstep sounds if (!slomo && !visions && (onground || abs(velocity.y) < 1) && (targetanimation == joganim || targetanimation == walkanim) && (targetframe == 0 || targetframe == 8) && who == 0) { auto soundsrc = playercoords - camera.position; playSound(gSourceID[footstepsound + randUint(5)], soundsrc.x, soundsrc.y, soundsrc.z); } if (targetanimation == zombieeatanim && targetframe == 3) { auto& joints = skeleton.joints; auto head_joint = joints[head]; auto soundsrc = (rotate(head_joint.position, 0, playerrotation, 0) + playercoords - camera.position) / soundscalefactor; playSound(gSourceID[munchsound], soundsrc.x, soundsrc.y, soundsrc.z); bleeding = 1; bleeddelay = 1; bjoint1 = &head_joint; bjoint2 = joints + neck; } currentanimation = targetanimation; targetframe = currentframe + (backwardsanim ? -1 : 1); if (targetframe >= animation[currentanimation].numframes) targetframe = 0; else if (targetframe < 0) targetframe = animation[currentanimation].numframes - 1; target = 0; if ((currentanimation == getupfrontanim || currentanimation == getupbackanim) && targetframe == 0) targetanimation = idleanim; if (targetanimation == diveanim && currentanimation == diveanim && targetframe == 0) { targetanimation = getupfrontanim; auto& joints = skeleton.joints; auto head_joint = joints[head]; auto soundsrc = (rotate(head_joint.position, 0, playerrotation, 0) + playercoords - camera.position) / soundscalefactor; ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z}; alSourcefv(gSourceID[bodywhacksound], AL_POSITION, gLoc); alSourcePlay(gSourceID[bodywhacksound]); } if (currentanimation == throwanim && targetframe == 0) targetanimation = idleanim; if (currentanimation == thrownanim && targetframe == 0) { skeleton.offset = 0; skeleton.free = 1; longdead = 1; for (auto& joint : skeleton.joints) { joint.position = playercoords + rotate(joint.position + joint.offset, 0, playerrotation, 0); joint.realoldposition = joint.position; joint.velocity = rotate(joint.velocity, 0, playerrotation, 0); } } } if(!skeleton.free){ if(currentanimation!=lyinganim){ if(animation[targetanimation].speed[currentframe]>animation[currentanimation].speed[currentframe]) target+=multiplier*animation[targetanimation].speed[currentframe]*speed; if(animation[targetanimation].speed[currentframe]<=animation[currentanimation].speed[currentframe]) target+=multiplier*animation[currentanimation].speed[currentframe]*speed; } if(currentanimation==lyinganim){ target+=multiplier*animation[targetanimation].speed[targetframe]*speed; } if(((currentanimation==crouchanim)&&(targetanimation!=crouchanim))||((currentanimation!=crouchanim)&&(targetanimation==crouchanim)))target+=multiplier*animation[crouchanim].speed[0]*2; if(currentanimation==idleanim&&targetanimation==idleanim)target-=multiplier*animation[idleanim].speed[0]/2; if(target>1)currentframe=targetframe; for (int i = 0; i < max_joints; ++i) { if(currentanimation!=lyinganim){ skeleton.joints[i].velocity=((animation[currentanimation].position[i][currentframe]*(1-target)+animation[targetanimation].position[i][targetframe]*(target))-(skeleton.joints[i].position))/multiplier; skeleton.joints[i].position=animation[currentanimation].position[i][currentframe]*(1-target)+animation[targetanimation].position[i][targetframe]*(target); if(skeleton.joints[i].hasparent&&skeleton.joints[i].visible) { skeleton.joints[i].rotate1=animation[currentanimation].rotate1[i][currentframe]*(1-target)+animation[targetanimation].rotate1[i][targetframe]*(target); skeleton.joints[i].rotate2=animation[currentanimation].rotate2[i][currentframe]*(1-target)+animation[targetanimation].rotate2[i][targetframe]*(target); skeleton.joints[i].rotate3=animation[currentanimation].rotate3[i][currentframe]*(1-target)+animation[targetanimation].rotate3[i][targetframe]*(target); } if(skeleton.muscles[i].visible) { skeleton.muscles[i].rotate1=animation[currentanimation].mrotate1[i][currentframe]*(1-target)+animation[targetanimation].mrotate1[i][targetframe]*(target); skeleton.muscles[i].rotate2=animation[currentanimation].mrotate2[i][currentframe]*(1-target)+animation[targetanimation].mrotate2[i][targetframe]*(target); skeleton.muscles[i].rotate3=animation[currentanimation].mrotate3[i][currentframe]*(1-target)+animation[targetanimation].mrotate3[i][targetframe]*(target); } } if(currentanimation==lyinganim){ skeleton.joints[i].velocity=((tempanimation.position[i][0]*(1-target)+animation[targetanimation].position[i][targetframe]*(target))-(skeleton.joints[i].position))/multiplier; skeleton.joints[i].position=tempanimation.position[i][0]*(1-target)+animation[targetanimation].position[i][targetframe]*(target); } } } //Look up+down if(!skeleton.free&&(whichgun!=nogun||who==0)&&health==100&¤tanimation!=lyinganim&¤tanimation!=getupfrontanim&¤tanimation!=getupbackanim&¤tanimation!=diveanim&&targetanimation!=diveanim&&targetanimation!=throwanim&&targetanimation!=thrownanim){ if (who == 0) playerrotation2 = camera.rotation2; XYZ facing {0.0f, 0.0f, 1.0f}; XYZ facinghalf = rotate(rotate(facing, playerrotation2 / 2, 0, 0), 0, -7, 0); facing = rotate(facing, playerrotation2, 0, 0); XYZ facingright = rotate(facing, 0, -90, 0); XYZ facingdown = rotate(facing, 90, 0, 0); XYZ rotatearound; XYZ oldpos; switch (whichgun) { case sniperrifle: case shotgun: case assaultrifle: for (int i = 0; i < max_joints; ++i) switch (skeleton.joints[i].label) { case leftelbow: case leftwrist: case lefthand: case rightelbow: case rightwrist: case righthand: skeleton.joints[i].position = animation[rifleholdanim].position[i][0]; if (currentanimation == crouchanim || targetanimation == crouchanim) skeleton.joints[i].position += skeleton.joints[neck].position - animation[idleanim].position[neck][0]; } } if((aiming||aimamount>0||whichgun==grenade)&&whichgun!=nogun){ if(aiming&&targetanimation!=joganim){ if(aimamount<1)aimamount+=multiplier*4; if(aimamount>1)aimamount=1; } if(!aiming||targetanimation==joganim){ if(aimamount>0)aimamount-=multiplier*4; if(aimamount<0)aimamount=0; } if (grenphase) { if(grenamount<1)grenamount+=multiplier*4; if(grenamount>1)grenamount=1; } else { if(grenamount>0)grenamount-=multiplier*4; if(grenamount<0)grenamount=0; } rotatearound=skeleton.joints[neck].position; for (int i = 0; i < max_joints; ++i){ if(skeleton.joints[i].label!=righthand&&skeleton.joints[i].label!=rightelbow&&skeleton.joints[i].label!=rightwrist&&skeleton.joints[i].label!=lefthand&&skeleton.joints[i].label!=leftelbow&&skeleton.joints[i].label!=leftwrist){ }else{ if(whichgun==sniperrifle){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[rifleaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim){ skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); } skeleton.joints[i].position+=facingright*0.1; skeleton.joints[i].position=rotatearound+rotate(skeleton.joints[i].position-rotatearound,(playerrotation2/2-10)*aimamount,0,0); skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==shotgun){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[assaultrifleaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=rotatearound+rotate(skeleton.joints[i].position-rotatearound,(playerrotation2/2)*aimamount,0,0); if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position+=facingdown*.2; else skeleton.joints[i].position-=facingdown*.02; if(skeleton.joints[i].label==righthand)skeleton.joints[i].position=skeleton.joints[lefthand].position-facinghalf*2; skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==assaultrifle){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[assaultrifleaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=rotatearound+rotate(skeleton.joints[i].position-rotatearound,(playerrotation2/2)*aimamount,0,0); if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position+=facingdown*.2; else skeleton.joints[i].position-=facingdown*.02; if(skeleton.joints[i].label==righthand)skeleton.joints[i].position=skeleton.joints[lefthand].position-facinghalf*2; skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==handgun1){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[pistolaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=rotatearound+rotate(skeleton.joints[i].position-rotatearound,(playerrotation2/2)*aimamount,0,0); if(currentanimation==crouchanim||targetanimation==crouchanim){skeleton.joints[i].position+=facingright*.15;skeleton.joints[i].position+=facingdown*.3;} else skeleton.joints[i].position-=facingdown*.1; skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==handgun2){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[pistolaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=rotatearound+rotate(skeleton.joints[i].position-rotatearound,(playerrotation2/2)*aimamount,0,0); if(currentanimation==crouchanim||targetanimation==crouchanim){skeleton.joints[i].position+=facingright*.15;skeleton.joints[i].position+=facingdown*.3;} else skeleton.joints[i].position-=facingdown*.1; skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==grenade){ aimamount=1; oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[grenadeaimanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=skeleton.joints[i].position*(aimamount)+oldpos*(1-aimamount); } if(whichgun==grenade&&grenamount>0){ oldpos=skeleton.joints[i].position; skeleton.joints[i].position=animation[grenadechargeanim].position[i][0]; if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[neck][0]-skeleton.joints[neck].position); skeleton.joints[i].position=skeleton.joints[i].position*(grenamount)+oldpos*(1-grenamount); } if(thirdperson||who!=0)skeleton.joints[i].position+=facingdown*.4; if(currentanimation!=crouchanim)skeleton.joints[i].position-=facinghalf*recoil*.35; if(currentanimation==crouchanim)skeleton.joints[i].position-=facinghalf*recoil*.1; } } } //Whack if(attackframe>-1&&whichgun!=grenade){ for (int i = 0; i < max_joints; ++i) { if(!skeleton.joints[i].lower){ if(attackframe==animation[riflehitanim].numframes)skeleton.joints[i].position=skeleton.joints[i].position*(attacktarget)+animation[riflehitanim].position[i][attackframe-1]*(1-attacktarget); if(attackframe>0&&attackframe0)attacktarget+=multiplier*animation[riflehitanim].speed[attackframe-1]*2; if(attacktarget>1){ attacktarget=0; attackframe++; if(attackframe>animation[riflehitanim].numframes)attackframe=-1; } } //Throw grenade if(attackframe>-1&&whichgun==grenade&&ammo>0){ for (int i = 0; i < max_joints; ++i) { if(!skeleton.joints[i].lower){ if(attackframe==animation[grenadethrowanim].numframes)skeleton.joints[i].position=skeleton.joints[i].position*(attacktarget)+animation[grenadethrowanim].position[i][attackframe-1]*(1-attacktarget); if(attackframe>0&&attackframe0)attacktarget+=multiplier*animation[grenadethrowanim].speed[attackframe-1]*2; if(attacktarget>1){ attacktarget=0; attackframe++; if(attackframe>animation[grenadethrowanim].numframes){ attackframe=-1; } if(attackframe==animation[grenadethrowanim].numframes-1&&ammo>0){ ammo=-1; sprites.MakeSprite(grenadesprite, 1, 1, 1, 1, rotate(skeleton.joints[righthand].position,0,playerrotation,0)+playercoords, rotate(facing,0,playerrotation,0)*30+velocity, 1); sprites.MakeSprite(spoonsprite, 1, 1, 1, 1, rotate(skeleton.joints[righthand].position,0,playerrotation,0)+playercoords, rotate(facing,0,playerrotation,0)*10+velocity, 1); sprites.MakeSprite(pinsprite, 1, 1, 1, 1, rotate(skeleton.joints[lefthand].position,0,playerrotation,0)+playercoords, facing*.1+velocity, 1); XYZ soundsrc = (rotate(skeleton.joints[righthand].position, 0, playerrotation, 0) + playercoords - camera.position) / soundscalefactor; ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z}; alSourcefv(gSourceID[grenadethrowsound], AL_POSITION, gLoc); alSourcePlay(gSourceID[grenadethrowsound]); } } } rotatearound=skeleton.joints[abdomen].position; if (who == 0) { for (auto& joint : skeleton.joints) if (!joint.lower) joint.position = rotatearound + rotate(joint.position - rotatearound, playerrotation2 / 2, 0, 0); else if (joint.label != groin) joint.position = rotate(joint.position, 0, playerlowrotation - playerrotation, 0); rotatearound = skeleton.joints[neck].position; skeleton.joints[head].position = rotatearound + rotate(skeleton.joints[head].position - rotatearound, playerrotation2 / 2, 0, 0); } skeleton.DoConstraints(); // Reload if (whichgun != nogun && whichgun != knife) { if (reloading > 0) { aiming = 0; reloading -= multiplier; } if(ammo < 0 && reloads[whichgun] > 0 && reloading <= 0) { ALint tempint; alGetSourcei(gSourceID[reloadsound], AL_SOURCE_STATE, &tempint); if (whichgun != grenade && tempint != AL_PLAYING) { auto soundsrc = playercoords - camera.position; playSound(gSourceID[reloadsound], soundsrc.x, soundsrc.y, soundsrc.z); } reloading = 3; aiming = 0; switch (whichgun) { case sniperrifle: ammo = 5; break; case shotgun: ammo = 6; break; case assaultrifle: ammo = 25; break; case handgun1: ammo = 12; break; case handgun2: ammo = 16; break; case grenade: ammo = 1; reloading = 1; break; } reloads[whichgun]--; } if (reloads[whichgun] == 0 && whichgun == grenade && ammo <= 0) whichgun = nogun; if (reloading < 0) { reloading = 0; aiming = 1; } } } } void Person::DoAnimationslite(int who) { if (skeleton.free) return; if (target > 1) { // Footstep sounds if (who == 0 && !visions && (onground || abs(velocity.y) < 1) && (targetanimation == joganim || targetanimation == walkanim) && (targetframe == 0 || targetframe == 8)) { auto soundsrc = playercoords - camera.position; playSound(gSourceID[footstepsound + randUint(5)], soundsrc.x, soundsrc.y, soundsrc.z); } if (targetanimation == zombieeatanim && targetframe == 3) { auto& joints = skeleton.joints; auto head_joint = joints[head]; auto soundsrc = (rotate(head_joint.position, 0, playerrotation, 0) + playercoords - camera.position) / soundscalefactor; playSound(gSourceID[munchsound], soundsrc.x, soundsrc.y, soundsrc.z); bleeding = 1; bleeddelay = 1; bjoint1 = &head_joint; bjoint2 = joints + neck; } currentanimation = targetanimation; targetframe = currentframe + (backwardsanim ? -1 : 1); if (targetframe >= animation[currentanimation].numframes) targetframe = 0; else if (targetframe < 0) targetframe = animation[currentanimation].numframes - 1; target = 0; if ((currentanimation == getupfrontanim || currentanimation == getupbackanim) && targetframe == 0) targetanimation = idleanim; } if (currentanimation == lyinganim) target += speed * multiplier * animation[targetanimation].speed[targetframe]; else target += speed * multiplier * std::max(animation[currentanimation].speed[currentframe], animation[targetanimation].speed[currentframe]); if ((currentanimation == crouchanim) ^ (targetanimation == crouchanim)) target += *animation[crouchanim].speed * multiplier * 2; if (currentanimation == idleanim && targetanimation == idleanim) target -= *animation[idleanim].speed * multiplier / 2; if (target > 1) currentframe = targetframe; } void Person::control() { if (visions) speed = 40; else speed = (targetanimation == joganim) ? 2.2 : 2.5; auto crouch = keyPress(keymap.crouch); if (crouch && currentanimation == idleanim && targetanimation == idleanim) { targetanimation = crouchanim; target = 0; } if (!crouch && currentanimation == crouchanim && targetanimation == crouchanim) { targetanimation = idleanim; target = 0; } auto forwards = keyPress(keymap.forwards) - keyPress(keymap.backwards); auto right = keyPress(keymap.right) - keyPress(keymap.left); if ((onground || visions) && currentanimation != crouchanim) { playerlowrotation -= right * (forwards ? forwards * 45 : 90); backwardsanim = forwards < 0; auto moveanim = (keyPress(keymap.accelerate) || visions) ? joganim : walkanim; // Should jog be the default? if (forwards || right) { if (targetanimation != moveanim) { targetanimation = moveanim; targetframe = 0; } } else { if (targetanimation == joganim || (targetanimation == walkanim && targetframe != 0 && targetframe != 2)) { targetanimation = idleanim; targetframe = 0; target = 0; } } } // Air? What does this even do? if (!onground && (forwards || right)) { auto rotation = playerrotation - right * (forwards ? forwards * 45 : 90); facing = rotate({0, 0, 1}, 0, rotation, 0); velocity += facing * multiplier * 4; } } void Person::DoStuff(int who) { if ((targetanimation != idleanim && targetanimation != crouchanim) || visions) playerlowrotation = playerrotation; if (targetanimation != crouchanim && currentanimation != crouchanim) { if (playerrotation > playerlowrotation + 50) { playerlowrotation = playerrotation - 50; targetanimation = walkanim; targetframe = 0; target = 0; } else if (playerrotation < playerlowrotation - 50) { playerlowrotation = playerrotation + 50; targetanimation = walkanim; targetframe = 0; target = 0; } } else if (playerrotation > playerlowrotation + 70) { playerrotation = playerlowrotation + 70; } else if (playerrotation < playerlowrotation - 70) { playerrotation = playerlowrotation - 70; } if (who == 0) { camera.rotation = 180 - playerrotation; } else if (!visions) { if(targetanimation!=walkanim&&targetanimation!=zombiewalkanim)speed=1.0*speedmult; if(targetanimation==walkanim||targetanimation==zombiewalkanim)speed=1.8*speedmult; playerlowrotation=playerrotation; } // Do controls if (who == 0 && targetanimation != diveanim && targetanimation != throwanim && targetanimation != thrownanim && currentanimation != diveanim && currentanimation != getupfrontanim) control(); facing = rotate({0, 0, 1}, 0, playerlowrotation, 0); if (backwardsanim) facing *= -1; if(onground) velocity = {}; if (((currentanimation == joganim || currentanimation == zombiejoganim || currentanimation == diveanim) && onground) || ((currentanimation == joganim || currentanimation == zombiejoganim || currentanimation == diveanim || currentanimation == walkanim || currentanimation == zombiewalkanim) && who == 0 && visions)) { playercoords+=facing*multiplier*15*speed; velocity.x=facing.x*15*speed; velocity.z=facing.z*15*speed; } if ((currentanimation == walkanim || currentanimation == zombiewalkanim) && onground && (who != 0 || !visions)) { playercoords+=facing*multiplier*4*speed; velocity.x=facing.x*4*speed; velocity.z=facing.z*4*speed; } } void Person::FindRotationGun(XYZ start, XYZ target) { XYZ temppoint1,temppoint2,tempforward; float distance; temppoint1=start; temppoint2=target; distance = len(temppoint1 - temppoint2); gunrotate2=asin((temppoint1.y-temppoint2.y)/distance)*rad2deg; temppoint1.y=0; temppoint2.y=0; gunrotate1 = rad2deg * acos((temppoint1.z - temppoint2.z) / len(temppoint1 - temppoint2)); if(temppoint1.x>temppoint2.x)gunrotate1=360-gunrotate1; tempforward=target-start; tempforward=rotate(tempforward,-90,0,0); tempforward=rotate(tempforward,0,gunrotate1-90,0); tempforward=rotate(tempforward,0,0,gunrotate2-90); tempforward.y=0; tempforward = normalize(tempforward); gunrotate3=acos(0-tempforward.z)*rad2deg; if(0>tempforward.x)gunrotate3=360-gunrotate3; } const float EVIL_VISUAL[3] = {1.0f, 0.0f, 0.0f}; const float VIP_VISUAL[3] = {0.0f, 0.0f, 1.0f}; const float OTHER_VISUAL[3] = {0.0f, 0.0f, 0.0f}; const float* determine_color(int model, enum PersonType type, int whichcostume) { if (visions) switch (type) { case eviltype: return EVIL_VISUAL; case viptype: return VIP_VISUAL; default: return OTHER_VISUAL; } switch (model) { case 0: if (type != playertype || thirdperson) return costume[whichcostume].headcolor; break; case 1: if (type != playertype || thirdperson) return costume[whichcostume].chestcolor; break; case 2: return costume[whichcostume].abdomencolor; case 3: return costume[whichcostume].upperarmcolor; case 4: return costume[whichcostume].lowerarmcolor; case 5: return costume[whichcostume].handcolor; case 6: return costume[whichcostume].upperlegcolor; case 7: return costume[whichcostume].lowerlegcolor; case 8: return costume[whichcostume].footcolor; } return nullptr; } void draw_joint(Joint& joint, enum PersonType type, int whichcostume) { if (!joint.hasparent || !joint.visible) return; glPushMatrix(); glTranslatef((joint.position.x + joint.parent->position.x) / 2, (joint.position.y + joint.parent->position.y) / 2, (joint.position.z + joint.parent->position.z) / 2); glRotatef(90 - joint.rotate1, 0, 1, 0); glRotatef(90 - joint.rotate2, 0, 0, 1); glRotatef(-joint.rotate3, 0, 1, 0); auto& model = joint.modelnum; if (auto color = determine_color(model, type, whichcostume)) drawModel(skeletonmodels + model, color); if (model == 0 && type == playertype && thirdperson) drawModel(skeletonmodels + 9, visions ? BLACK : NULL); glPopMatrix(); } void draw_muscle(Muscle& mus, enum PersonType type, int whichcostume) { if (!mus.visible) return; auto& pos1 = mus.parent1->position; auto& pos2 = mus.parent2->position; glPushMatrix(); glTranslatef((pos1.x + pos2.x) / 2, (pos1.y + pos2.y) / 2, (pos1.z + pos2.z) / 2); glRotatef(90 - mus.rotate1, 0, 1, 0); glRotatef(90 - mus.rotate2, 0, 0, 1); glRotatef(-mus.rotate3, 0, 1, 0); auto& model = mus.parent1->modelnum; if (auto color = determine_color(model, type, whichcostume)) drawModel(skeletonmodels + model, color); glPopMatrix(); } int Person::drawSkeleton() { auto& left_wrist = skeleton.joints[lefthand].position; auto& right_wrist = skeleton.joints[righthand].position; auto& head_pos = skeleton.joints[head].position; auto& neck_pos = skeleton.joints[neck].position; switch (whichgun) { case sniperrifle: FindRotationGun(right_wrist, left_wrist); glPushMatrix(); glTranslatef(right_wrist.x, right_wrist.y, right_wrist.z); glRotatef(90 - gunrotate1, 0, 1, 0); glRotatef(90 - gunrotate2, 0, 0, 1); glRotatef(-gunrotate3, 0, 1, 0); drawModel(gunmodels + sniperriflemodel, visions ? BLACK : NULL); glPopMatrix(); break; case shotgun: FindRotationGun(right_wrist, left_wrist); glPushMatrix(); glTranslatef(right_wrist.x, right_wrist.y, right_wrist.z); glRotatef(2, 1, 0, 0); glRotatef(90 + 1 - gunrotate1, 0, 1, 0); glRotatef(90 - gunrotate2, 0, 0, 1); glRotatef(-gunrotate3, 0, 1, 0); glTranslatef(0, -0.4, 0); drawModel(gunmodels + shotgunmodel, visions ? BLACK : NULL); glPopMatrix(); break; case assaultrifle: FindRotationGun(right_wrist, left_wrist); glPushMatrix(); glTranslatef(right_wrist.x, right_wrist.y, right_wrist.z); glRotatef(90 - gunrotate1, 0, 1, 0); glRotatef(90 - gunrotate2, 0, 0, 1); glRotatef(-gunrotate3, 0, 1, 0); drawModel(gunmodels + assaultriflemodel, visions ? BLACK : NULL); glPopMatrix(); break; case handgun1: case handgun2: if (this->type != playertype || thirdperson) FindRotationGun(right_wrist, head_pos * 0.35 + neck_pos * 0.65); else FindRotationGun(right_wrist, head_pos * 0.65 + neck_pos * 0.35); glPushMatrix(); glTranslatef(right_wrist.x, right_wrist.y, right_wrist.z); glRotatef(90 - 1.5 - gunrotate1, 0, 1, 0); glRotatef(90 - gunrotate2, 0, 0, 1); glRotatef(-gunrotate3, 0, 1, 0); glTranslatef(0, 0, 0.15); drawModel(gunmodels + (whichgun == handgun1 ? handgunbasemodel : handgun2basemodel), visions ? BLACK : NULL); glTranslatef(0, recoil * -0.3, 0); drawModel(gunmodels + (whichgun == handgun1 ? handgunslidemodel : handgun2slidemodel), visions ? BLACK : NULL); glPopMatrix(); break; case grenade: glPushMatrix(); glTranslatef(right_wrist.x, right_wrist.y, right_wrist.z); glRotatef(-90, 1, 0, 0); glTranslatef(0, 0, 0.05); if (reloading <= 0) { drawModel(gunmodels + grenadebasemodel, visions ? BLACK : NULL); if (!grenphase) drawModel(gunmodels + grenadepinmodel, visions ? BLACK : NULL); glTranslatef(0, 0, 0.005); drawModel(gunmodels + grenadespoonmodel, visions ? BLACK : NULL); } glPopMatrix(); glPushMatrix(); glTranslatef(left_wrist.x, left_wrist.y, left_wrist.z); glRotatef(-90, 1, 0, 0); glTranslatef(0, 0, -0.15); if (reloading <= 0 && grenphase) drawModel(gunmodels + grenadepinmodel, visions ? BLACK : NULL); glPopMatrix(); break; case knife: auto& wrist = skeleton.joints[righthand]; glPushMatrix(); glTranslatef(wrist.position.x, wrist.position.y, wrist.position.z); glRotatef(90 - 1.5 - wrist.rotate1, 0, 1, 0); glRotatef(90 - wrist.rotate2, 0, 0, 1); glRotatef(-wrist.rotate3, 0, 1, 0); glTranslatef(0, -0.2, 0); drawModel(gunmodels + knifemodel, visions ? BLACK : NULL); glPopMatrix(); break; } if (litup) { GLfloat LightAmbient[] {0, 0, 0, 1.0f}; GLfloat LightDiffuse[] {1, 1, 1, 1.0f}; XYZ lightpoint = skeleton.joints[lefthand].position; GLfloat LightPosition[] {lightpoint.x, lightpoint.y, lightpoint.z, 0}; glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); glEnable(GL_LIGHT1); litup = 0; } else { glDisable(GL_LIGHT1); } // Find forward vectors if (this->type == playertype || skeleton.free || skeleton.offset || whichgun != nogun || currentanimation == lyinganim || ((currentanimation == getupfrontanim || currentanimation == getupbackanim) && targetanimation == idleanim)) { if (skeleton.free != 1 || longdead > 0) { if (skeleton.offset && skeleton.free < 1) { XYZ normal; skeleton.offset = 0; for (auto& joint : skeleton.joints) { joint.oldposition = joint.position; joint.position += joint.offset; if (sqrlen(joint.offset) >= multiplier * multiplier * 25) { normal = normalize(joint.offset); skeleton.offset = 1; joint.offset -= normal * multiplier * 5; } else { joint.offset = {}; } } skeleton.DoConstraints(); } auto& fwdjoints = skeleton.forwardjoints; skeleton.forward = normalize(crossProduct(skeleton.joints[fwdjoints[1]].position - skeleton.joints[fwdjoints[0]].position, skeleton.joints[fwdjoints[2]].position - skeleton.joints[fwdjoints[0]].position)); auto& lowfwd = skeleton.lowforwardjoints; skeleton.lowforward = normalize(crossProduct(skeleton.joints[lowfwd[1]].position - skeleton.joints[lowfwd[0]].position, skeleton.joints[lowfwd[2]].position - skeleton.joints[lowfwd[0]].position)); // Special forwards auto specialfwd = skeleton.specialforward; *specialfwd++ = skeleton.forward; *specialfwd = normalize(skeleton.joints[rightelbow].position - skeleton.joints[rightshoulder].position / 2 - right_wrist / 2 + skeleton.forward * 0.2); specialfwd++; *specialfwd = normalize(skeleton.joints[leftelbow].position - skeleton.joints[leftshoulder].position / 2 - left_wrist / 2 + skeleton.forward * 0.2); specialfwd++; if (this->type != playertype && aimamount > 0 && health == 100 && whichgun != nogun) { //Facing XYZ facing {0}; facing.z = 1; facing = rotate(facing, camera.rotation2, 0, 0); XYZ facingdown = rotate(facing, 90, 0, 0); skeleton.specialforward[1] *= 1 - aimamount; skeleton.specialforward[1] += facingdown * aimamount; skeleton.specialforward[2] *= 1 - aimamount; skeleton.specialforward[2] += facingdown * aimamount; } *specialfwd = normalize(skeleton.joints[righthip].position / 2 + skeleton.joints[rightankle].position / 2 - skeleton.joints[rightknee].position + skeleton.lowforward * 0.2); specialfwd++; *specialfwd = normalize(skeleton.joints[lefthip].position / 2 + skeleton.joints[leftankle].position / 2 - skeleton.joints[leftknee].position + skeleton.lowforward * 0.2); specialfwd++; for (int i = 0; i < max_joints; i++) if (skeleton.joints[i].hasparent && skeleton.joints[i].visible) skeleton.FindRotationJoint(i); for(int i = 0; i < skeleton.num_muscles; i++) if (skeleton.muscles[i].visible) skeleton.FindRotationMuscle(i); } } for (int i = 0; i < max_joints; i++) draw_joint(skeleton.joints[i], this->type, whichcostume); for (int i = 0; i < skeleton.num_muscles; i++) draw_muscle(skeleton.muscles[i], this->type, whichcostume); if (skeleton.offset && skeleton.free < 1) for (auto& joint : skeleton.joints) joint.position = joint.oldposition; glDisable(GL_LIGHT1); return 0; }