aboutsummaryrefslogblamecommitdiff
path: root/src/Person.cpp
blob: 9e49cbbfaad443ee5ede1fc8345c239e8898b918 (plain) (tree)


















                                                                         

                       

                   
                        




















                                    
                                
                           
 
                                                                             

                             

                      
                    



















                                                                                          
                                      





























































































                                                                                                                                                        
 











































                                                                                                                                                             






                                                                           
                                                                            



                                                                            


                                                                             








                                                                            

                                                                               



                                                             
                 






















                                                                                


                                                                                 














                                                                           


                         
 








                                                                                                                           
                 

                                                                                                                                                                                                        
 
                                                     
 






















                                                                                                                                                                                                                                       
 
                      
                                                                                                                                                                                                                                                                                   



                                




                                                         
 









                                                                            
 






                                                                            
                           
















                                                                                                                                                                                                                                                                  
                 







                                                                                                                                                                                                                                                                  
                 






























































































































                                                                                                                                                                                                                                                                                    



                                                                                                                                                   




                                                                                                    
 















                                                                                                                                                                                      
 
                                         
 




                                                             
                         






























                                                                                                            
                                 

                                                    




                                                                                       




                         





                                      
                                                                             






                                                                            


                                                                             








                                                                            

                                                                               



                                                             
                 
 





                                                                                
 




                                                                               
         














                                                                                














                                                                                                                                                
 




                                                                                                  
 






                                                                                                                                                                     
 


                                                                   
                                          




                                                     
                 




                                                       

                                                                                   
                                                                                 
                                                                           
                                                         
                         
                                                                         


                                                                           



                                                                 
                         
                                                                         


                                                                           



                                                                 
                         
                                                      







                                                                           
                                                                                 
                                         
                                           


                                                                             
                                                                         
                                                   



                                                             
                                         
                                           


                                                                             
                                                                         
                                                   



                                                             
                                         
                                           


                                                                             

                                                                              

                                                    
                                           




                                                                             


                                                                               






                                                                                           
 

                   
 

                                                        
 


















                                                                                                                                                                                                                                                                                                   
 

















                                                                                                 



                                                            
                                            
                                                               
                      
               
                                            
                                                                
                      













                                                           
         
                       














                                                                       
                                     
                                                                   
                                                                       
                                                  








                                                        

                                           






                                                              
                                            

                                                                       
                                                  





                                         





                                                                              
 


                                                         
                               








                                                                          
                               










                                                                          
                               














                                                                          
 
                               




                                                                          
 











                                                             
                               










                                                                          
 
                               







                                                                       
                                                                               









                                                             
         



                                                       
                                                            


                                                                
                                                                 

                                                               
                                    


                                     
         
 
                              









                                                                               
                                                                         











                                                                                                           
                         
 
                                                                 





                                                                           
 
                                                                 





                                                                        
 
                                           

                                                                  
 

                                                                                   



                                                                              
 

                                                                                 

















                                                                                     
 


                                                                             




                                                                             
 


                                                                           













                                                                            

                 
 

                                                                  

                                                                    
 

                                                               
                                                         
                                                           
                 
 
                             
                 
 
// 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 <https://www.gnu.org/licenses/>.

#include <GLFW/glfw3.h>

#include "Person.h"

