aboutsummaryrefslogblamecommitdiff
path: root/src/GameTick.cpp
blob: 3f42796354d822248e53168bcd161d4ef31fa571 (plain) (tree)
1
2
3
4
5
6
7
8

                                  
                                     


                                          
                                  
                                              














                                                                         
 
                    
 
                 
                 
 
                        
                       
                   
                       
                                  
                     
                         
               
                       
                               
                               
                       
                                  
                              
                 

                     

                     
                             


                         
 






                                              
                          
                            


                                                                  

                                       
                                        

                                       


                                                                             
                                                                        
                                                       
                                                           
         
 
                                                              
                        


                                              


                                                                 

 
                           





                                                    


                                                              
 



                                                   
            
                                            
 



                                                              
 
 
                                                        
 
                         
                                                     






                                                                      
                                

                                                         
                                           
                                                              






                                                             



                                                
                                         


























                                                                                  

                              
                                          
                       
         
 

                                       
 











                                                             
                                           




                                                                    
                                                     








                                                                           

                                                                               






                                                                             

                 


                                                


                               
 












                                                                             

                                                                               






                                                                             

                 



































                                                                                    
                                                        

                                                                                      









                                                                             

                                                                            




                                                                  

                                                                            

                         

         
 
                                               
 












                                                                             
                       



                                                      
 
                                    
                                                                           


                                                      
                                                                              
                                                                               
                                               
 



                                                          


                                                       



                                                                              
         

 
                                        











                                                                      
                         
 
                                                       
                                                                            
                                            
 
                                           






                                       

                                                                    



                                       
                                                           


                                                                  

                      
 
                                         
                                                            
 
 
                             
 
                                    
                                
                               











                                  


                                                    
                                
 
                                              
                                           





                                                                  
                                                      

                                                                    
                          
                                                                      
                                                                               
                                          

 





























                                                                      

















































































                                                                                                                                 

                         

                                                         




                                                                            

                                                              




                                                                  

                              


                                                                             












                                                                                
                   

                                                        

                                    



                                                                

                                      




                                                               

                          




                                                           

                      




                                                               
                      


























                                                                              



































































                                                                           




                                                   


                                                              
























                                                                         
                                

                                       


                                                                



























                                                                                        

                                      
                                                
                                     








                                                                                 






















                                                                 










































                                                         





                                        
                                                                  



































                                                                         


















                                               
                     




                                                          

                      
                                                           

                                                        






                                                                  
                             


































                                                                                        
                                                                  



                                                                         
                                                                








                                                                           

                 


                                                                             
                                            
 

                                
 

                                                                   
 

                                             
                                                     
 
                                 
                               
         
 
                       
                          
                         
 
                 
                              
                                                             
                                                            
 
                                
                         
                                           
 
                                         
                        
                        
                 
                     
                       
                      
                                                                      
 


                                                  
 




                                  



                       
                                                
                               
                              
                                               
                                        
                                               
 
                                               
 






                                                                                


                                                                               

                                                                                                        




                                                                              
 




                                                                                                               
 
                                                                                                                                                                     













                                                                                                                      
 





                                                                                                                                      
                                                         











                                                                                                                      
                                                 
                                         
 



                                                                                  


                                                                                             


                                                                        




                                                                                 
 

                                                                                  
 


                                                                                         








                                                                                               





                                                                                                                          



                                                                                                                         





                                                                                                                                                                                                                                                    



                                                                                                                         




                                                                                 
 


                                                                                           


                                                 
 
                                                   
                                                                                                                        
                                                               
                                                                                                                     










                                                                                                                       
                                                                                                  





















                                                                                                                                                   
                                                              


                                                                                     
 


                                                                                                





                                                                                                                    




                                                                                                                                                                                                                               


                                                                                                 
                                                 
 


                                                                                                





                                                                                                                    




                                                                                                                                                                                                                               


                                                                                                 
                                                 
 


                                                                                                          








                                                                                               
                                                                                      
                                                                                              
                                                                                                                               
 

                                                                                                                        





                                                                                                                         




                                                                                                                                                                                                                                             



                                                                                                                         



                                                                                 
                                                          
                                                 
 

                                                                           



                                                                                         
 




                                                                                                                        


                                                                                                                                          
 
                                                                                                                     
 

                                                                                       







                                                                                               
                                                                                      
                                                                                              
                                                                                               


                                                                                                        





                                                                                                                                                                                                              
                                                          

                                                         

                                                                                                                                       
                                                                                                          
                                                                  
 
                                                                                                  
                                                                                           
                                                                  
 
                                                                                                 



                                                                                                            
                                                                                                          
                                                                                                                                          


                                                                                                                                                  
 
                                                                                                                                              
 
                                                                                           
 
                                                                                                                    
 
                                                                                                                                                                    
 
                                                                                                                                                                                                       
 

                                                                                      
 



                                                                                                        
 



                                                                                                             
 



                                                                                                            
 



                                                                                                      
 
                                                                                                                                                                
                                                                                                                  
 





                                                                                                                                                                            

                                                                                                                           


                                                                                                                
 




                                                                                                                                                        

                                                                                                                                         


                                                                                                                                                                     

                                                                                                                                                                                         






                                                                                                                                                           
                                                                                         
                                                                                 
                                                                         
                                                                                                                              

                                                                  
 

                                                                                                                                       
                                                                                                                
                                                                  
 
                                                                                                  
                                                                                           
                                                                  
 
                                                                                                 


                                                                                                            
 
                                                                                                                                              
 
                                                                                                                                                               


                                                                                                                      

                                                                                                                          
                                                                                                                              
                                                                  
                                                         
 
                                                                                                                            

                                                                                                                                                                
                                                 
                                         
 
                                                                                                                 
                                                                                                                   

                                                                                                                     
                                         
                                 
                         
 

                                                                                                         
                                                                                        
                                                                                                                         
 


                                                            

                                                          
 







                                                                                                                    
                                 
                         
                  
 
                          


                                                                                                                        
 




                                                                              
                                                       
 



                                                                                                                                                                                                                                        
                                                  
 

                                                                       
 
                                                           

                                                                                                           

                                                                                                      

                 














                                                                                                                  


                                                                                    
 
                                          

                                                                                         



                                                                                              
                                                      

                                                                                                   
                                                              

                                                                                                                                                        
                         
                 
         
 
                                           

                                                                   
 

                                                      


                                                                         
                                         
         
 


                         





                                 
 







                                                           
                                                 
                           
                                                                      










                                                                        
 




                                                                  
 




                                                                   
 
                                                                                      
                                 

                                                                 
                                                                   
 
                                                   

                                     
 


                                                          
 


                                                                   
 
                                                    

                                
                                                      
                                       
                                                      

                                             
                                             
 



                                                     
                                                      

                                      
                                                    
                         



                                                                                          





                                                                             















                                                                  
                         
 














                                                                                       
                                                                                            

                                                                    
                                 


                                                         















                                                                              
                                 


                                                                        
                         
 
                                                     

                                             
 
                                                          
 
                                        
 
                                            
 
                                                             
 
                                                                                   
 
                                                                                                               
 
                                                                            
                                                                                                             
                                                                                               
                                                                                              
                                                                                     
                                                                                        
                                                                           
                                                         
                                                 
                                         
                                 
 

                                             
                                                                                                  
 
                                                     
 
                                                                                                  
 
                                                     
 
                                                                                                
 
                                                                       
 
                                                                                                
 
                                                                       
 
                                                            
 
                                                  
                                                             
                                                                      
                                                                                                                    
                                                                                                                                          
 
                                                                 
 
                                                                    
 
                                                                    
 
                                                                             
 
                                                                                                                                               
 
                                                                     
 
                                                                                          
 
                                                                         
 
                                                                                      
 
                                                                                                                                
                                                 
                                         
                                                                                       
 
                                                                                            
 
                                                 
                                                  
                                                    
                                                             
                                                         

                                                                     
                                                      
                                 
 
                                         
 
                                                           
                                                                                   
 
                                                                                                
 
                                                                                                
 
                                                                                                 
 
                                                                                                 
 
                                                                                          
 
                                                                                             
 
                                                                                   
 
                                                                                                
 
                                                                                                
 
                                                        
 
                                                                                                           
 
                                                               
 
                                                                           
 
                                         
 
                                 
 
                                        
 
                                                 
 
                                             
 
                                                                      
 
                                                                        
 
                                                        
 
                                                           
 
                                         
 
                                                                               
 
                                                                                                  
 
                                                                                               
 
                                         
 
                                                                               
 
                                                           
 
                                         
 





                                                                                           
 
                                                                                                        
 
                                                                                                                                           
 
                                                                         
 
                                                                                                                  
 
                                                                                                                  
 
                                                                                        
 
                                         
 
                                                                                                    
 
                                                                                                                                       
 
                                                                                                             
 
                                                                                                   
 
                                                                                  
 
                                                                                                                  
 
                                                                                                                  
 
                                                                                        
 
                                         
 
                                                                                                                     
 
                                                                            
 
                                         
 
                                                                                                             
 
                                                                                                            
 






                                                                                                                             
                                                                                                         
                                                                                        
                                         
 
                                                                    
 
                                                                       
 
                                                                                   
 
                                                                                      
 
                                                                                         
 
                                                                    
 




                                                                                                                                                   


                                                                                                   
                                                         
                                                 
 
                                                                                                      
                                                                                                                       


                                                                                                                         
                                                         
                                                 
                                         
 
                                                                      
 



                                                                                                            
                                                                                                                                               
 
                                                                                                                                                 
 
                                                                                                                                                     
 
                                                                                                                                                                                                                                                                  
 
                                                                                                                                                                                                                                                             
 
                                                                                                                                                                                                                                                            
 
                                                                                                                                                                                                                                                       
 
                                                                                       
 
                                                                                  
 
                                                 
 
                                                                                   
 
                                                                                                      


                                                                                                                                                



                                                                                                                                 
                                                         
                                                                                      
                                                                                                           
                                                 
                                         
 
                                                                                                              
 
                                                                                      
 
                                                                                                                                                                           
                                                                                                              







                                                                                                                                                    
                                                                                                                 
                                                                                                           
                                                                                                       
                                                                                                                       
                                                                                                                        
                                                                 
                                                         
                                                 
                                         
 
                                                     
 
                                                        
 
                                               
 
                                                                                      
 
                                                                                                                                                                 
 
                                                                                                                                                                             
 
                                                                                                                                                             
 
                                                                                                                                                                         
 
                                                                                                                                                                  
 
                                                                                                                                                                              
 
                                                                                                                                                              
 
                                                                                                                                                                          
 
                                                                                                                                                              
 
                                                                                                                                                                          
 
                                              
 
                                                                                                                                        
 
                                                                                                                                         
 
                                                                                                                                          
 
                                         
 
                                                                                  
                                                                                  
                                                                    
                                                                      
 




                                                                                                 

                                                                                          
 
                                            
                                                         
 
                                                                                                                                    
 
                                                     
 
                                                        
 
                                                           
 
                                                                            
 
                                                                                                                         
 
                                                                                                                             
 
                                         
 
                                                                        
 
                                                                                                                        
 
                                                                                                                              
 
                                         
 
                                                                             
 
                                                                                                                        
 
                                                                                                                             
 
                                         
 
                                                                         
 
                                                                                                                        
 
                                                                                                                             
 
                                         
 
                                                                         
 
                                                                                                                        
 
                                                                                                                             
 
                                         
 


                                                                                       
                                 
 
                                                  
                                                   
                                                        
 
                                                                                                                                                                                        
 
                                                                                                                                                       
 
                                                                                                                                                   
 
                                                                                                                               
 











                                                                           
 




                                                                                                        
 
                                             
                                                                             

                                                                                   

                                                                                       
                                 


                         
 
                                 
                                  
 
              
                              
                                                           
                                                    
                                                 
                                      
                                           

                                                       
                                                                                  
         
 
                                                           
                                                    
                                                   
                                      
                                           

                                                              
                                                                                   
         
 












                                                                   
 
                                    
                                                      










                                                                                                                                                                                  
                                                                             



                                                                                               
                                                                                    







                                                                                             
                                 
 
                                                                      

                                                                 
 




                                                               
 





                                                                                                                                                       

                                         
                                                                                              
                                                                                    








                                                                                             

                                 
 
                                                                      

                                                                 
 

                                                                  








                                                                                                                                           
                                                                                    




                                                                                 
 


















                                                                                                                                       
 

                                                                                                  
 








                                                                                                              
 
                                                                                               


                                                                                                                                         



                                                                                                                                                                                         
                                                                                       
                                                                                                           
                                                         
                                                 
                                         
                                 
                         

                                                                   
 

































                                                                                                                                                    
 





                                                                                                                      
 

                                                       





                                                                                                    



                                                                                   
 

                                                                      
 




                                                                                                        


                                                                      
 

















                                                                                                                            
 

                                                                               
                                                                                                   






                                                                                                          
                                                                         






                                                                                                                                             
                                         
                                 
                         
                 
         
 


                                       
 

                         
 
                                                                                                                                                                  
 
                                                                      
 
                                                                                                                                              
 
                                                                              
 
                    
 
                                                     
 



                                            
 






                                                                           
                         
 
                                                     
                                                                     

                                                                       
                         
                                                  
                 

                                                     
 


                                            














                                                                         
                 
         
 


                                           
                                  

                          
 
