// 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;
}