extern float multiplier;
extern unsigned int gSourceID[100];
extern unsigned int gSampleSet[100];
extern Animation animation[30];
extern int thirdperson;
extern int 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 int forwardskey;
extern int backwardskey;
extern int leftkey;
extern int rightkey;
extern int aimkey;
extern int psychicaimkey;
extern int psychickey;

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;
	XYZ average;
	int howmany;
	float distancemax;
	HitStruct hitstruct;
	hitstruct.collision=0;
	//Make bounding sphere
	average=0;
	howmany=0;
	for(int j=0;j<skeleton.num_joints;j++){
		average.x=average.x+skeleton.joints[j].position.x;
		average.y=average.y+skeleton.joints[j].position.y;
		average.z=average.z+skeleton.joints[j].position.z;
		howmany++;
	}
	average=average/howmany;
	distancemax=0;
	for(int j=0;j<skeleton.num_joints;j++){
		if(findDistancefast(average,skeleton.joints[j].position)>distancemax){
			distancemax=findDistancefast(average,skeleton.joints[j].position);
		}
	}
	distancemax=sqrt(distancemax);
	//Collide with player
	if(skeleton.free<1){
		start=start-playercoords;
		end=end-playercoords;
		if(playerrotation)start=DoRotation(start,0,-playerrotation,0);
		if(playerrotation)end=DoRotation(end,0,-playerrotation,0);
	}
	tempbulletloc[0]=start;
	tempbulletloc[1]=end;
	if(sphere_line_intersection(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z,
								tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z,
								average.x, average.y, average.z, distancemax)){
	for(int j=0;j<skeleton.num_joints;j++){
		if(skeleton.joints[j].hasparent&&skeleton.joints[j].visible){
			tempbulletloc[0]=start;
			tempbulletloc[1]=end;
			glPushMatrix();
				glLoadIdentity();
				glScalef(1,1/skeleton.joints[j].length,1);
				glRotatef(skeleton.joints[j].rotate2-90,0,0,1);
				glRotatef(skeleton.joints[j].rotate1-90,0,1,0);
				glTranslatef(	(-(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2),
								(-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2),
								(-(skeleton.joints[j].position.z+skeleton.joints[j].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/skeleton.joints[j].length,1);
				glRotatef(skeleton.joints[j].rotate2-90,0,0,1);
				glRotatef(skeleton.joints[j].rotate1-90,0,1,0);
				glTranslatef(	(-(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2),
								(-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2),
								(-(skeleton.joints[j].position.z+skeleton.joints[j].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=skeletonmodels[skeleton.joints[j].modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint);
			if(collide!=-1)
			{
				glPushMatrix();
					glLoadIdentity();
					glTranslatef(	(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2,
									(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2,
									(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2);
					glRotatef(-skeleton.joints[j].rotate1+90,0,1,0);
					glRotatef(-skeleton.joints[j].rotate2+90,0,0,1);
					glScalef(1,skeleton.joints[j].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=&skeleton.joints[j];
				hitstruct.joint2=skeleton.joints[j].parent;
			}
		}
	}
	for(int j=0;j<skeleton.num_muscles;j++){
		if(skeleton.muscles[j].visible){
			tempbulletloc[0]=start;
			tempbulletloc[1]=end;
			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[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=skeletonmodels[skeleton.muscles[j].parent1->modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&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,findDistance(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=DoRotation(hitstruct.hitlocation,0,playerrotation,0);
		hitstruct.hitlocation=hitstruct.hitlocation+playercoords;
	}
	return hitstruct;
}

extern float camerashake;
extern int cycle;
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)
				/ soundscalefactor;
			ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
			int whichsound = footstepsound + abs(Random()) % 5;
			alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
			alSourcePlay(gSourceID[whichsound]);
		}

		if (targetanimation == zombieeatanim && targetframe == 3) {
			auto& joints = skeleton.joints;
			auto& jointlabels = skeleton.jointlabels;
			auto head_joint = joints[jointlabels[head]];
			auto soundsrc = (DoRotation(head_joint.position,
				0, playerrotation, 0) + playercoords
				- camera.position) / soundscalefactor;
			ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
			alSourcefv(gSourceID[bodyhitsound], AL_POSITION, gLoc);
			alSourcePlay(gSourceID[bodyhitsound]);
			bleeding = 1;
			bleeddelay = 1;
			bjoint1 = &head_joint;
			bjoint2 = joints + jointlabels[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& jointlabels = skeleton.jointlabels;
			auto head_joint = joints[jointlabels[head]];
			auto soundsrc = (DoRotation(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
					+ DoRotation(joint.position
						+ joint.offset,
						0, playerrotation, 0);
				joint.realoldposition = joint.position;
				joint.velocity = DoRotation(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<skeleton.num_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&&currentanimation!=lyinganim&&currentanimation!=getupfrontanim&&currentanimation!=getupbackanim&&currentanimation!=diveanim&&targetanimation!=diveanim&&targetanimation!=throwanim&&targetanimation!=thrownanim){
		XYZ facing;
		XYZ facingdown;
		XYZ facinghalf;
		XYZ facingright;
		if(who==0){
			playerrotation2=camera.rotation2;
			//Facing
			facing=0;
			facing.z=1;

			facinghalf=DoRotation(facing,playerrotation2/2,0,0);
			facinghalf=DoRotation(facinghalf,0,-7,0);
			facing=DoRotation(facing,playerrotation2,0,0);
			facingright=DoRotation(facing,0,-90,0);
			facingdown=DoRotation(facing,90,0,0);
		}
		if(who!=0){
			//Facing
			facing=0;
			facing.z=1;

			facinghalf=DoRotation(facing,playerrotation2/2,0,0);
			facinghalf=DoRotation(facinghalf,0,-7,0);
			facing=DoRotation(facing,playerrotation2,0,0);
			facingright=DoRotation(facing,0,-90,0);
			facingdown=DoRotation(facing,90,0,0);
		}
		XYZ rotatearound;
		XYZ oldpos;
		if(whichgun==sniperrifle){
			for(int i=0;i<skeleton.num_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{
					skeleton.joints[i].position=animation[rifleholdanim].position[i][0];
					if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
				}
			}
		}
		if(whichgun==shotgun){
			for(int i=0;i<skeleton.num_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{
					skeleton.joints[i].position=animation[rifleholdanim].position[i][0];
					if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
				}
			}
		}
		if(whichgun==assaultrifle){
			for(int i=0;i<skeleton.num_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{
					skeleton.joints[i].position=animation[rifleholdanim].position[i][0];
					if(currentanimation==crouchanim||targetanimation==crouchanim)skeleton.joints[i].position-=(animation[idleanim].position[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
				}
			}
		}
		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==1){
				if(grenamount<1)grenamount+=multiplier*4;
				if(grenamount>1)grenamount=1;
			}
			if(grenphase==0){
				if(grenamount>0)grenamount-=multiplier*4;
				if(grenamount<0)grenamount=0;
			}
			rotatearound=skeleton.joints[skeleton.jointlabels[neck]].position;
			for(int i=0;i<skeleton.num_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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
						}
						skeleton.joints[i].position+=facingright*0.1;
						skeleton.joints[i].position=rotatearound+DoRotation(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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
						skeleton.joints[i].position=rotatearound+DoRotation(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[skeleton.jointlabels[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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
						skeleton.joints[i].position=rotatearound+DoRotation(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[skeleton.jointlabels[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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
						skeleton.joints[i].position=rotatearound+DoRotation(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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[neck]].position);
						skeleton.joints[i].position=rotatearound+DoRotation(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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[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[skeleton.jointlabels[neck]][0]-skeleton.joints[skeleton.jointlabels[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<skeleton.num_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&&attackframe<animation[riflehitanim].numframes)skeleton.joints[i].position=animation[riflehitanim].position[i][attackframe-1]*(1-attacktarget)+animation[riflehitanim].position[i][attackframe]*(attacktarget);
					if(attackframe==0)skeleton.joints[i].position=skeleton.joints[i].position*(1-attacktarget)+animation[riflehitanim].position[i][attackframe]*(attacktarget);
				}
			}
			if(attackframe==0)attacktarget+=multiplier*animation[riflehitanim].speed[attackframe]*2;
			if(attackframe>0)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<skeleton.num_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&&attackframe<animation[grenadethrowanim].numframes)skeleton.joints[i].position=animation[grenadethrowanim].position[i][attackframe-1]*(1-attacktarget)+animation[grenadethrowanim].position[i][attackframe]*(attacktarget);
					if(attackframe==0)skeleton.joints[i].position=skeleton.joints[i].position*(1-attacktarget)+animation[grenadethrowanim].position[i][attackframe]*(attacktarget);
				}
			}
			if(attackframe==0)attacktarget+=multiplier*animation[grenadethrowanim].speed[attackframe]*2;
			if(attackframe>0)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, DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,playerrotation,0)+playercoords, DoRotation(facing,0,playerrotation,0)*30+velocity, 1);
					sprites.MakeSprite(spoonsprite, 1, 1, 1, 1, DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,playerrotation,0)+playercoords, DoRotation(facing,0,playerrotation,0)*10+velocity, 1);
					sprites.MakeSprite(pinsprite, 1, 1, 1, 1, DoRotation(skeleton.joints[skeleton.jointlabels[lefthand]].position,0,playerrotation,0)+playercoords, facing*.1+velocity, 1);

					XYZ soundsrc = (DoRotation(skeleton.joints[skeleton.jointlabels[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[skeleton.jointlabels[abdomen]].position;
		if(who==0)
		for(int i=0;i<skeleton.num_joints;i++){
		 	if(skeleton.joints[i].lower==0)
		 		skeleton.joints[i].position=rotatearound+DoRotation(skeleton.joints[i].position-rotatearound,playerrotation2/2,0,0);
		}
		if(who==0)
		for(int i=0;i<skeleton.num_joints;i++){
		 	if(skeleton.joints[i].lower==1&&skeleton.joints[i].label!=groin)
		 		skeleton.joints[i].position=DoRotation(skeleton.joints[i].position,0,playerlowrotation-playerrotation,0);
		}
		//head facing
		if(who==0){
		rotatearound=skeleton.joints[skeleton.jointlabels[neck]].position;
		skeleton.joints[skeleton.jointlabels[head]].position=rotatearound+DoRotation(skeleton.joints[skeleton.jointlabels[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) / soundscalefactor;
					ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
					alSourcefv(gSourceID[reloadsound], AL_POSITION, gLoc);
					alSourcePlay(gSourceID[reloadsound]);
				}
				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)
				/ soundscalefactor;
			ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
			int whichsound = footstepsound + abs(Random()) % 5;
			alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
			alSourcePlay(gSourceID[whichsound]);
		}

		if (targetanimation == zombieeatanim && targetframe == 3) {
			auto& joints = skeleton.joints;
			auto& jointlabels = skeleton.jointlabels;
			auto head_joint = joints[jointlabels[head]];
			auto soundsrc = (DoRotation(head_joint.position,
				0, playerrotation, 0) + playercoords
				- camera.position) / soundscalefactor;
			ALfloat gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
			alSourcefv(gSourceID[bodyhitsound], AL_POSITION, gLoc);
			alSourcePlay(gSourceID[bodyhitsound]);
			bleeding = 1;
			bleeddelay = 1;
			bjoint1 = &head_joint;
			bjoint2 = joints + jointlabels[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
			* 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::DoStuff(int who){
	int moveanim;

	if((targetanimation!=idleanim&&targetanimation!=crouchanim)||visions==1)playerlowrotation=playerrotation;
	if(targetanimation!=crouchanim&&currentanimation!=crouchanim){
		if(playerrotation>playerlowrotation+50){playerlowrotation=playerrotation-50; targetanimation=walkanim; targetframe=0; target=0;}
		if(playerrotation<playerlowrotation-50){playerlowrotation=playerrotation+50; targetanimation=walkanim; targetframe=0; target=0;}
	}
	if(targetanimation==crouchanim||currentanimation==crouchanim){
		if(playerrotation>playerlowrotation+70){playerrotation=playerlowrotation+70;}
		if(playerrotation<playerlowrotation-70){playerrotation=playerlowrotation-70;}
	}
	if(who==0)camera.rotation=180-playerrotation;

	if(who!=0&&visions==0){
		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){
		backwardsanim=0;
		if(visions==1)speed=40;
		if(visions==0&&targetanimation==joganim)speed=2.2;
		if(visions==0&&targetanimation!=joganim)speed=1.3;
		if(visions==0&&targetanimation==walkanim)speed=2.5;

		if (IsKeyDown(GLFW_KEY_LEFT_SHIFT) || visions == 1)
			moveanim = joganim;
		else
			moveanim=walkanim;
		if (IsKeyDown(GLFW_KEY_LEFT_CONTROL)
		    && currentanimation == idleanim
		    && targetanimation == idleanim) {
			targetanimation = crouchanim;
			target = 0;
		}
		if (!IsKeyDown(GLFW_KEY_LEFT_CONTROL)
		    && currentanimation == crouchanim
		    && targetanimation == crouchanim) {
			targetanimation = idleanim;
			target = 0;
		}
		if((onground||(who==0&&visions==1))&&currentanimation!=crouchanim){
			if (IsKeyDown(forwardskey) && !IsKeyDown(backwardskey)) {
				if(targetanimation!=moveanim)targetframe=0;
				targetanimation=moveanim;
			}
			if (IsKeyDown(rightkey) && !IsKeyDown(leftkey)) {
				if(targetanimation!=moveanim)targetframe=0;
				targetanimation=moveanim;
				playerlowrotation-=90;
				if (IsKeyDown(forwardskey))
					playerlowrotation += 45;
				if (IsKeyDown(backwardskey))
					playerlowrotation -= 235;
			}
			if (IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
				if(targetanimation!=moveanim)targetframe=0;
				targetanimation=moveanim;
				playerlowrotation+=90;
				if (IsKeyDown(forwardskey))
					playerlowrotation -= 45;
				if (IsKeyDown(backwardskey))
					playerlowrotation += 235;
			}
			if (IsKeyDown(backwardskey)) {
				if(targetanimation!=moveanim)targetframe=0;
				targetanimation=moveanim;
				backwardsanim=1;
			}
		}
		//air control
		if(!onground){
			float oldplayerrotation=playerrotation;
			if (IsKeyDown(forwardskey) && !IsKeyDown(backwardskey)) {
				facing=0;
				facing.z=1;
				facing=DoRotation(facing,0,playerrotation,0);
				velocity=velocity+facing*multiplier*4;
			}
			if (IsKeyDown(rightkey) && !IsKeyDown(leftkey)) {
				playerrotation-=90;
				if (IsKeyDown(forwardskey))
					playerrotation += 45;
				if (IsKeyDown(backwardskey))
					playerrotation -= 45;
				facing=0;
				facing.z=1;
				facing=DoRotation(facing,0,playerrotation,0);
				velocity=velocity+facing*multiplier*4;
			}
			if (IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
				playerrotation+=90;
				if (IsKeyDown(forwardskey))
					playerrotation -= 45;
				if (IsKeyDown(backwardskey))
					playerrotation += 45;
				facing=0;
				facing.z=1;
				facing=DoRotation(facing,0,playerrotation,0);
				velocity=velocity+facing*multiplier*4;
			}
			if (IsKeyDown(backwardskey) && !IsKeyDown(forwardskey)
			    && !IsKeyDown(leftkey) && !IsKeyDown(rightkey)) {
				playerrotation+=180;
				facing=0;
				facing.z=1;
				facing=DoRotation(facing,0,playerrotation,0);
				velocity=velocity+facing*multiplier*4;
			}
			playerrotation=oldplayerrotation;
		}
		if (!IsKeyDown(forwardskey) && !IsKeyDown(leftkey)
		    && !IsKeyDown(rightkey) && !IsKeyDown(backwardskey)
		    && (targetanimation==joganim||targetanimation==walkanim)) {
			if(!(targetanimation==walkanim&&(targetframe==0||targetframe==2))){
				targetanimation=idleanim;
				targetframe=0;
				target=0;
			}
		}
	}

	facing=0;
	facing.z=1;

	facing=DoRotation(facing,0,playerlowrotation,0);
	if(backwardsanim)facing*=-1;

	if(onground){
		velocity=0;
	}
	if(((currentanimation==joganim||currentanimation==zombiejoganim||currentanimation==diveanim)&&onground)||(who==0&&visions==1&&((currentanimation==joganim||currentanimation==walkanim||currentanimation==diveanim)||(currentanimation==zombiejoganim||currentanimation==zombiewalkanim)))){
		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==0)){
		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=findDistance(temppoint1,temppoint2);
	gunrotate2=asin((temppoint1.y-temppoint2.y)/distance)*rad2deg;
	temppoint1.y=0;
	temppoint2.y=0;
	gunrotate1=acos((temppoint1.z-temppoint2.z)/findDistance(temppoint1,temppoint2))*rad2deg;
	if(temppoint1.x>temppoint2.x)gunrotate1=360-gunrotate1;
	tempforward=target-start;
	tempforward=DoRotation(tempforward,-90,0,0);
	tempforward=DoRotation(tempforward,0,gunrotate1-90,0);
	tempforward=DoRotation(tempforward,0,0,gunrotate2-90);
	tempforward.y=0;
	Normalise(&tempforward);
	gunrotate3=acos(0-tempforward.z)*rad2deg;
	if(0>tempforward.x)gunrotate3=360-gunrotate3;
}

float* determine_color(int model, int who, int whichcostume)
{
	switch (model) {
	case 0:
		if (who != 0 || thirdperson)
			return costume[whichcostume].headcolor;
		break;
	case 1:
		if (who != 0 || 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, int who, 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, who, whichcostume))
		skeletonmodels[model].draw(*color, color[1], color[2]);
	if (model == 0 && who == 0 && thirdperson)
		skeletonmodels[9].draw();
	glPopMatrix();
}

void draw_muscle(Muscle& mus, int who, 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, who, whichcostume))
		skeletonmodels[model].draw(*color, color[1], color[2]);
	if (model == 0 && who == 0 && thirdperson)
		skeletonmodels[9].draw();
	glPopMatrix();
}

int Person::DrawSkeleton(int who)
{
	auto& left_hand = skeleton.jointlabels[lefthand];
	auto& left_wrist = skeleton.joints[left_hand].position;
	auto& right_hand = skeleton.jointlabels[righthand];
	auto& right_wrist = skeleton.joints[right_hand].position;
	auto& head_pos = skeleton.joints[skeleton.jointlabels[head]].position;
	auto& neck_pos = skeleton.joints[skeleton.jointlabels[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);
		gunmodels[sniperriflemodel].draw();
		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);
		gunmodels[shotgunmodel].draw();
		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);
		gunmodels[assaultriflemodel].draw();
		glPopMatrix();
		break;
	case handgun1:
	case handgun2:
		if (who || 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);

		if (whichgun == handgun1)
			gunmodels[handgunbasemodel].draw();
		else
			gunmodels[handgun2basemodel].draw();
		glTranslatef(0, recoil * -0.3, 0);
		if (whichgun == handgun1)
			gunmodels[handgunslidemodel].draw();
		else
			gunmodels[handgun2slidemodel].draw();
		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) {
			gunmodels[grenadebasemodel].draw();
			if (grenphase == 0)
				gunmodels[grenadepinmodel].draw();
			glTranslatef(0, 0, 0.005);
			gunmodels[grenadespoonmodel].draw();
		}
		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 == 1)
			gunmodels[grenadepinmodel].draw();
		glPopMatrix();
		break;
	case knife:
		auto& wrist = skeleton.joints[skeleton.jointlabels[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);
		gunmodels[knifemodel].draw();
		glPopMatrix();
		break;
	}

	if (litup) {
		GLfloat LightAmbient[] {0, 0, 0, 1.0f};
		GLfloat LightDiffuse[] {1, 1, 1, 1.0f};
		auto& hand = skeleton.jointlabels[lefthand];
		XYZ lightpoint = skeleton.joints[hand].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 (!who || 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 (int i = 0; i < skeleton.num_joints; i++) {
					auto& joint = skeleton.joints[i];
					joint.oldposition = joint.position;
					joint.position += joint.offset;
					if (findLengthfast(joint.offset) >= multiplier * multiplier * 25) {
						normal = joint.offset;
						Normalise(&normal);
						skeleton.offset = 1;
						joint.offset -= normal * multiplier * 5;
					} else {
						joint.offset=0;
					}
				}
				skeleton.DoConstraints();
			}

			auto& fwdjoints = skeleton.forwardjoints;
			CrossProduct(skeleton.joints[fwdjoints[1]].position
				- skeleton.joints[fwdjoints[0]].position,
				skeleton.joints[fwdjoints[2]].position
				- skeleton.joints[fwdjoints[0]].position,
				&skeleton.forward);
			Normalise(&skeleton.forward);

			auto& lowfwd = skeleton.lowforwardjoints;
			CrossProduct(skeleton.joints[lowfwd[1]].position
				- skeleton.joints[lowfwd[0]].position,
				skeleton.joints[lowfwd[2]].position
				- skeleton.joints[lowfwd[0]].position,
				&skeleton.lowforward);
			Normalise(&skeleton.lowforward);

			// Special forwards
			auto specialfwd = skeleton.specialforward;
			*specialfwd++ = skeleton.forward;

			auto& right_shoulder = skeleton.jointlabels[rightshoulder];
			auto& right_elbow = skeleton.jointlabels[rightelbow];
			*specialfwd = skeleton.joints[right_elbow].position
				- skeleton.joints[right_shoulder].position / 2
				- right_wrist / 2 + skeleton.forward * 0.2;
			Normalise(specialfwd++);

			auto& left_shoulder = skeleton.jointlabels[leftshoulder];
			auto& left_elbow = skeleton.jointlabels[leftelbow];
			*specialfwd = skeleton.joints[left_elbow].position
				- skeleton.joints[left_shoulder].position / 2
				- left_wrist / 2 + skeleton.forward * 0.2;
			Normalise(specialfwd++);

			if(!who && aimamount > 0
			   && health == 100 && whichgun != nogun) {
				//Facing
				XYZ facing {0};
				facing.z = 1;
				facing = DoRotation(facing, camera.rotation2, 0, 0);
				XYZ facingdown = DoRotation(facing, 90, 0, 0);

				skeleton.specialforward[1] *= 1 - aimamount;
				skeleton.specialforward[1] += facingdown * aimamount;
				skeleton.specialforward[2] *= 1 - aimamount;
				skeleton.specialforward[2] += facingdown * aimamount;
			}

			auto& right_hip = skeleton.jointlabels[righthip];
			auto& right_ankle = skeleton.jointlabels[rightankle];
			auto& right_knee = skeleton.jointlabels[rightknee];
			*specialfwd = skeleton.joints[right_hip].position / 2
				+ skeleton.joints[right_ankle].position / 2
				- skeleton.joints[right_knee].position
				+ skeleton.lowforward * 0.2;
			Normalise(specialfwd++);

			auto& left_hip = skeleton.jointlabels[lefthip];
			auto& left_ankle = skeleton.jointlabels[leftankle];
			auto& left_knee = skeleton.jointlabels[leftknee];
			*specialfwd = skeleton.joints[left_hip].position / 2
				+ skeleton.joints[left_ankle].position / 2
				- skeleton.joints[left_knee].position
				+ skeleton.lowforward * 0.2;
			Normalise(specialfwd++);

			for(int i = 0; i < skeleton.num_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 < skeleton.num_joints; i++)
		draw_joint(skeleton.joints[i], who, whichcostume);
	for (int i = 0; i < skeleton.num_muscles; i++)
		draw_muscle(skeleton.muscles[i], who, whichcostume);

	if (skeleton.offset && skeleton.free < 1)
		for (int i = 0; i < skeleton.num_joints; i++) {
			auto& joint = skeleton.joints[i];
			joint.position = joint.oldposition;
		}

	glDisable(GL_LIGHT1);
	return 0;
}