// Game tick handling
// Copyright (C) 2002  David Rosen
// Copyright (C) 2003  Ryan C. Gordon
// Copyright (C) 2003  Dan Olson
// Copyright (C) 2003  Steven Fuller
// Copyright (C) 2003  Zachary Jack Slater
// Copyright (C) 2003  Toby Haynes
// Copyright (C) 2021-2022  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 <algorithm>

#include "Game.h"
#include "misc.h"

extern float multiplier;
extern int thirdperson;
extern int visions;
extern Sprites sprites;
extern unsigned int gSourceID[37];
extern Camera camera;
extern float camerashake;
extern Fog fog;
extern int environment;
extern float precipitationhorz;
extern float precipitationvert;
extern float snowdelay;
extern float precipitationdensity;
extern float soundscalefactor;
extern int slomo;
extern Decals decals;

#define maxfallvel 40

void Splat(Game* game, int k)
{
	if (k && visions)
		return;

	auto& person = game->person[k];
	if (person.velocity.y > -maxfallvel) {
		person.velocity.y = 0;
		return;
	}

	auto& skeleton = person.skeleton;
	skeleton.free = 1;
	skeleton.offset = 0;
	person.health = 0;
	person.longdead = person.bleeding = person.bleeddelay = 1;
	person.DoAnimations(k);

	auto& joints = skeleton.joints;
	auto& head_joint = joints[head];
	person.bjoint1 = &head_joint;
	person.bjoint2 = joints + neck;

	for (auto& joint : joints) {
		joint.position = DoRotation(joint.position + joint.offset, 0,
			person.playerrotation, 0) + person.playercoords;
		joint.realoldposition = joint.position;
		joint.velocity = {0, person.velocity.y, 0};
	}

	auto soundpos = head_joint.position - camera.position;
	ALfloat gLoc[] {
		soundpos.x / soundscalefactor,
		soundpos.y / soundscalefactor,
		soundpos.z / soundscalefactor,
	};
	alSourcefv(gSourceID[headwhacksound], AL_POSITION, gLoc);
	alSourcePlay(gSourceID[headwhacksound]);
}

void updateSong(Game* game)
{
	if (environment == rainy_environment)
		alSourcePlay(gSourceID[rainsound]);
	else
		alSourcePause(gSourceID[rainsound]);

	alSourceStop(gSourceID[game->whichsong]);
	alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 0);
	alSourcef(gSourceID[game->whichsong], AL_MAX_GAIN, 0);

	if (game->type == zombie_type)
		game->whichsong = zombiesong;
	else if (game->person[0].whichgun == knife)
		game->whichsong = knifesong;
	else
		game->whichsong = shootsong;

	alSourcef(gSourceID[game->whichsong], AL_PITCH, 1);
	alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 1);
	alSourcef(gSourceID[game->whichsong], AL_MAX_GAIN, 1);
	alSourcePlay(gSourceID[game->whichsong]);
}

void click(Game* game, int button, int action, int mods)
{
	if (game->menu) {
		if (button != GLFW_MOUSE_BUTTON_LEFT)
			return;
		double xpos, ypos;
		auto window = glfwGetCurrentContext();
		glfwGetCursorPos(window, &xpos, &ypos);
		double mousex = xpos * 640 / game->screenwidth;
		double mousey = 480 - ypos * 480 / game->screenheight;

		auto button = 0;
		if (mousex > 120 && mousex < 560) {
			if (mousey > 235 && mousey < 305)
				button = 1;
			else if (mousey > 112 && mousey < 182)
				button = 2;
		}
		if (action == GLFW_PRESS) {
			game->mouseoverbutton = button;
			return;
		} else if (button != game->mouseoverbutton) {
			game->mouseoverbutton = 0;
		}

		switch (game->mouseoverbutton) {
		case 1:
			updateSong(game);
			game->flashr = game->flashg = game->flashb = 1.0f;
			game->flashamount = 1.0f;
			alSourcePlay(gSourceID[soulinsound]);

			if (!game->gameinprogress) {
				game->mission = 0;
				initGame(game);
			}

			if (visions)
				alSourcePlay(gSourceID[visionsound]);

			game->gameinprogress = true;
			setMenu(game, false);
			break;
		case 2:
			if (game->gameinprogress) {
				game->flashr = game->flashg = game->flashb = 1.0f;
				game->flashamount = 1.0f;
				game->gameinprogress = false;
			} else {
				game->flashamount = game->flashr = 1.0f;
				game->flashg = game->flashb = 0.0f;
				glfwSetWindowShouldClose(window, true);
			}

			alSourcePlay(gSourceID[losesound]);
			break;
		}
		game->mouseoverbutton = 0;
		return;
	}

	auto& player = game->person[0];
	auto& weapon = player.whichgun;

	if (visions) {
		if (action == GLFW_PRESS)
			alSourcePlay(gSourceID[soulinsound]);
		return;
	}

	XYZ facing {0, 0, -1};
	facing = DoRotation(facing, -camera.rotation2, 0, 0);
	facing = DoRotation(facing, 0, -camera.rotation, 0);

	XYZ flatfacing = facing;
	flatfacing.y = 0;
	flatfacing = normalize(flatfacing);

	// Gun whacking or knife slashing
	if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS
	    && player.attackframe < 0
	    && (!player.aiming || player.ammo <= 0
	        || weapon == nogun || weapon == knife
	        || player.targetanimation == joganim)
	    && player.targetanimation != diveanim
	    && player.targetanimation != throwanim) {
		bool attacking = false;
		float closedistance = 0.0f;
		for (int i = 1; i < game->numpeople; ++i) {
			auto& person = game->person[i];
			if (person.type == viptype || person.skeleton.free)
				continue;
			auto distance = sqrlen(player.playercoords + flatfacing
				- person.playercoords);
			if (distance > 12 + (weapon == knife) * 10)
				continue;
			if (closedistance == 0 || distance < closedistance) {
				attacking = true;
				player.killtarget = i;
				closedistance = distance;
			}
		}

		if (attacking) {
			player.attacktarget = 0;
			player.attackframe = 0;
			return;
		}
	}

	// Disarming
	if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS
	    && player.attackframe < 0
	    && (!player.aiming || weapon == nogun || weapon == knife)
	    && (player.targetanimation == idleanim
	        || player.targetanimation == walkanim
	        || player.targetanimation == joganim)) {
		bool attacking = false;
		float closedistance = 0.0f;
		for (int i = 1; i < game->numpeople; ++i) {
			auto& person = game->person[i];
			if (person.skeleton.free || person.whichgun == nogun)
				continue;
			auto distance = sqrlen(player.playercoords + flatfacing
				- person.playercoords);
			if (distance > 12)
				continue;
			attacking = true;
			if (closedistance == 0 || distance < closedistance) {
				player.killtarget = i;
				closedistance = distance;
			}
		}

		if (attacking) {
			auto& target = game->person[player.killtarget];
			weapon = target.whichgun;
			player.ammo = target.ammo;
			player.aiming = true;
			target.whichgun = nogun;
			target.killtarget = -1;

			target.targetframe = player.targetframe = 0;
			target.targetanimation = player.targetanimation = throwanim;
			target.target = player.target = 1;
			target.playercoords = player.playercoords;
			target.playerrotation = player.playerrotation;
			target.speed = player.speed = 1;
			target.speedmult = 1;
			game->score += 150;
			return;
		}
	}

	// Pulling gun trigger
	if (player.aiming && player.targetanimation != joganim
	    && weapon != nogun && weapon != knife && weapon != grenade) {
		if (button == GLFW_MOUSE_BUTTON_RIGHT && weapon == sniperrifle)
			game->zoom = action == GLFW_PRESS;
		else if (button == GLFW_MOUSE_BUTTON_LEFT)
			player.firing = action == GLFW_PRESS;
		else if (button == GLFW_MOUSE_BUTTON_MIDDLE && game->debug)
			player.firing = player.grenphase = action == GLFW_PRESS;
		return;
	}

	// Grenade
	if (weapon == grenade && player.ammo > 0
	    && player.reloading <= 0 && player.attackframe < 0) {
		auto& skeleton = player.skeleton;
		auto& hand = skeleton.joints[righthand];
		auto soundsrc = DoRotation(hand.position, 0, player.playerrotation, 0)
			+ player.playercoords - camera.position;
		if (player.grenphase) {
			if (button == GLFW_MOUSE_BUTTON_LEFT
			    && action == GLFW_RELEASE) { // throw
				player.grenphase = false;
				player.attackframe = 0;
				player.attacktarget = 0;
				player.killtarget = 0;
			} else if (button == GLFW_MOUSE_BUTTON_RIGHT
			           && action == GLFW_PRESS) { // put pin back
				player.grenphase = false;
				playSound(gSourceID[pinreplacesound],
					soundsrc.x, soundsrc.y, soundsrc.z);
			}
		} else {
			if (button == GLFW_MOUSE_BUTTON_LEFT
			    && action == GLFW_PRESS) { // pull pin
				player.grenphase = true;
				playSound(gSourceID[pinpullsound],
					soundsrc.x, soundsrc.y, soundsrc.z);
			}
		}
	}
}

void look(Game* game, double xpos, double ypos)
{
	if (game->menu)
		return;

	int width, height;
	const auto window = glfwGetCurrentContext();
	glfwGetWindowSize(window, &width, &height);
	int xcenter = width / 2, ycenter = height / 2;
	glfwSetCursorPos(window, xcenter, ycenter); // we shouldn't need this

	auto& player = game->person[0];
	auto factor = game->mouse_sensitivity;
	if (player.aimamount >= 1)
		factor *= (game->zoom) ? 0.05 : 0.8;
	if (slomo == 2)
		factor *= 0.6;

	camera.rotation += (xpos - xcenter) * factor;
	camera.rotation2 += (ypos - ycenter) * factor;

	// Smoothen camera movements
	camera.rotation = camera.rotation * 0.7 + camera.oldrotation * 0.3;
	camera.oldrotation = camera.rotation;
	player.playerrotation = 180 - camera.rotation;

	camera.rotation2 = camera.rotation2 * 0.7 + camera.oldrotation2 * 0.3;
	camera.rotation2 = std::min(std::max(camera.rotation2, -89.0f), 89.0f);
	camera.oldrotation2 = camera.rotation2;

	if (game->zoom || visions || player.aimamount <= 0
	    || player.whichgun == nogun
	    || player.whichgun == grenade
	    || player.whichgun == knife) {
		camera.visrotation = camera.rotation;
		camera.visrotation2 = camera.rotation2;
	} else {
		camera.visrotation = std::min(camera.rotation + 7,
			std::max(camera.rotation - 7, camera.visrotation));
		camera.visrotation2 = std::min(camera.rotation2 + 15,
			std::max(camera.rotation2 - 15, camera.visrotation2));
	}
}

void setListener(Game* game, XYZ facing)
{
	XYZ upvector {0, 0, -1};
	upvector = DoRotation(upvector, -camera.rotation2 + 90, 0, 0);
	upvector = DoRotation(upvector, 0, -camera.rotation, 0);

	ALfloat ori[] {
		facing.x, facing.y, facing.z,
		-upvector.x, upvector.y, upvector.z,
	};
	alListenerfv(AL_ORIENTATION, ori);
}

XYZ aimPlayer(Game* game)
{
	auto& joints = game->person[0].skeleton.joints;
	auto point = joints[lefthand].position - joints[righthand].position;
	float aimrot = 0.0f, aimrot2 = 0.0f;

	switch (game->person[0].whichgun) {
		case assaultrifle:
			aimrot = -2.5f;
			break;
		case sniperrifle:
			aimrot = 4.0f;
			break;
		case shotgun:
			aimrot = randInt(-1000, 1000) / 500.0f - 1;
			aimrot2 = randInt(-1000, 1000) / 500.0f + 2;
			break;
		case handgun1:
		case handgun2:
			aimrot = -0.9f;
			auto k = thirdperson ? 0.35 : 0.65;
			point = joints[righthand].position
				- joints[head].position * k
				- joints[neck].position * (1 - k);
		break;
	}

	return DoRotation(point, aimrot2,
		game->person[0].playerrotation + aimrot, 0);
}

XYZ aimBot(Game* game, int j)
{
	auto& bot = game->person[j];
	float inaccuracy = 0.0f;
	switch (bot.whichgun) {
	case handgun1:
	case handgun2:
		inaccuracy = 8.0f;
		break;
	case assaultrifle:
	case shotgun:
		inaccuracy = 6.0f;
		break;
	case sniperrifle:
		inaccuracy = 2.0f;
		break;
	}

	auto& target = game->person[bot.killtarget];
	if (target.skeleton.free)
		inaccuracy *= 3;

	auto& joints = target.skeleton.joints;
	XYZ aim = joints[abdomen].position;
	if (target.skeleton.free)
		inaccuracy *= 3;
	else
		aim = DoRotation(aim, 0, target.playerrotation, 0)
			+ target.playercoords;

	auto& lefthandpos = joints[lefthand].position;
	aim -= bot.playercoords
		+ DoRotation(lefthandpos, 0, bot.playerrotation, 0);
	return DoRotation(
		DoRotation(DoRotation(aim, 0, -bot.playerrotation, 0),
			randFloat() * inaccuracy, randFloat() * inaccuracy, 0),
		0, bot.playerrotation, 0);
}

void nextLevel(Game* game)
{
	game->score += ++game->mission * 50 + 100;
	game->highscore = std::max(game->score, game->highscore);

	game->flashamount = game->flashg = 1;
	game->flashr = game->flashb = 0;
	alSourcePlay(gSourceID[souloutsound]);

	if (game->mission >= game->nummissions) {
		alSourcePause(gSourceID[rainsound]);
		alSourceStop(gSourceID[visionsound]);
		alSourceStop(gSourceID[game->whichsong]);
		alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 0);
		alSourcef(gSourceID[game->whichsong], AL_MAX_GAIN, 0);

		game->whichsong = mainmenusong;
		alSourcef(gSourceID[game->whichsong], AL_PITCH, 1);
		alSourcef(gSourceID[game->whichsong], AL_MIN_GAIN, 1);
		alSourcef(gSourceID[game->whichsong], AL_MAX_GAIN, 1);
		alSourcePlay(gSourceID[game->whichsong]);

		setMenu(game, game->beatgame = true);
		game->gameinprogress = 0;
	} else {
		updateSong(game);
		initGame(game);
	}
}

void checkPersonCollisions(Game* game, int k)
{
	auto& person = game->person[k];
	person.oldplayercoords = person.playercoords;
	person.DoStuff(k);
	if (person.skeleton.free)
		return;

	person.onground = false;
	auto overpoint = person.playercoords;
	overpoint.y += 3000;
	auto underpoint = person.playercoords;
	underpoint.y -= 3000;

	const int x = (person.playercoords.x + block_spacing / 2) / block_spacing;
	const int z = (person.playercoords.z + block_spacing / 2) / block_spacing;
	const int endx = std::min(num_blocks - 1, x + 1);
	const int endz = std::min(num_blocks - 1, z + 1);
	/* TODO: huh?
	 * if(k!=0) {
	 * 	beginx == person.whichblockx;
	 * 	beginz == person.whichblocky;
	 * 	endx == person.whichblockx;
	 * 	endz == person.whichblocky;
	 * }
	 */

	for (auto i = std::max(0, x); i <= endx; ++i)
		for (auto j = std::max(0, z); j <= endz; ++j) {
			// Ground collision
			const auto city_rot = game->cityrotation[i][j] * 90;
			const XYZ move = {(float) i * block_spacing,
				0.0f, (float) j * block_spacing};
			XYZ collpoint;
			if (game->sidewalkcollide.LineCheck2(overpoint,
					underpoint, &collpoint, move, city_rot) == -1)
				continue;

			if (person.playercoords.y <= collpoint.y
			    && person.velocity.y <= 0) {
				person.playercoords.y = collpoint.y;
				person.onground = true;
				Splat(game, k);
			}

			if (k != 0)
				continue;
			game->onblockx = i;
			game->onblocky = j;

			// Wall collision
			float depth;
			const auto city_type = game->citytype[i][j];
			for (auto& bound : game->boundingpoints) {
				const auto whichtri = game->blockwalls[city_type].LineCheck3(person.playercoords + bound,
					person.playercoords + bound,
					&collpoint, move, city_rot, &depth);
				if (whichtri == -1)
					continue;
			}
			for (auto& bound : game->boundingpoints) {
				auto pointnum = k + 1;
				if (pointnum > 3)
					pointnum = 0;
				const auto whichtri = game->blockwalls[city_type].LineCheck3(person.playercoords + bound,
					person.playercoords + game->boundingpoints[pointnum],
					&collpoint, move, city_rot, &depth);
				if (whichtri == -1)
					continue;
				person.playercoords += DoRotation(game->blockwalls[city_type].normals[whichtri], 0, city_rot, 0);
			}
		}

	if (person.playercoords.y <= 0) {
		person.onground = true;
		person.playercoords.y = 0;
		Splat(game, k);
		if (k == 0)
			game->onblockx = game->onblocky = -1;
	}
}

void spawnNpc(Game* game)
{
	// Pick a random unfull block close to the player
	int blockspawnx, blockspawny;
	auto block = game->person[0].playercoords / block_spacing;
	auto npc_type = (game->type == zombie_type) ? zombietype
		: randUint(game->evilprobability) ? civiliantype : eviltype;
	auto& vip = game->person[1];
	for (auto i = 0; i < 42; ++i) {
		blockspawnx = block.x + 0.5f + randInt(-1, 1);
		blockspawny = block.z + 0.5f + randInt(-1, 1);
		if ((game->citypeoplenum[blockspawnx][blockspawny]
		     < max_people_block)
		    && (npc_type == civiliantype
		        || blockspawnx != vip.whichblockx
		        || blockspawny != vip.whichblocky))
			break;
	}
	if (game->citypeoplenum[blockspawnx][blockspawny] >= max_people_block
	    || (game->spawndelay -= multiplier) > 0)
		return;

	size_t k = 0;
	if (game->numpeople < max_people)
		k = game->numpeople++;
	else
		for (auto i = 0; i < game->numpeople; ++i) {
			auto p = game->person + randInt(2, game->numpeople - 1);
			if (abs(p->whichblockx - block.x) > 2
			    && abs(p->whichblocky - block.z) > 2) {
				k = p - game->person;
				break;
			}
		}
	if (k == 0)
		return;
	game->citypeoplenum[blockspawnx][blockspawny]++;
	game->spawndelay = 0.1f;
	auto& npc = game->person[k];

	npc.whichblockx = blockspawnx;
	npc.whichblocky = blockspawny;
	npc.whichcostume = casualcostumes + randUint(numcasual);
	switch (npc.type = npc_type) {
	case zombietype:
		npc.aiming = false;
		npc.existing = true;
		npc.pathsize = 1.04;
		npc.speedmult = 0.7f + 0.2f * game->difficulty;
		npc.targetanimation = zombiewalkanim;
		break;
	case civiliantype:
		npc.aiming = false;
		npc.existing = false;
		npc.pathsize = 0.98f + 0.04f * randFloat();
		npc.speedmult = 0.8f + 0.4f * randFloat();
		npc.targetanimation = walkanim;
		break;
	case eviltype:
		npc.aiming = true;
		npc.existing = true;
		npc.pathsize = 1.04;
		npc.speedmult = 1.0f + 0.3f * game->difficulty;
		npc.targetanimation = walkanim;
		break;
	}

	npc.pathnum = -1;
	while (npc.pathnum < 0
	       || npc.pathnum == 1
	       || npc.pathnum >= game->path.vertexNum)
		npc.pathnum = randUint(game->path.vertexNum);
	npc.oldoldoldpathnum = npc.oldoldpathnum = npc.oldpathnum = -1;

	npc.pathtarget.x = game->path.vertex[npc.pathnum].x;
	npc.pathtarget.z = game->path.vertex[npc.pathnum].z;
	npc.pathtarget *= npc.pathsize;
	npc.pathtarget.x += npc.whichblockx * block_spacing;
	npc.pathtarget.z += npc.whichblocky * block_spacing;
	npc.oldplayercoords =  npc.playercoords = npc.pathtarget;

	npc.skeleton.free = false;
	npc.speed = 1;
	npc.health = npc.maxhealth = 100;
	npc.playerrotation = 0;
	npc.playerrotation2 = 0;
	npc.lastdistancevictim = 200000;
	npc.whichgun = nogun;
	npc.killtarget = (game->enemystate == 2
		&& (npc.type == zombietype || npc.type == eviltype)) ? 1 : -1;
}

void attackCloseRange(Game* game, XYZ flatfacing)
{
	auto& player = game->person[0];
	if ((player.attackframe < 0 || player.currentanimation != joganim)
	    && player.attackframe <= 1 && player.targetanimation != joganim
	    && player.whichgun != nogun && player.whichgun != knife
	    && player.aiming)
		return;
	if (player.killtarget < 2)
		return;
	auto& target = game->person[player.killtarget];
	player.killtarget = 0;
	if (target.skeleton.free)
		return;
	target.skeleton.free = true;
	target.longdead = 1.0f;
	if (target.type == zombietype) {
		target.health -= 200;
		target.maxhealth -= 20;
	} else {
		target.health -= 100;
	}

	for (auto& joint : target.skeleton.joints) {
		joint.position = DoRotation(joint.position,
			0, target.playerrotation, 0);
		joint.position += target.playercoords;
		joint.realoldposition = joint.position;
		joint.velocity = target.velocity;
		joint.velocity.x += randInt(-4, 4);
		joint.velocity.y += randInt(-4, 4);
		joint.velocity.z += randInt(-4, 4);
	}

	auto soundpos = player.playercoords + flatfacing
		- camera.position;
	if (player.whichgun == knife) {
		playSound(gSourceID[knifeslashsound],
			soundpos.x, soundpos.y, soundpos.z);
		target.bjoint1=&target.skeleton.joints[neck];
		target.bjoint2=&target.skeleton.joints[neck];
		target.bleeding=1;
		target.bleeddelay=1;

		player.bjoint1=&player.skeleton.joints[righthand];
		player.bjoint2=&player.skeleton.joints[righthand];
		player.bleeding=1;
		player.bleeddelay=1;

		auto velocity = DoRotation(flatfacing, 0, 70, 0) * 50
			+ player.velocity * 2;
		velocity.y += 30;
		auto sprite_pos = target.playercoords
			+ DoRotation(target.skeleton.joints[neck].position,
				0, target.playerrotation, 0);
		for (auto i = 2; i < 5; ++i)
			sprites.MakeSprite(bloodspritedown,
				0.8f, 1.0f, 0.2f, 0.2f, sprite_pos,
				velocity * (0.5f - 0.1f * i), i);
	} else {
		playSound(gSourceID[headwhacksound],
			soundpos.x, soundpos.y, soundpos.z);
		target.skeleton.joints[head].velocity
			+= DoRotation(flatfacing, 0, 40, 0) * 50
			+ player.velocity * 2;
	}
}

void tackle(Game* game, XYZ flatfacing)
{
	auto& player = game->person[0];
	for (int i = 1; i < game->numpeople; ++i) {
		auto& person = game->person[i];
		if (person.skeleton.free
		    || sqrlen(player.playercoords + flatfacing
		              - person.playercoords) > 22)
			continue;

		float gLoc[] {
			flatfacing.x / soundscalefactor / 2,
			flatfacing.y / soundscalefactor / 2,
			flatfacing.z / soundscalefactor / 2,
		};
		alSourcefv(gSourceID[headwhacksound], AL_POSITION, gLoc);
		alSourcePlay(gSourceID[headwhacksound]);
		person.skeleton.free = true;
		person.longdead = 1;

		for (auto& joint : person.skeleton.joints) {
			joint.position = person.playercoords
				+ DoRotation(joint.position,
					0, person.playerrotation, 0);
			joint.realoldposition = joint.position;
			joint.velocity = player.velocity;
			joint.velocity.x += randInt(-4, 4);
			joint.velocity.y = randInt(-4, 4) - 10;
			joint.velocity.z += randInt(-4, 4);
		}
	}
}

void bleed(Game* game, size_t i)
{
	auto& person = game->person[i];
	if (person.health < 100.0f && person.type != zombietype)
		person.health -= multiplier * 120.0f;

	if (person.health < 0.0f && person.longdead < 0.0f
	    && !person.firstlongdead && person.type != zombietype) {
		int x = person.whichblockx, y = person.whichblocky;
		auto rot = game->cityrotation[x][y] * 90;
		auto overpoint = person.skeleton.joints[abdomen].position;
		overpoint.y += 3000;
		auto underpoint = person.skeleton.joints[abdomen].position;
		underpoint.y -= 3000;
		XYZ temp;
		XYZ move {(float) x * block_spacing, 0.0f, (float) y * block_spacing, };
		auto whichtri = game->sidewalkcollide.LineCheck2(overpoint,
			underpoint, &temp, move, rot);

		XYZ normish {0.0f, 1.0f, 0.0f};
		if (whichtri >= 0) {
			decals.MakeDecal(bloodpool, temp, 12, normish,
				whichtri, &game->sidewalkcollide, move, rot);
		} else {
			temp = person.skeleton.joints[abdomen].position;
			temp.y = -0.5f;
			decals.MakeDecal(bloodpool, temp, 12, normish,
				0, &game->sidewalkcollide, {}, 0);
		}
		person.firstlongdead = true;
		return;
	}

	if (person.bleeding <= 0.0f)
		return;
	person.bleeding -= multiplier;
	person.bleeddelay -= multiplier * 10.0f;
	if (person.bleeddelay > 0.0f)
		return;
	person.bleeddelay = 1.0f;
	XYZ loc = (person.bjoint1->position + person.bjoint2->position) / 2.0f;
	sprites.MakeSprite(bloodspritedown, 0.6f, 1.0f, 0.2f, 0.2f,
		person.skeleton.free ? loc : DoRotation(loc,
			0.0f, person.playerrotation, 0.0f) + person.playercoords,
		{}, person.bleeding * 3.0f);
}

void heal(Game* game, size_t i)
{
	auto& zombie = game->person[i];
	if (zombie.type != zombietype)
		return;
	zombie.maxhealth = std::min(100.0f,
		zombie.maxhealth + multiplier * 2.0f);
	zombie.health = std::min(zombie.maxhealth,
		zombie.health + multiplier * 10.0f);

	float slow = 0.6f, fast = 0.7f + game->difficulty * 0.2f;
	if (zombie.health < 40.0f)
		zombie.speedmult = std::max(slow,
			zombie.speedmult - multiplier * 0.05f);
	else
		zombie.speedmult = std::min(fast,
			zombie.speedmult + multiplier * 0.025f);
	if (zombie.speedmult < slow)
		zombie.killtarget = -1;
	else if (zombie.speedmult > fast)
		zombie.killtarget = 1;
}

void recoil(Game* game, size_t i)
{
	auto& person = game->person[i];
	switch (person.type) {
	case playertype:
		switch (person.whichgun) {
		case shotgun:
			person.recoil -= multiplier * 4;
			break;
		case sniperrifle:
			person.recoil -= multiplier * 2;
			break;
		case handgun1:
		case handgun2:
			person.recoil -= multiplier * 5;
			break;
		case assaultrifle:
			person.recoil -= multiplier * 10;
			break;
		}
		if (!person.aiming || visions)
			game->zoom = false;
		break;
	case eviltype:
		switch (person.whichgun) {
		case shotgun:
		case sniperrifle:
			person.recoil -= multiplier * 1;
			break;
		case handgun1:
		case handgun2:
			person.recoil -= multiplier * 2;
			break;
		case assaultrifle:
			person.recoil -= multiplier * 10;
			break;
		}
		break;
	}
	if (person.recoil < 0)
		person.recoil = 0;
}

void controlZombie(Game* game, size_t i)
{
	auto& zombie = game->person[i];
	if (zombie.type != zombietype)
		return;
	auto& vip = game->person[1];
	if (sqrlen(zombie.playercoords - vip.playercoords) > 20000
	    || zombie.speedmult < 0.7f) {
		zombie.killtarget = -1;
		return;
	} else if (game->enemystate == 2) {
		zombie.killtarget = 1;
	}

	auto& target = game->person[zombie.killtarget];
	if (zombie.targetanimation != zombieeatanim || target.eaten != i)
		return;
	auto& target_joints = target.skeleton.joints;
	target_joints[head].locked = true;
	target_joints[rightshoulder].locked = true;

	auto& zombie_joints = zombie.skeleton.joints;
	target_joints[head].position = zombie.playercoords
		+ DoRotation(zombie_joints[righthand].position,
			0.0f, zombie.playerrotation, 0.0f);
	target_joints[head].velocity = {};
	target_joints[rightshoulder].position = zombie.playercoords
		+ DoRotation(zombie_joints[lefthand].position,
			0.0f, zombie.playerrotation, 0.0f);
	target_joints[rightshoulder].velocity = {};
	target.skeleton.DoConstraints();

	size_t x = zombie.whichblockx, y = zombie.whichblocky;
	auto& collide = game->blocksimplecollide[game->citytype[x][y]];
	XYZ tmp;
	auto rotation = game->cityrotation[x][y] * 90.0f;
	target.skeleton.DoConstraints(&collide, &tmp, rotation);

	target.skeleton.joints[rightshoulder].locked = false;
	target.skeleton.joints[head].locked = false;
	target.longdead = 1.0f;
}

void renderLaser(Game* game)
{
	auto& player = game->person[0];
	if (!player.aiming)
		return;
	switch (player.currentanimation) {
	case walkanim:
	case idleanim:
		break;
	default:
		return;
	}

	XYZ aim;
	float coeff;
	auto& joints = player.skeleton.joints;
	auto& rotation = player.playerrotation;
	switch (player.whichgun) {
	case assaultrifle:
	case shotgun:
		aim = DoRotation(joints[lefthand].position
			- joints[righthand].position,
			0.0f, rotation - 2.5f, 0.0f);
		coeff = 0.15f;
		break;
	case handgun1:
	case handgun2:
		aim = DoRotation(joints[righthand].position
			- joints[head].position * 0.35f
			- joints[neck].position * 0.65f,
			0.0f, player.playerrotation - 0.9f, 0.0f);
		coeff = -0.15f;
		break;
	default:
		return;
	}

	aim = normalize(aim);
	auto& coords = player.playercoords;
	auto start = coords
		+ DoRotation(joints[lefthand].position, 0.0f, rotation, 0.0f)
		+ DoRotation(DoRotation(DoRotation(aim, 0.0f, -rotation, 0.0f),
		                        90.0f, 0.0f, 0.0f),
		             0.0f, rotation, 0) * coeff;
	auto end = start + aim * 1000.0f;

	// Blocks
	int x = coords.x / block_spacing + 0.5f;
	int z = coords.z / block_spacing + 0.5f;
	for (int i = std::max(0, x - 2); i < std::min(num_blocks, x + 3); ++i)
		for (int j = std::max(0, z - 2); j < std::min(num_blocks, z + 3); ++j) {
			XYZ move = {
				(float) i * block_spacing,
				0.0f,
				(float) j * block_spacing,
			};
			XYZ tmp {};
			auto& block = game->blocks[game->citytype[i][j]];
			auto whichtri = block.LineCheck2(start, end,
				&tmp, move, game->cityrotation[i][j]*90);
			if (whichtri != -1)
				end = tmp;
		}
	XYZ tmp {camera.position.x, 0.0f, camera.position.z};
	auto whichtri = game->Bigstreet.LineCheck2(start, end, &tmp, tmp, 0);
	if (whichtri != -1)
		end = tmp;

	// People
	float olddistance = 0.0f;
	int whichhit = -1;
	for (auto i = 1; i < game->numpeople; ++i) {
		auto& person = game->person[i];
		if (sqrlen(coords -  person.playercoords) > 20000)
			continue;
		auto hit = person.BulletCollideWithPlayer(i, start, end);
		if (!hit.collision)
			continue;
		auto distance = sqrlen(start - hit.hitlocation);
		if (distance < olddistance || whichhit == -1) {
			olddistance = distance;
			whichhit = i;
			end = hit.hitlocation;
		}
	}
	sprites.MakeSprite(bulletinstant, 0.4f, 1, 0, 0, start, end, 0.2f);
}

void Game::Tick()
{
	if (person[1].health <= 0 || person[0].health <= 0 || killedinnocent)
		losedelay -= multiplier / 6;
	else
		timeremaining -= multiplier;

	if (timeremaining <= 0)
		nextLevel(this);

	if (losedelay <= 0) {
		score -= (person[murderer].health > 0) ? 200 : 100;

		flashamount = 1;
		flashr = flashg = flashb = 0;
		alSourcePlay(gSourceID[soulinsound]);

		updateSong(this);
		initGame(this);
	}

	spawnNpc(this);
	sprites.DoStuff();
	decals.DoStuff();

	// Facing
	XYZ facing {0, 0, -1};
	facing = DoRotation(facing, -camera.rotation2, 0, 0);
	facing = DoRotation(facing, 0, -camera.rotation, 0);

	XYZ flatfacing = facing;
	flatfacing.y = 0;
	flatfacing = normalize(flatfacing);

	// Check collision with buildings
	int beginx,endx;
	int beginz,endz;
	XYZ move;
	int whichtri;
	XYZ underpoint;
	XYZ overpoint;
	for (auto k = numpeople; k--; checkPersonCollisions(this, k));

	// Camera
	camera.oldposition = camera.position;
	camera.targetoffset = {0.0f, 0.0f, -5.0f};

	XYZ towards;
	XYZ finaltarget;
	XYZ blah;
	int closesttarget = 0;
	float leastdistance = 0.0;
	float tooclose;
	float toofar;

	//People
	for (size_t i = 0; i < numpeople; ++i) {
		bleed(this, i);
		heal(this, i);
		if (!person[i].skeleton.free) {
			recoil(this, i);
			controlZombie(this, i);

			bool realcheck = false;

			// Pathfinding
			if (i > 0 && person[i].targetanimation != getupfrontanim
			    && person[i].targetanimation != thrownanim
			    && person[i].targetanimation != getupbackanim
			    && person[i].currentanimation != getupfrontanim
			    && person[i].currentanimation != getupbackanim) {
				person[i].pathcheckdelay -= multiplier;
				// Realcheck tells us
				// a) we've got close to the end of our path or
				// b) we're moving away from our target
				auto moving_away = sqrlen(person[i].pathtarget - person[i].playercoords)
					> sqrlen(person[i].pathtarget - person[i].oldplayercoords);
				realcheck = (abs(person[i].playercoords.x
						- person[i].pathtarget.x) < 1
					&& abs(person[i].playercoords.z
						- person[i].pathtarget.z) < 1)
					|| moving_away;

				if(person[i].targetanimation==idleanim&&person[i].killtargetvisible==0){
					person[i].targetanimation=walkanim;
					if(person[i].type==zombietype)person[i].targetanimation=zombiewalkanim;
					realcheck=1;
				}

				if((realcheck||((person[i].killtarget>-1&&person[i].type!=civiliantype)&&person[i].pathcheckdelay<=0)||person[i].killtargetvisible)){
					person[i].pathcheckdelay = 1.2f;

					if ((person[i].killtarget == -1
					     || person[i].type == civiliantype)
					    && !person[i].running) {
						person[i].killtargetvisible = 0;
						leastdistance = 2000000;
						for (int j = 0; j < path.vertexNum; j++) {
							person[i].pathtarget.x = path.vertex[j].x;
							person[i].pathtarget.z = path.vertex[j].z;
							person[i].pathtarget.y = path.vertex[j].y;
							person[i].pathtarget *= person[i].pathsize;
							person[i].pathtarget.x += person[i].whichblockx*block_spacing;
							person[i].pathtarget.z += person[i].whichblocky*block_spacing;

							if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance
							    && j != 1 && j != person[i].oldpathnum
							    && j != person[i].oldoldpathnum
							    && j != person[i].oldoldoldpathnum){
								leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget);
								closesttarget = j;
							}
						}

						if (closesttarget >= 0 && closesttarget < path.vertexNum) {
							person[i].oldoldoldpathnum = person[i].oldoldpathnum;
							person[i].oldoldpathnum = person[i].oldpathnum;
							person[i].oldpathnum = person[i].pathnum;
							person[i].pathnum = closesttarget;
							person[i].pathtarget.x = path.vertex[person[i].pathnum].x;
							person[i].pathtarget.z = path.vertex[person[i].pathnum].z;
							person[i].pathtarget *= person[i].pathsize;
							person[i].pathtarget.x += person[i].whichblockx*block_spacing;
							person[i].pathtarget.z += person[i].whichblocky*block_spacing;
						}
					}

					if(person[i].running&&realcheck){
						person[i].killtargetvisible=0;
						person[i].targetanimation=joganim;

						// Dead target?
						if (person[person[i].killtarget].health <= 0)
							person[i].running = 0;

						 person[i].killtarget=1;

						// If pathfind
						if (realcheck) {
						leastdistance = 2000000;
						person[i].lastdistancevictim = 0;
						closesttarget = -1;

						// Check best path
						closesttarget = person[i].pathnum;

						// Check other blocks?
						if (closesttarget == person[i].pathnum) {
							beginx = person[i].whichblockx-2;
							if(beginx<0)beginx=0;
							beginz=person[i].whichblocky-2;
							if(beginz<0)beginz=0;
							endx=person[i].whichblockx+2;
							if(endx>num_blocks-1)endx=num_blocks-1;
							endz=person[i].whichblocky+2;
							if(endz>num_blocks-1)endz=num_blocks-1;
							leastdistance=2000000;

							for (int l = beginx; l <= endx; l++) {
								for (int m = beginx; m <= endx; m++) {
									for (int j = 0; j < path.vertexNum; j++){
										person[i].pathtarget.x = path.vertex[j].x;
										person[i].pathtarget.y = path.vertex[j].y;
										person[i].pathtarget.z = path.vertex[j].z;
										person[i].pathtarget*=person[i].pathsize;
										person[i].pathtarget.x+=l*block_spacing;
										person[i].pathtarget.z+=m*block_spacing;

										if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance
										    && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) > sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords)
										    && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1
										    && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[l][m]) == -1) {
											person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords);
											leastdistance - sqrlen(person[i].playercoords - person[i].pathtarget);
											closesttarget=j;
											finaltarget=person[i].pathtarget;
											person[i].whichblockx=l;
											person[i].whichblocky=m;
										}
									}
									}
								}
							}

						if (closesttarget != -1) {
							person[i].pathnum = closesttarget;
							person[i].pathtarget = finaltarget;
						}
						}
					}

					// Assassin
					if((person[i].killtarget>-1&&person[i].type!=civiliantype)&&!person[i].running){
						// Dead target?
						if(person[person[i].killtarget].health<=0&&person[i].type==eviltype){
							person[i].playerrotation2 = 0;
							person[i].whichgun = nogun;
							person[i].targetanimation = walkanim;
							person[i].lastdistancevictim = 200000;
							person[i].pathnum = -1;
							enemystate = 1;
							person[i].killtarget = -1;
							realcheck = 1;
						}

						if(person[i].type==zombietype&&person[person[i].killtarget].health<=0){
							if(person[person[i].killtarget].eaten!=i){
								person[i].playerrotation2 = 0;
								person[i].targetanimation = zombiewalkanim;
								person[i].lastdistancevictim = 200000;
								person[i].pathnum = -1;
								realcheck = 1;
								person[i].killtarget = -1;
							}

							if(person[person[i].killtarget].eaten == i && person[i].targetanimation != zombieeatanim) {
								person[i].targetanimation = zombieeatanim;
								person[i].targetframe = 0;
								person[i].target = 0;
							}
							enemystate = 1;
						}

						if(person[person[i].killtarget].health>0){
						if(person[person[i].killtarget].skeleton.free){
							person[person[i].killtarget].playercoords=person[person[i].killtarget].averageloc;
						}

						// If pathfind
						if(realcheck){
						leastdistance=2000000;
						person[i].lastdistancevictim=2000000;
						closesttarget=-1;

						//Check best path
						for(int j=0;j<path.vertexNum;j++){
							person[i].pathtarget.x=path.vertex[j].x;
							person[i].pathtarget.z=path.vertex[j].z;
							person[i].pathtarget.y=path.vertex[j].y;
							person[i].pathtarget*=person[i].pathsize;
							person[i].pathtarget.x+=person[i].whichblockx*block_spacing;
							person[i].pathtarget.z+=person[i].whichblocky*block_spacing;

							if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance
							    && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < person[i].lastdistancevictim
							    && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) {
								leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget);
								person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords);
								closesttarget=j;
								finaltarget=person[i].pathtarget;
							}
						}

						leastdistance=2000000;
						for(int j=0;j<path.vertexNum;j++){
							person[i].pathtarget.x=path.vertex[j].x;
							person[i].pathtarget.z=path.vertex[j].z;
							person[i].pathtarget.y=path.vertex[j].y;
							person[i].pathtarget*=person[i].pathsize;
							person[i].pathtarget.x+=person[i].whichblockx*block_spacing;
							person[i].pathtarget.z+=person[i].whichblocky*block_spacing;

							if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance
							    && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < person[i].lastdistancevictim
							    && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) {
								leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget);
								person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords);
								closesttarget=j;
								finaltarget=person[i].pathtarget;
							}
						}

						//Check other blocks?
						if((closesttarget==person[i].pathnum)||closesttarget==-1){
							beginx=person[i].whichblockx-2;
							if(beginx<0)beginx=0;
							beginz=person[i].whichblocky-2;
							if(beginz<0)beginz=0;
							endx=person[i].whichblockx+2;
							if(endx>num_blocks-1)endx=num_blocks-1;
							endz=person[i].whichblocky+2;
							if(endz>num_blocks-1)endz=num_blocks-1;
							leastdistance=2000000;

							for(int l=beginx;l<=endx;l++){
								for(int m=beginx;m<=endx;m++){
									if(l!=person[i].whichblockx||m!=person[i].whichblocky){

									for(int j=0;j<path.vertexNum;j++){
										person[i].pathtarget.x=path.vertex[j].x;
										person[i].pathtarget.y=path.vertex[j].y;
										person[i].pathtarget.z=path.vertex[j].z;
										person[i].pathtarget*=person[i].pathsize;
										person[i].pathtarget.x+=l*block_spacing;
										person[i].pathtarget.z+=m*block_spacing;

										if (sqrlen(person[i].playercoords - person[i].pathtarget) < leastdistance
										    && sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords) < sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords)
										    && j != 1 && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[l][m]) == -1
										    && blocksimple.LineCheck2(person[i].playercoords, person[i].pathtarget, &blah, move, cityrotation[person[i].whichblockx][person[i].whichblocky]) == -1) {
											leastdistance = sqrlen(person[i].playercoords - person[i].pathtarget);
											closesttarget=j;
											finaltarget=person[i].pathtarget;
											person[i].whichblockx=l;
											person[i].whichblocky=m;
										}
									}
									}
								}
							 }
						}

						if(closesttarget!=-1){
							person[i].onpath=1;
							person[i].pathnum=closesttarget;
							person[i].pathtarget=finaltarget;
						}
						}

						//Check killtargetvisible
						person[i].killtargetvisible=1;

						if(person[person[i].killtarget].health<=0)person[i].killtargetvisible=0;

						if (closesttarget != -1
						    && sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) > 30000)
							person[i].killtargetvisible = 0;

						if(person[i].killtarget==0&&visions==1)person[i].killtargetvisible=0;

						if(person[i].killtargetvisible){
							beginx=person[i].whichblockx-2;
							if(beginx<0)beginx=0;
							beginz=person[i].whichblocky-2;
							if(beginz<0)beginz=0;
							endx=person[i].whichblockx+2;
							if(endx>num_blocks-1)endx=num_blocks-1;
							endz=person[i].whichblocky+2;
							if(endz>num_blocks-1)endz=num_blocks-1;

							for(int l=beginx;l<=endx;l++){
								for(int m=beginx;m<=endx;m++){
									move.x=l*block_spacing;
									move.z=m*block_spacing;
									move.y=-3;
									if(person[i].killtargetvisible){
										if(blocksimple.LineCheck2(person[i].playercoords,person[person[i].killtarget].playercoords,&blah,move,cityrotation[l][m])!=-1)
										{
											person[i].killtargetvisible=0;
										}
									}
								}
							 }
							}

							if(person[i].type==eviltype){
								 if(!person[i].killtargetvisible&&person[i].targetanimation==idleanim){
									person[i].targetanimation=joganim;
								 }

								 if(!person[i].killtargetvisible){
									person[i].aiming=0;
								 }

								 if(person[i].killtargetvisible){
									person[i].onpath=0;
									person[i].lastdistancevictim=200000;
									person[i].pathnum=-1;

									if (person[i].whichgun == nogun) {
										person[i].whichgun=possiblegun[randUint(numpossibleguns)];
										person[i].reloads[person[i].whichgun]=1;
										if(person[i].whichgun==knife)person[i].speedmult=.8+.5*difficulty;
									}

									if(person[i].aiming==0)person[i].shotdelay=shotdelayamount/difficulty;

									person[i].aiming=1;

									if(person[i].reloading>0)person[i].aiming=0;

									if(person[i].whichgun==handgun1||person[i].whichgun==handgun2)person[i].playerrotation2=-10;

									if(person[i].whichgun==assaultrifle||person[i].whichgun==sniperrifle||person[i].whichgun==shotgun)person[i].playerrotation2=20;

									tooclose=1300;
									toofar=3000;

									if(person[i].whichgun==shotgun){
										tooclose=1400;
										toofar=5000;
									}

									if(person[i].whichgun==assaultrifle){
										tooclose=5000;
										toofar=9000;
									}

									if(person[i].whichgun==sniperrifle){
										tooclose=10000;
										toofar=20000;
									}

									if(person[i].whichgun==knife){
										tooclose=20;
										toofar=20000;
									}

									if (sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) > toofar)
										person[i].targetanimation=joganim;

									if ((sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) <= tooclose
									     && person[person[i].killtarget].skeleton.free == 0)
									    || (tooclose > 200
									        && sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) <= 200)
									    || (tooclose <= 200
									        && sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) < tooclose)) {
										if(person[i].targetanimation!=idleanim){
											person[i].targetanimation=idleanim;
											person[i].targetframe=0;
											person[i].target=0;
										}

										if(person[i].whichgun==knife&&person[person[i].killtarget].health==100){
											murderer=i;
											person[i].attacktarget=0;
											person[i].attackframe=0;

											if(person[person[i].killtarget].type!=zombietype)
											{
												auto stabpos = person[i].playercoords + flatfacing - camera.position;
												playSound(gSourceID[knifeslashsound],
													stabpos.x, stabpos.y, stabpos.z);
												person[person[i].killtarget].bjoint1=&person[person[i].killtarget].skeleton.joints[neck];
												person[person[i].killtarget].bjoint2=&person[person[i].killtarget].skeleton.joints[neck];
												person[person[i].killtarget].bleeding=1;
												person[person[i].killtarget].bleeddelay=1;
												person[person[i].killtarget].health-=20;
												person[person[i].killtarget].targetanimation=chestpainanim;
												person[person[i].killtarget].targetframe=0;
												person[person[i].killtarget].target=0;
												person[person[i].killtarget].longdead=1;
											}
										}
									}
									finaltarget=person[person[i].killtarget].playercoords;
								 }
							}

							if(person[i].type==zombietype&&person[person[i].killtarget].health>0){
								 if(!person[i].killtargetvisible&&person[i].targetanimation==idleanim){
									person[i].targetanimation=zombiejoganim;
								 }

								 if(!person[i].killtargetvisible){
									person[i].aiming=0;
								 }

								 if(person[i].killtargetvisible){
									person[i].onpath=0;
									person[i].lastdistancevictim=200000;
									person[i].pathnum=-1;

									if(person[i].aiming==0)person[i].shotdelay=shotdelayamount/difficulty;

									if (sqrlen(person[i].playercoords - person[person[i].killtarget].playercoords) <= 20) {
										murderer=i;
										person[person[i].killtarget].health=0;
										person[person[i].killtarget].eaten=i;
									} else if (person[i].targetanimation != idleanim)
										person[i].targetanimation = zombiejoganim;
									finaltarget=person[person[i].killtarget].playercoords;
								 }
							}

						 if(person[i].killtargetvisible||realcheck)person[i].pathtarget=finaltarget;
						if (realcheck)
							person[i].lastdistancevictim = sqrlen(person[i].pathtarget - person[person[i].killtarget].playercoords);
						}
					}

					if(person[i].targetanimation!=zombieeatanim||person[i].type!=zombietype){
						towards = normalize(person[i].playercoords - person[i].pathtarget);
						person[i].playerrotation=asin(0-towards.x)*360/6.28;
						if(towards.z>0)person[i].playerrotation=180-person[i].playerrotation;
					}
				}
			}

			person[i].whichblockx=((person[i].playercoords.x+block_spacing/2)/block_spacing);
			person[i].whichblocky=((person[i].playercoords.z+block_spacing/2)/block_spacing);
			if(!person[i].onground)person[i].velocity.y+=multiplier*gravity;
			if(!person[i].onground&&(i!=0||visions!=1))person[i].playercoords+=person[i].velocity*multiplier;

			//Death by bleeding/shock
			if(person[i].health<=0){
				person[i].skeleton.offset=0;
				person[i].skeleton.free=1;
				person[i].longdead=1;

				for (auto& joint : person[i].skeleton.joints) {
					joint.position += joint.offset;
					joint.position = DoRotation(joint.position, 0, person[i].playerrotation, 0);
					joint.position += person[i].playercoords;
					joint.realoldposition = joint.position;
					joint.velocity = DoRotation(joint.velocity, 0, person[i].playerrotation, 0);
					joint.velocity += person[i].velocity;
					joint.velocity += person[i].facing * 4;
				}
			}
		 }

		//Rag doll
		if(person[i].skeleton.free==1&&person[i].longdead>0){
			person[i].whichblockx=((person[i].skeleton.joints[0].position.x+block_spacing/2)/block_spacing);
			person[i].whichblocky=((person[i].skeleton.joints[0].position.z+block_spacing/2)/block_spacing);

			move = {
				(float) person[i].whichblockx * block_spacing,
				0.0f,
				(float) person[i].whichblocky * block_spacing,
			};
			person[i].skeleton.DoGravity();

			if(person[i].averageloc.y<=50)person[i].skeleton.DoConstraints(&blocksimplecollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90);
			if(person[i].averageloc.y>50)person[i].skeleton.DoConstraints(&blockcollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90);

			person[i].oldaverageloc=person[i].averageloc;
			person[i].averageloc = {};

			for (auto& joint : person[i].skeleton.joints)
				person[i].averageloc += joint.position;

			person[i].averageloc /= max_joints;
			person[i].playercoords=person[i].averageloc;
			if(person[i].longdead<multiplier/2&&person[i].longdead>0)person[i].DrawSkeleton(i);
			if (sqrlen(person[i].averageloc - person[i].oldaverageloc) < 0.2 * multiplier)
				person[i].longdead -= multiplier / 2;
		}

		if(person[i].skeleton.free==1&&person[i].longdead<=0&&person[i].health>0&&person[i].longdead!=-1){
			person[i].longdead=1;
			person[i].skeleton.free=0;
			person[i].currentanimation=lyinganim;
			person[i].target=0;
			person[i].targetframe=0;

			//Get up from front or back?
			if(person[i].skeleton.forward.y>0)
			person[i].targetanimation=getupfrontanim;
			else
			person[i].targetanimation=getupbackanim;

			//Find playercoords
			person[i].playercoords=person[i].averageloc;
			for (auto& joint : person[i].skeleton.joints)
				if (joint.position.y > person[i].playercoords.y)
					person[i].playercoords.y = joint.position.y;

			//Find orientation
			XYZ firsttop = normalize(person[i].skeleton.joints[neck].position
				- person[i].skeleton.joints[groin].position);
			person[i].playerrotation=acos(0-firsttop.z);
			person[i].playerrotation*=360/6.28;
			if(0>firsttop.x)person[i].playerrotation=360-person[i].playerrotation;
			person[i].playerrotation*=-1;
			person[i].playervelocity = {};
			if(person[i].targetanimation==getupfrontanim)person[i].playerrotation+=180;

			for (int j = 0; j < max_joints; ++j) {
				person[i].tempanimation.position[j][0]=person[i].skeleton.joints[j].position-person[i].playercoords;
				person[i].tempanimation.position[j][0]=DoRotation(person[i].tempanimation.position[j][0],0,-person[i].playerrotation,0);
			}
		}
	}

	attackCloseRange(this, flatfacing);
	if (person[0].currentanimation == diveanim && visions == 0)
		tackle(this, flatfacing);

	// Empty magazine
	if (person[0].firing && person[0].ammo <= 0) {
		auto soundpos = person[0].playercoords - camera.position;
		playSound(gSourceID[clicksound],
			soundpos.x, soundpos.y, soundpos.z);
		person[0].firing = false;
	}

	XYZ wallhit;
	XYZ start;
	XYZ finalwallhit;
	int numshots;
	XYZ hitnorm;
	XYZ hitmove;
	int hitpoly = 0;
	float hitrotation = 0.0f;
	Model* model = NULL;

	for (int j = 0; j < numpeople; j++) {
		if (j && person[j].type != eviltype)
			continue;

		if (person[j].ammo <= 0
		    || person[j].reloading > 0
		    || person[j].targetanimation == joganim
		    || person[j].aimamount < 1)
			person[j].firing = false;
		else if (j)
			person[j].firing = person[j].whichgun != nogun
				&& person[j].whichgun != knife
				&& person[j].killtargetvisible
				&& person[j].shotdelay < 0;

		if (j && person[j].killtargetvisible
		    && person[j].whichgun != nogun
		    && person[j].whichgun != knife) {
			person[j].aiming = 1;
			if (person[j].shotdelay > 0)
				person[j].shotdelay -= multiplier * 0.9;
		}

		if (person[j].skeleton.free == 1
		    || person[j].targetanimation == getupfrontanim
		    || person[j].targetanimation == getupbackanim)
			person[j].shotdelay = shotdelayamount
				/ difficulty;

		if (person[j].ammo == 0
		    && person[j].reloads[person[j].whichgun] > 0) {
			person[j].ammo = -1;
			person[j].aiming = 0;
		}

		if (!person[j].firing || person[j].aiming < 1 || person[j].recoil > 0)
			continue;
		if (j != 0 || person[j].whichgun != assaultrifle)
			person[j].firing = false;
		person[j].shotdelay = shotdelayamount / difficulty;

		HitStruct hitstruct, temphitstruct;
		person[j].litup = 1;
		person[j].recoil = 1;

		float olddistance = 0.0f, distance = 0.0f;
		float totalarea = 0.0f;
		int whichhit = -1;

		numshots = (person[j].whichgun == shotgun) ? 7 : 1;
		if (person[j].whichgun != grenade)
			person[j].ammo--;

		for (int p = 0; p < numshots; p++) {
			XYZ aim;
			if (j)
				aim = aimBot(this, j);
			else if (!zoom)
				aim = aimPlayer(this);
			else
				aim = facing;
			aim = normalize(aim);

			int aimjoint;
			switch (person[j].whichgun) {
			case handgun1:
			case handgun2:
				aimjoint = rightwrist;
				break;
			default:
				aimjoint = lefthand;
			}
			start = person[j].playercoords
				+ DoRotation(person[j].skeleton.joints[aimjoint].position,
					0, person[j].playerrotation, 0);

			if (j == 0 && person[j].grenphase) {
				person[j].grenphase = false;
				sprites.MakeSprite(grenadesprite, 1, 1, 1, 1,
					start, aim * 200, 1.01);
			}

			auto startsub = DoRotation(aim,
				0, -person[j].playerrotation, 0);
			startsub = DoRotation(startsub, 90, 0, 0);
			startsub *= DoRotation(startsub,
				0, person[j].playerrotation,0);
			switch (person[j].whichgun) {
			case sniperrifle:
			case shotgun:
				start -= startsub * 0.35f;
				break;
			case handgun1:
			case handgun2:
				start -= startsub * 0.55f;
				break;
			default: // assaultrifle
				start -= startsub * 0.25f;
			}

			if (p == numshots - 1) {
				auto crouch = person[j].currentanimation == crouchanim;
				float rot = 0.0f, rot2 = 0.0f;
				switch (person[j].whichgun) {
				case sniperrifle:
				case shotgun:
					rot2 = crouch ? 3.0f : 7.0f;
					break;
				case handgun1:
					rot2 = crouch ? 4.0f : 6.0f;
					break;
				case handgun2:
					rot2 = crouch ? 3.0f : 5.0f;
					break;
				case assaultrifle:
					rot = randInt(-100, 100) / (crouch ? 60.0f : 50.0f);
					rot2 = crouch ? 1.5f : 2.3f;
					break;
				}
				camera.rotation -= rot;
				camera.rotation2 -= rot2;

				ALuint gunsound;
				switch (person[j].whichgun) {
				case sniperrifle:
					gunsound = gSourceID[riflesound];
					break;
				case shotgun:
					gunsound = gSourceID[shotgunsound];
					break;
				case handgun1:
					gunsound = gSourceID[pistol1sound];
					break;
				case handgun2:
					gunsound = gSourceID[pistol2sound];
					break;
				default: // assaultrifle
					gunsound = gSourceID[machinegunsound];
				}
				auto soundpos = start - camera.position;
				playSound(gunsound, soundpos.x,
					soundpos.y, soundpos.z);
			}

			XYZ end {start + aim * 1000};
			int bulletstrength=1;
			int firstpass=-1;

			for(int m=0;m<bulletstrength;m++){

				//People

				whichhit=-1;

				for(int i=0;i<numpeople;i++){

					if(i!=j&&i!=firstpass&&person[i].existing){

						temphitstruct=person[i].BulletCollideWithPlayer(i, start, end);

						if(temphitstruct.collision){
							distance = sqrlen(start - temphitstruct.hitlocation);
							if(distance<olddistance||whichhit==-1){
								end=temphitstruct.hitlocation;
								olddistance=distance;
								hitstruct=temphitstruct;
								whichhit=i;
							}
						}
					}
				}

				// Blocks
				wallhit = {};
				beginx=(person[j].playercoords.x+block_spacing/2)/block_spacing-3;

				if(beginx<0)beginx=0;

				beginz=(person[j].playercoords.z+block_spacing/2)/block_spacing-3;

				if(beginz<0)beginz=0;

				endx=(person[j].playercoords.x+block_spacing/2)/block_spacing+3;

				if(endx>num_blocks-1)endx=num_blocks-1;

				endz=(person[j].playercoords.z+block_spacing/2)/block_spacing+3;

				if(endz>num_blocks-1)endz=num_blocks-1;

				if(beginx<endx&&beginz<endz)

				finalwallhit = {};
				for(int i=beginx;i<=endx;i++)
					for(int j=beginz;j<=endz;j++){
						move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing};
						whichtri=blocks[citytype[i][j]].LineCheck2(start,end,&wallhit,move,cityrotation[i][j]*90);

						if(whichtri!=-1){

							whichhit=-1;

							end=wallhit;

							finalwallhit=wallhit;

							hitnorm=DoRotation(blocks[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0);

							hitmove=move;

							hitrotation=cityrotation[i][j]*90;

							hitpoly=whichtri;

							model=&blocks[citytype[i][j]];

							if(j==0&&blocks[citytype[i][j]].normals[whichtri].y>.9)bulletstrength=2;
						}
					}
				wallhit = {camera.position.x, 0.0f, camera.position.z};

				whichtri=Bigstreet.LineCheck2(start,end,&wallhit,wallhit,0);

				if(whichtri!=-1){
					end.y-=.5;
					end=wallhit;
					finalwallhit=wallhit;
					bulletstrength=2;
					hitnorm = {0.0f, 1.0f, 0.0f};
					hitmove = {};
					hitrotation=0;
				}

				if(m==0){

					if(j==0&&slomo==2){
						alSourceStop(gSourceID[whichsong]);

						alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 0);

						alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 0);

						if(person[0].whichgun==knife)whichsong=knifesong;

						if(person[0].whichgun!=knife)whichsong=shootsong;

						if(type==zombie_type)whichsong=zombiesong;

						alSourcef(gSourceID[whichsong], AL_PITCH, 1);

						alSourcePlay(gSourceID[whichsong]);

						alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 1);

						alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 1);

						slomo=0;

						if(whichhit==-1)alSourcePlay(gSourceID[disguisekillsound]);

						flashamount=.5;

						flashr=1;flashg=1;flashb=1;

					}

				}

				//Impact

				XYZ oldend {end};

				//with person

				if(whichhit!=-1&&whichhit!=firstpass){

					if(j==0)person[whichhit].dead=1;

					if(whichhit==1){

						murderer=j;

					}

					if(person[whichhit].health==100&&j==0){

						if(person[whichhit].type==civiliantype)civkills++;

						if(person[whichhit].type==eviltype)goodkills++;

					}

					if(person[whichhit].health==100&&j!=0){

						badkills++;

					}

					bool penetrate = (numshots > 1) ? 0 : !randUint(3);
					if (penetrate) {
						bulletstrength = 2;
						firstpass = whichhit;
						end = start + aim * 1000;
					}

					if(person[j].whichgun==assaultrifle)person[whichhit].health-=20;

					if(person[j].whichgun==assaultrifle&&person[whichhit].type==zombietype)person[whichhit].health-=60;

					if(person[j].whichgun==handgun1){

						if(person[whichhit].type!=zombietype)person[whichhit].health-=100;

						if(person[whichhit].type==zombietype)person[whichhit].health-=100;

						person[whichhit].DoAnimations(whichhit);

					}

					if(person[j].whichgun==handgun2)person[whichhit].health-=20;

					if(person[j].whichgun==handgun2&&person[whichhit].type==zombietype)person[whichhit].health-=60;

					if(person[j].whichgun==sniperrifle&&m!=0)person[whichhit].health-=30;

					if(person[j].whichgun==shotgun)person[whichhit].health-=60;

					if(person[j].whichgun==sniperrifle&&m==0){

						if(person[whichhit].type!=zombietype)person[whichhit].health-=100;

						if(person[whichhit].type==zombietype)person[whichhit].health-=120;

						person[whichhit].DoAnimations(whichhit);

					}

					if(hitstruct.joint1->modelnum==headmodel&&person[whichhit].type!=zombietype){

						person[whichhit].health-=60;

					}

					if(person[whichhit].type==zombietype)person[whichhit].speedmult-=.05;

					if(person[whichhit].type==zombietype)person[whichhit].maxhealth-=10;

					if (whichhit == 0) {
						bulletstrength = 1;
						person[0].health = 100;
						flashamount = 1;
						flashr = flashg = flashb = 0;
						auto soundsrc = (hitstruct.hitlocation - camera.position) / soundscalefactor;
						float gLoc[] {soundsrc.x, soundsrc.y, soundsrc.z};
						alSourcefv(gSourceID[bodywhacksound], AL_POSITION, gLoc);
						alSourcePlay(gSourceID[bodywhacksound]);
					}

					person[whichhit].longdead=1;

					if(person[whichhit].health<=0){

						person[whichhit].skeleton.offset=0;

						if(person[whichhit].skeleton.free!=1){

							person[whichhit].skeleton.free=1;

							totalarea=0;

							for (auto& joint : person[whichhit].skeleton.joints) {
								joint.position = DoRotation(joint.position, 0, person[whichhit].playerrotation, 0);
								joint.position += person[whichhit].playercoords;
								joint.realoldposition = joint.position;
								joint.velocity = person[whichhit].velocity;
								joint.velocity.x += randInt(-4, 4);
								joint.velocity.y += randInt(-4, 4);
								joint.velocity.z += randInt(-4, 4);
							}
						}

						for (auto& joint : person[whichhit].skeleton.joints) {
							auto distance = sqrlen(joint.position - hitstruct.hitlocation);
							if (distance < 200) {
								totalarea += 200 / distance;
								joint.velocity += aim * 200 / distance / totalarea * 200;
							}
						}
					}

					if(person[whichhit].health>0){

						if (person[whichhit].killtargetvisible == 0
						    && person[whichhit].type != zombietype
						    && person[whichhit].currentanimation !=getupfrontanim
						    && person[whichhit].currentanimation != getupbackanim) {
							if(hitstruct.joint1->modelnum==headmodel)person[whichhit].targetanimation=headpainanim;

							if(hitstruct.joint1->modelnum==chestmodel)person[whichhit].targetanimation=chestpainanim;

							if(hitstruct.joint1->modelnum==abdomenmodel)person[whichhit].targetanimation=stomachpainanim;

							if(hitstruct.joint1->label==rightelbow||hitstruct.joint1->label==rightshoulder||hitstruct.joint1->label==rightwrist||hitstruct.joint1->label==righthand)person[whichhit].targetanimation=rightarmpainanim;

							if(hitstruct.joint1->label==leftelbow||hitstruct.joint1->label==leftshoulder||hitstruct.joint1->label==leftwrist||hitstruct.joint1->label==lefthand)person[whichhit].targetanimation=leftarmpainanim;

							if(hitstruct.joint1->label==rightknee||hitstruct.joint1->label==righthip||hitstruct.joint1->label==rightankle||hitstruct.joint1->label==rightfoot)person[whichhit].targetanimation=rightlegpainanim;

							if(hitstruct.joint1->label==leftknee||hitstruct.joint1->label==lefthip||hitstruct.joint1->label==leftankle||hitstruct.joint1->label==leftfoot)person[whichhit].targetanimation=leftlegpainanim;

							person[whichhit].targetframe=0;

							person[whichhit].target=0;

						}

						person[whichhit].skeleton.offset=1;

						for (auto& joint : person[whichhit].skeleton.joints) {
							auto distance = sqrlen(DoRotation(joint.position, 0, person[whichhit].playerrotation, 0)
								+ person[whichhit].playercoords
								- hitstruct.hitlocation);
							if(distance < 200) {
								totalarea += 200 / distance;
								joint.offset += DoRotation(aim * 200 / distance / totalarea * 10,
									0, -person[whichhit].playerrotation, 0);
							}
							if (sqrlen(joint.offset) > 36)
								joint.offset = normalize(joint.offset) * 6;
						}
					}

					if(hitstruct.joint1->modelnum==headmodel&&person[whichhit].health<=0){

						for (int j = 0; j < max_joints; ++j) {

							if(&person[whichhit].skeleton.joints[j]==hitstruct.joint1||&person[whichhit].skeleton.joints[j]==hitstruct.joint2){
								if (j != abdomen && j != groin && j != neck) {
									sprites.MakeSprite(bloodspritedown, 0.8f, 1, 0.2f, 0.2f,
										person[whichhit].skeleton.joints[j].position,
										person[whichhit].skeleton.joints[j].velocity / 3, 9);
									for (int tmp = 0; tmp < 4; ++tmp)
										sprites.MakeSprite(bloodspritedown, 0.8f, 1, 0.2f, 0.2f,
											person[whichhit].skeleton.joints[j].position,
											DoRotation(person[whichhit].skeleton.joints[j].velocity / 3,
												randUint(360), randUint(360), 0) / 5, 5);
									person[whichhit].skeleton.DeleteJoint(j);
									person[whichhit].skeleton.broken=1;
									person[whichhit].health=-10000;
									person[whichhit].skeleton.joints[j].existing=0;
									if(person[whichhit].type==zombietype)score+=300;
								}
							}
						}
					}

					XYZ velocity;

					velocity=aim*-8;

					//blood

					if (hitstruct.joint1->modelnum != headmodel) {

					if(person[j].whichgun==sniperrifle)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 5);

					if(person[j].whichgun==sniperrifle&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7);

					if(person[j].whichgun==shotgun)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 5);

					if(person[j].whichgun==shotgun&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7);

					if(person[j].whichgun==assaultrifle)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3);

					if(person[j].whichgun==assaultrifle&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 7);

					if(person[j].whichgun==handgun1)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3);

					if(person[j].whichgun==handgun1&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 4);

					if(person[j].whichgun==handgun2)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*0, 3);

					if(person[j].whichgun==handgun2&&penetrate)sprites.MakeSprite(bloodspritenoup, 1, 1, 0, 0, hitstruct.hitlocation, velocity*-3, 4);

					}else{

						sprites.MakeSprite(bloodspritenoup, 1, 1, .2, .2, hitstruct.hitlocation, velocity*0, 6);

						sprites.MakeSprite(bloodspritenoup, 1, 1, .5, .5, hitstruct.hitlocation, velocity*-2, 7);

						sprites.MakeSprite(bloodspritenoup, 1, 1, .2, .2, hitstruct.hitlocation, velocity*-3, 10);

					}

					person[whichhit].bjoint1=hitstruct.joint1;
					person[whichhit].bjoint2=hitstruct.joint2;
					person[whichhit].bleeding=1;
					person[whichhit].bleeddelay=1;

					auto hitsound = (hitstruct.joint1->modelnum == headmodel)
						? gSourceID[headshotsound]
						: gSourceID[bodyhitsound];
					auto hitpos = hitstruct.hitlocation
						- camera.position;
					playSound(hitsound, hitpos.x, hitpos.y, hitpos.z);
				}

				// with wall
				if(oldend==finalwallhit){

					decals.MakeDecal(bullethole, finalwallhit,.7,hitnorm, hitpoly, model, hitmove, hitrotation);

					XYZ velocity;

					velocity=aim*-4;

					velocity=hitnorm*3;

					if(person[j].whichgun==sniperrifle){

						sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 10);

						sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 2);

					}

					if(person[j].whichgun==shotgun){

						sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 5);

						sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, .8);

					}

					if(person[j].whichgun==assaultrifle){

						sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6);

						sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1);

					}

					if(person[j].whichgun==handgun1){

						sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6);

						sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1);

					}

					if(person[j].whichgun==handgun2){

						sprites.MakeSprite(smokesprite, .4, 1, 1, 1, finalwallhit, velocity, 6);

						sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, finalwallhit, velocity, 1);

					}

					auto soundpos = finalwallhit - camera.position;
					playSound(gSourceID[wallhitsound],
						soundpos.x, soundpos.y, soundpos.z);
				}

				lastshot[0]=start;
				lastshot[1]=oldend;
				auto velocity = aim * 8;

				if(person[j].whichgun!=sniperrifle&&person[j].whichgun!=shotgun&&p==numshots-1)sprites.MakeSprite(smokesprite, .3, 1, 1, 1, start+aim*1.5, velocity, 3);

				if(person[j].whichgun==shotgun&&p==numshots-1)sprites.MakeSprite(smokesprite, .4, 1, 1, 1, start+aim*1.5, velocity, 5);

				if(person[j].whichgun==sniperrifle&&!zoom)sprites.MakeSprite(smokesprite, .3, 1, 1, 1, start+aim*2.2, velocity, 4);

				if(j!=0||zoom==0)sprites.MakeSprite(bullet, .07, 1, 1, .7, lastshot[0]+aim*1, lastshot[1], .2);

				// Nearby bullet whoosh
				XYZ* a = &lastshot[0];
				*a += aim;
				XYZ* b = &lastshot[1];
				XYZ* c = &camera.position;
				XYZ nearest {};
				long dot_ta = (c->x - a->x) * (b->x - a->x)
					+ (c->y - a->y) * (b->y - a->y)
					+ (c->z - a->z) * (b->z - a->z);
				long dot_tb = (c->x - b->x) * (a->x - b->x)
					+ (c->y - b->y) * (a->y - b->y)
					+ (c->z - b->z) * (a->z - b->z);

				if (dot_ta > 0 && dot_tb > 0) {
					nearest.x = a->x + ((b->x - a->x) * dot_ta) / (dot_ta + dot_tb);
					nearest.y = a->y + ((b->y - a->y) * dot_ta) / (dot_ta + dot_tb);
					nearest.z = a->z + ((b->z - a->z) * dot_ta) / (dot_ta + dot_tb);
				}

				if (nearest.x
				    && sqrlen(nearest - camera.position) < 10
				    && (thirdperson == 2 || j != 0)) {
					auto nearsound = nearest - camera.position;
					playSound(gSourceID[nearbulletsound],
						nearsound.x, nearsound.y, nearsound.z);
				}
			}
		}
	}

	if (thirdperson && !zoom)
		renderLaser(this);

	//Snow
	snowdelay-=multiplier;
	while(snowdelay<0&&environment==snowy_environment){
		snowdelay+=1/precipitationdensity*2;
		XYZ velocity {0.0f, -5.0f, 0.0f};
		start=camera.position;
		start.y+=precipitationvert;
		start.x += randUint(precipitationhorz);
		start.z += randUint(precipitationhorz);
		sprites.MakeSprite(snowsprite, 1, 1, 1, 1, start, velocity, 1.01);
	}

	while(snowdelay<0&&environment==rainy_environment){
		snowdelay+=1/precipitationdensity/4;
		XYZ velocity {0.0f, -100.0f, 0.0f};
		start=camera.position;
		start.y+=precipitationvert;
		start.x += randUint(precipitationhorz) * 0.5f;
		start.z += randUint(precipitationhorz) * 0.5f;
		sprites.MakeSprite(rainsprite, .5, 1, 1, 1, start, velocity, 2.00);
	}

	// Grenade collision
	for (int i = 0; i < sprites.howmanysprites; ++i) {
		switch (sprites.type[i]) {
		case grenadesprite:
			sprites.brightness[i] -= multiplier * 0.3f;
			break;
		case pinsprite:
		case spoonsprite:
			sprites.brightness[i] -= multiplier * 0.2f;
			break;
		default:
			continue;
		}

		bool impact = false;
		if (sqrlen(sprites.velocity[i]) > 0) {
			int wherex = sprites.location[i].x / block_spacing + 0.5f;
			int wherey = sprites.location[i].z / block_spacing + 0.5f;
			move = {(float) wherex * block_spacing, 0.0f, (float) wherey * block_spacing};
			whichtri=blocks[citytype[wherex][wherey]].LineCheck2(sprites.oldlocation[i],sprites.location[i],&wallhit,move,cityrotation[wherex][wherey]*90);

			if (whichtri != -1) {
				impact = true;
				auto normalrotated = DoRotation(blocks[citytype[wherex][wherey]].normals[whichtri], 0, cityrotation[wherex][wherey] * 90, 0);
				if (sprites.size[i] > 1)
					decals.MakeDecal(crater, wallhit, 9, normalrotated, whichtri, &blocks[citytype[wherex][wherey]], move, cityrotation[wherex][wherey] * 90);
				sprites.location[i] = wallhit + normalrotated * 0.02f;
				reflect(&sprites.velocity[i], normalrotated);
				sprites.velocity[i] *= 0.3f;

				if (sprites.type[i] == grenadesprite && sprites.size[i] <= 1) {
					auto soundpos = sprites.location[i] - camera.position;
					auto v = sqrlen(sprites.velocity[i]) * 0.2f;
					ALfloat gLoc[] {
						soundpos.x / v / soundscalefactor,
						soundpos.y / v / soundscalefactor,
						soundpos.z / v / soundscalefactor,
					};
					int whichsound = bouncesound + randUint(2);
					alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
					alSourcePlay(gSourceID[whichsound]);
				}

				if (sqrlen(sprites.velocity[i]) <= 10)
					sprites.velocity[i] = {};
			}

			if(sprites.location[i].y<0){
				impact = true;
				sprites.velocity[i].y *= -1.0f;
				sprites.velocity[i] *= 0.3f;
				sprites.location[i].y = 0.0f;

				if(sprites.type[i]==grenadesprite){
					if(sprites.size[i]>1){
						move = {};
						sprites.location[i].y=-.5;
						XYZ normish = {0.0f, 1.0f, 0.0f};
						decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &blocks[citytype[wherex][wherey]], move, 0);
					}

					auto soundpos = sprites.location[i] - camera.position;
					auto v = sqrlen(sprites.velocity[i]) * 0.2f;
					ALfloat gLoc[] {
						soundpos.x / v / soundscalefactor,
						soundpos.y / v / soundscalefactor,
						soundpos.z / v / soundscalefactor,
					};
					int whichsound = bouncesound + randUint(2);
					alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
					if (sprites.size[i] <= 1)
						alSourcePlay(gSourceID[whichsound]);

				}

				if (sqrlen(sprites.velocity[i]) <= 10)
					sprites.velocity[i] = {};
			}

			if (sprites.type[i] == grenadesprite
			    && sqrlen(sprites.velocity[i]) > 20) {
				for (int j = 0; j < numpeople; ++j) {
					if (j == 0 && sprites.brightness[i] > 0.9f || !person[j].existing)
						continue;
					auto hitstruct = person[j].BulletCollideWithPlayer(j, sprites.oldlocation[i], sprites.location[i]);
					if (!hitstruct.collision)
						continue;
					impact = true;
					sprites.location[i] = hitstruct.hitlocation;
					auto landpos = sprites.location[i] - camera.position;
					auto v = sqrlen(sprites.velocity[i]) * 0.2f;
					ALfloat gLoc[] {
						landpos.x / v / soundscalefactor,
						landpos.y / v / soundscalefactor,
						landpos.z / v / soundscalefactor,
					};

					sprites.velocity[i] *= -0.3f;
					if (person[j].skeleton.free)
						continue;
					if((hitstruct.joint1->label==head||hitstruct.joint2->label==head)&&person[j].type!=zombietype){
						alSourcefv(gSourceID[headwhacksound], AL_POSITION, gLoc);
						if(sprites.size[i]<=1)alSourcePlay(gSourceID[headwhacksound]);
						person[j].skeleton.free=1;
						person[j].longdead=1;
						for (auto& joint : person[j].skeleton.joints) {
							joint.realoldposition = joint.position
								= DoRotation(joint.position,
									0, person[j].playerrotation, 0)
								+ person[j].playercoords;

							joint.velocity = person[j].velocity;
							joint.velocity.x += randInt(-4, 4);
							joint.velocity.y += randInt(-4, 4);
							joint.velocity.z += randInt(-4, 4);
						}

						hitstruct.joint1->velocity += sprites.velocity[i];
						hitstruct.joint2->velocity += sprites.velocity[i];

						if (person[j].type == civiliantype)
							civkills++;
						if (person[j].type == eviltype)
							goodkills++;
					} else {
						float totalarea = 0.0f;
						alSourcefv(gSourceID[bodywhacksound], AL_POSITION, gLoc);
						if(sprites.size[i]<=1)alSourcePlay(gSourceID[bodywhacksound]);
						person[j].skeleton.offset=1;

						for (auto& joint : person[j].skeleton.joints) {
							auto distance = sqrlen(DoRotation(joint.position, 0, person[j].playerrotation, 0)
								+ person[j].playercoords
								- hitstruct.hitlocation);
							if (distance < 200) {
								totalarea += 200 / distance;
								joint.offset += DoRotation(sprites.velocity[i] * 0.1 * 200 / distance / totalarea * 10, 0, -person[j].playerrotation, 0);
							}
							if (sqrlen(joint.offset) > 9) {
								joint.offset = normalize(joint.offset) * 3;
							}
						}
					}
				}
			}
			sprites.oldlocation[i]=sprites.location[i];
		}

		// Explode
		if (sprites.type[i] == grenadesprite
		    && (sprites.brightness[i] <= 0 || impact && sprites.size[i] > 1)) {
			sprites.brightness[i] = 0;
			sprites.MakeSprite(smokesprite, 1, 1, 1, 1, sprites.location[i], facing*0, 60);
			sprites.MakeSprite(muzzleflashsprite, 1, 1, 1, 1, sprites.location[i], facing*0, 9);

			auto explodepos = sprites.location[i] - camera.position;
			ALfloat gLoc[] {
				explodepos.x / 3 / soundscalefactor,
				explodepos.y / 3 / soundscalefactor,
				explodepos.z / 3 / soundscalefactor,
			};
			alSourcefv(gSourceID[explosionsound], AL_POSITION, gLoc);
			alSourcePlay(gSourceID[explosionsound]);

			XYZ relation;
			camerashake=1-findDistance(person[0].playercoords,sprites.location[i])/200;

			overpoint=sprites.location[i];
			overpoint.y+=3000;
			underpoint=sprites.location[i];
			underpoint.y-=3000;
			int wherex=(sprites.location[i].x+block_spacing/2)/block_spacing;
			int wherey=(sprites.location[i].z+block_spacing/2)/block_spacing;
			move = {(float) wherex * block_spacing, 0.0f, (float) wherey * block_spacing};

			XYZ temp;
			whichtri=sidewalkcollide.LineCheck2(overpoint,underpoint,&temp,move,cityrotation[wherex][wherey]*90);

			XYZ normish = {0.0f, 1.0f, 0.0f};
			if(whichtri>=0){
				decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, cityrotation[wherex][wherey]*90);
			}

			if(whichtri==-1){
				temp=sprites.location[i];
				temp.y=-.5;
				move = {};
				decals.MakeDecal(crater, sprites.location[i],9,normish, 0, &sidewalkcollide, move, 0);
			}

			for(int k=0;k<numpeople;k++){
				if (!person[k].existing
				    || (person[k].longdead == -1
				        && person[k].skeleton.free)
				    || ((sqrlen(person[k].playercoords - sprites.location[i]) > 700
				         || person[k].skeleton.free)
				        && (sqrlen(person[k].averageloc - sprites.location[i]) > 700
				            || !person[k].skeleton.free)))
					continue;
				if(person[k].skeleton.free!=1){
					if(person[k].type==civiliantype)civkills++;
					if(person[k].type==eviltype)goodkills++;

					person[k].skeleton.free=1;
					person[k].killtargetvisible=0;

					if ((sqrlen(person[k].playercoords - sprites.location[i]) < 600
					     && person[k].skeleton.free < 1)
					    || (sqrlen(person[k].averageloc - sprites.location[i]) < 600
					        && person[k].skeleton.free >= 1)
					    || person[k].type == playertype) {
						person[k].health-=100;
						person[k].bleeding=1;
					}

					person[k].DoAnimations(k);
					person[k].longdead = 1;
					person[k].bleeddelay = 1;

					person[k].bjoint1 = &person[k].skeleton.joints[head];
					person[k].bjoint2 = &person[k].skeleton.joints[neck];

					for (auto& joint : person[k].skeleton.joints) {
						joint.position = DoRotation(joint.position, 0, person[k].playerrotation, 0);
						joint.position += person[k].playercoords;
						joint.realoldposition = joint.position;
						joint.velocity = DoRotation(joint.velocity, 0, person[k].playerrotation, 0);
						joint.velocity += person[k].velocity;
						joint.velocity.x += randInt(-9, 9);
						joint.velocity.y += randInt(-9, 9);
						joint.velocity.z += randInt(-9, 9);
					}
				}

				person[k].longdead=1;
				for (auto& joint : person[k].skeleton.joints) {
					relation = normalize(joint.position - sprites.location[i]);
					auto distance = findDistance(joint.position, sprites.location[i]);
					if (distance > 1)
						joint.velocity += relation / distance * 300;
					else
						joint.velocity += relation * 300;

					// Sever stuff
					if (sqrlen(joint.velocity) > 1500
					    && joint.existing && randUint(5)) {
						sprites.MakeSprite(bloodspritedown, 0.8, 1, 0.2, 0.2, joint.position, joint.velocity / 3, 9);
						person[k].skeleton.DeleteJoint(&joint
							- person[k].skeleton.joints);
						person[k].skeleton.broken=2;
						person[k].health=-10000;
						joint.existing = false;
					}
				}
			}
		}
	}

	//camera shake
	camerashake-=multiplier;
	if(camerashake<0)camerashake=0;

	//camera position
	XYZ average;

	if(!zoom)average=person[0].skeleton.joints[head].position*(person[0].aimamount/2+.5)+person[0].skeleton.joints[neck].position*((1-person[0].aimamount)/2);

	if(zoom)average=person[0].skeleton.joints[righthand].position;

	if(person[0].skeleton.free==0&&thirdperson!=2)camera.position=person[0].playercoords+DoRotation(average,0,person[0].playerrotation,0);

	if(person[0].skeleton.free==1&&thirdperson!=2)camera.position=average;

	//Restraints

	if(camera.position.y<.1)camera.position.y=.1;

	if(thirdperson!=2){
		oldrot=camera.visrotation;
		oldrot2=camera.visrotation2;
	}

	//Kill count
	for(int i=0;i<numpeople;i++){
		if(person[i].oldhealth>0&&person[i].health<=0){
			if(i==1)alSourcePlay(gSourceID[losesound]);
			if(person[i].type==civiliantype){
				alSourcePlay(gSourceID[disguisekillsound]);
				score-=300;
			}

			if(person[i].type==eviltype){
				alSourcePlay(gSourceID[soulinsound]);
				score+=75;
				if(person[i].whichgun==knife)score+=50;
			}
			person[i].firstlongdead=0;
		}
		person[i].oldhealth=person[i].health;
	}

	if(slomo==2){
		psychicpower-=multiplier*15;
		if(psychicpower<0){
			alSourceStop(gSourceID[whichsong]);
			alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 0);
			alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 0);
			if(person[0].whichgun==knife)whichsong=knifesong;
			if(person[0].whichgun!=knife)whichsong=shootsong;
			if(type==zombie_type)whichsong=zombiesong;
			alSourcef(gSourceID[whichsong], AL_PITCH, 1);
			alSourcePlay(gSourceID[whichsong]);
			alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 1);
			alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 1);
			slomo=0;
			alSourcePlay(gSourceID[soulinsound]);
			psychicpower=0;
			flashamount=.5;
			flashr=1;flashg=1;flashb=1;
		}
	}

	psychicpower+=multiplier*5;
	if(psychicpower>10)psychicpower=10;

	setListener(this, facing);
	if (score < 0)
		score = 0;
}