// 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 Nguyễn Gia Phong
//
// This file is part of Black Shades.
//
// Black Shades is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Black Shades is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Black Shades. If not, see .
#include
#include "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;
Normalise(&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 = findDistancefast(person.playercoords,
player.playercoords + flatfacing);
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;
game->whacked = false;
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 = findDistancefast(person.playercoords,
player.playercoords + flatfacing);
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 Game::Tick()
{
if (person[1].health <= 0 || person[0].health <= 0 || killedinnocent)
losedelay -= multiplier / 6;
else
timeremaining -= multiplier;
if (timeremaining <= 0) {
score += ++mission * 50 + 100;
highscore = std::max(score, highscore);
flashamount = flashg = 1;
flashr = flashb = 0;
alSourcePlay(gSourceID[souloutsound]);
if (mission >= nummissions) {
alSourcePause(gSourceID[rainsound]);
alSourceStop(gSourceID[visionsound]);
alSourceStop(gSourceID[whichsong]);
alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 0);
alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 0);
whichsong = mainmenusong;
alSourcef(gSourceID[whichsong], AL_PITCH, 1);
alSourcef(gSourceID[whichsong], AL_MIN_GAIN, 1);
alSourcef(gSourceID[whichsong], AL_MAX_GAIN, 1);
alSourcePlay(gSourceID[whichsong]);
setMenu(this, beatgame = true);
gameinprogress = 0;
} else {
updateSong(this);
initGame(this);
}
}
if (losedelay <= 0) {
score -= (person[murderer].health > 0) ? 200 : 100;
flashamount = 1;
flashr = flashg = flashb = 0;
alSourcePlay(gSourceID[soulinsound]);
updateSong(this);
initGame(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;
Normalise(&flatfacing);
//Check collision with buildings
int beginx,endx;
int beginz,endz;
XYZ collpoint;
XYZ move;
int whichtri;
XYZ underpoint;
XYZ overpoint;
int pointnum;
float depth;
XYZ normalrotated;
bool inblock;
//Check people collisions
for(int k=0;knum_blocks-1)endx=num_blocks-1;
endz=(person[k].playercoords.z+block_spacing/2)/block_spacing+1;
if(endz>num_blocks-1)endz=num_blocks-1;
/* TODO: huh?
* if(k!=0) {
* beginx == person[k].whichblockx;
* beginz == person[k].whichblocky;
* endx == person[k].whichblockx;
* endz == person[k].whichblocky;
* }
*/
if(beginx<=endx&&beginz<=endz)
for(int i=beginx;i<=endx;i++)
for(int j=beginz;j<=endz;j++){
inblock=0;
//Ground collision
move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing};
whichtri=sidewalkcollide.LineCheck2(overpoint,underpoint,&collpoint,move,cityrotation[i][j]*90);
if(whichtri!=-1&&person[k].playercoords.y<=collpoint.y&&person[k].velocity.y<=0){
person[k].playercoords.y=collpoint.y;
person[k].onground=1;
Splat(this, k);
}
if(whichtri!=-1){
inblock=1;
if(k==0){onblockx=i;onblocky=j;}
}
//Wall collision
if(k==0){
if(inblock){
for(int l=0;l<8;l++){
move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing};
whichtri=blockwalls[citytype[i][j]].LineCheck3(person[k].oldplayercoords+boundingpoints[l],person[k].playercoords+boundingpoints[l],&collpoint,move,cityrotation[i][j]*90,&depth);
if(whichtri!=-1){
normalrotated=DoRotation(blockwalls[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0);
person[k].playercoords+=normalrotated*(-(dotproduct(normalrotated,person[k].playercoords-person[k].oldplayercoords))-depth);
}
}
for(int l=0;l<8;l++){
pointnum=k+1;
if(pointnum>3)pointnum=0;
move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing};
whichtri=blockwalls[citytype[i][j]].LineCheck3(person[k].playercoords+boundingpoints[l],person[k].playercoords+boundingpoints[pointnum],&collpoint,move,cityrotation[i][j]*90,&depth);
if(whichtri!=-1){
normalrotated=DoRotation(blockwalls[citytype[i][j]].normals[whichtri],0,cityrotation[i][j]*90,0);
person[k].playercoords+=normalrotated;
}
}
}
//Roof collision
if(inblock&&person[k].playercoords.y>30){
if(!person[k].onground){
move = {(float) i * block_spacing, 0.0f, (float) j * block_spacing};
whichtri=blockroofs[citytype[i][j]].LineCheck2(overpoint,underpoint,&collpoint,move,cityrotation[i][j]*90);
if(whichtri!=-1&&person[k].playercoords.y<=collpoint.y&&person[k].velocity.y<=0){
person[k].playercoords.y=collpoint.y;
person[k].onground=1;
Splat(this, k);
}
if(whichtri!=-1)inblock=1;
}
}
}
}
if (person[k].playercoords.y <= 0) {
person[k].onground = 1;
person[k].playercoords.y = 0;
Splat(this, k);
if (k == 0)
onblockx = onblocky = -1;
}
// SBF - this is definately in the wrong spot!
//person[k].oldplayercoords=person[k].playercoords;
}
}
}
// Camera
camera.oldposition = camera.position;
camera.targetoffset = {0.0f, 0.0f, -5.0f};
// Spawn people
int cyclenum = 0;
int blockspawnx = 0, blockspawny = 0;
do {
auto block = person[0].playercoords / block_spacing;
blockspawnx = block.x + 0.5f + randInt(-1, 1);
blockspawny = block.z + 0.5f + randInt(-1, 1);
auto& people = citypeoplenum[blockspawnx][blockspawny];
if (people < max_people_block)
break;
} while (++cyclenum < 10);
spawndelay -= multiplier;
if(cyclenum<10){
if (spawndelay < 0 && numpeople < max_people) {
if (type == zombie_type)
person[numpeople].type = zombietype;
else if (randUint(evilprobability))
person[numpeople].type = civiliantype;
else
person[numpeople].type = eviltype;
if(person[numpeople].type!=civiliantype&&blockspawnx==person[1].whichblockx&&blockspawny==person[1].whichblocky){
while((citypeoplenum[blockspawnx][blockspawny]>=max_people_block&&cyclenum<10)||blockspawnx==0||(blockspawnx==person[1].whichblockx&&blockspawny==person[1].whichblocky)){
blockspawnx = (person[0].playercoords.x + block_spacing / 2) / block_spacing + randInt(-1, 1);
blockspawny = (person[0].playercoords.z + block_spacing / 2) / block_spacing + randInt(-1, 1);
cyclenum++;
}
}
person[numpeople].playerrotation=0;
person[numpeople].whichcostume = casualcostumes + randUint(numcasual);
person[numpeople].whichblockx=blockspawnx;
person[numpeople].whichblocky=blockspawny;
person[numpeople].pathnum=-1;
person[numpeople].oldpathnum=-1;
person[numpeople].oldoldpathnum=-1;
person[numpeople].oldoldoldpathnum=-1;
while(person[numpeople].pathnum<0||person[numpeople].pathnum>=path.vertexNum||person[numpeople].pathnum==1){
person[numpeople].pathnum = randUint(path.vertexNum);
}
person[numpeople].pathtarget.x=path.vertex[person[numpeople].pathnum].x;
person[numpeople].pathtarget.z=path.vertex[person[numpeople].pathnum].z;
person[numpeople].pathsize = 0.98f + 0.04f * randFloat();
person[numpeople].pathtarget*=person[numpeople].pathsize;
person[numpeople].pathtarget.x+=person[numpeople].whichblockx*block_spacing;
person[numpeople].pathtarget.z+=person[numpeople].whichblocky*block_spacing;
person[numpeople].playercoords=person[numpeople].pathtarget;
person[numpeople].oldplayercoords=person[numpeople].playercoords;
person[numpeople].skeleton.free=0;
person[numpeople].targetanimation=walkanim;
if(person[numpeople].type==zombietype)person[numpeople].targetanimation=zombiewalkanim;
person[numpeople].speed=1;
person[numpeople].existing=0;
person[numpeople].speedmult = 0.8f + 0.4f * randFloat();
person[numpeople].health=100;
person[numpeople].maxhealth=100;
person[numpeople].playerrotation2=0;
person[numpeople].lastdistancevictim=200000;
if(numpeople==1)person[numpeople].type=viptype;
person[numpeople].killtarget=-1;
if(person[numpeople].type==eviltype){person[numpeople].existing=1; person[numpeople].pathsize=1.04; person[numpeople].whichgun=nogun; person[numpeople].aiming=1; person[numpeople].killtarget=-1; person[numpeople].speedmult=1+.3*difficulty;}
if(person[numpeople].type==zombietype){person[numpeople].existing=1; person[numpeople].pathsize=1.04; person[numpeople].whichgun=nogun; person[numpeople].aiming=0; person[numpeople].killtarget=-1; person[numpeople].speedmult=0.7+.2*difficulty;}
else {person[numpeople].whichgun=nogun; person[numpeople].aiming=0; person[numpeople].killtarget=-1;}
if(person[numpeople].type==viptype){person[numpeople].existing=1;}
if(enemystate==2)person[numpeople].killtarget=1;
numpeople++;
citypeoplenum[blockspawnx][blockspawny]++;
spawndelay=.1;
}
if(spawndelay<0&&numpeople>=max_people){
if(cycle>=max_people)cycle=0;
cyclenum=0;
while(cyclenum=max_people)cycle=0;
}
if(cycle=max_people_block&&cyclenum<10)||blockspawnx==0||(blockspawnx==person[1].whichblockx&&blockspawny==person[1].whichblocky)){
blockspawnx = (person[0].playercoords.x + block_spacing / 2) / block_spacing + randInt(-1, 1);
blockspawny = (person[0].playercoords.z + block_spacing / 2) / block_spacing + randInt(-1, 1);
cyclenum++;
}
}
person[cycle].playerrotation=0;
person[cycle].whichcostume = casualcostumes + randUint(numcasual);
citypeoplenum[person[cycle].whichblockx][person[cycle].whichblocky]--;
person[cycle].whichblockx=blockspawnx;
person[cycle].whichblocky=blockspawny;
person[cycle].pathnum=-1;
person[cycle].oldpathnum=-1;
person[cycle].oldoldpathnum=-1;
person[cycle].oldoldoldpathnum=-1;
while(person[cycle].pathnum<0||person[cycle].pathnum>=path.vertexNum||person[cycle].pathnum==1){
person[cycle].pathnum = randUint(path.vertexNum);
}
person[cycle].pathtarget.x=path.vertex[person[cycle].pathnum].x;
person[cycle].pathtarget.z=path.vertex[person[cycle].pathnum].z;
person[cycle].pathsize= 0.98f + 0.04f * randFloat();
person[cycle].pathtarget*=person[cycle].pathsize;
person[cycle].pathtarget.x+=person[cycle].whichblockx*block_spacing;
person[cycle].pathtarget.z+=person[cycle].whichblocky*block_spacing;
person[cycle].playercoords=person[cycle].pathtarget;
person[cycle].oldplayercoords=person[cycle].playercoords;
person[cycle].skeleton.free=0;
person[cycle].targetanimation=walkanim;
if(person[cycle].type==zombietype)person[cycle].targetanimation=zombiewalkanim;
person[cycle].speed=1;
person[cycle].existing=0;
person[cycle].speedmult = 0.8f + 0.4f * randFloat();
person[cycle].health=100;
person[cycle].maxhealth=100;
person[cycle].playerrotation2=0;
if(enemystate==1)person[cycle].killtarget=-1;
if(person[cycle].type==eviltype){person[cycle].existing=1; person[cycle].pathsize=1.04; person[cycle].whichgun=nogun; person[cycle].aiming=1; person[cycle].killtarget=-1; person[cycle].speedmult=1+.3*difficulty;}
if(person[cycle].type==zombietype){person[cycle].existing=1; person[cycle].pathsize=1.04; person[cycle].whichgun=nogun; person[cycle].aiming=0; person[cycle].killtarget=-1; person[cycle].speedmult=.7+.2*difficulty;}
else {person[cycle].whichgun=nogun; person[cycle].aiming=0; person[cycle].killtarget=-1;}
person[cycle].lastdistancevictim=200000;
if(enemystate==2)person[cycle].killtarget=1;
if(numpeople=0){
decals.MakeDecal(bloodpool,temp,12,normish, whichtri, &sidewalkcollide, move, cityrotation[person[i].whichblockx][person[i].whichblocky]*90);
}
if(whichtri==-1){
temp=person[i].skeleton.joints[abdomen].position;
temp.y=-.5;
move = {};
decals.MakeDecal(bloodpool,temp,12,normish, 0, &sidewalkcollide, move, 0);
}
person[i].firstlongdead=1;
}
}
if(person[i].health<100&&person[i].type!=zombietype){
person[i].health-=multiplier*120;
}
if(person[i].health<100&&person[i].type==zombietype){
person[i].health+=multiplier*10;
if(person[i].health>person[i].maxhealth)person[i].health=person[i].maxhealth;
}
if(person[i].health<100&&person[i].type==zombietype&&person[i].skeleton.free==1){
person[i].health+=multiplier*10;
if(person[i].health>person[i].maxhealth)person[i].health=person[i].maxhealth;
}
if(person[i].health<40&&person[i].type==zombietype){
person[i].speedmult-=multiplier/20;
if(person[i].speedmult<.6){
person[i].speedmult=.6;
person[i].killtarget=-1;
}
}
if(person[i].health>=40&&person[i].type==zombietype){
person[i].speedmult+=multiplier/40;
if(person[i].speedmult>.7+difficulty*.2){
person[i].speedmult=.7+difficulty*.2;
person[i].killtarget=1;
}
}
if(person[i].maxhealth<100&&person[i].type==zombietype){
person[i].maxhealth+=multiplier*2;
if(person[i].maxhealth>100)person[i].maxhealth=100;
}
if(person[i].bleeding>0){
person[i].bleeding-=multiplier;
person[i].bleeddelay-=multiplier*10;
if(person[i].bleeddelay<=0){
person[i].bleeddelay=1;
if(person[i].skeleton.free==0){
bleedloc=DoRotation((person[i].bjoint1->position+person[i].bjoint2->position)/2,0,person[i].playerrotation,0)+person[i].playercoords;
}
if(person[i].skeleton.free>0){
bleedloc=(person[i].bjoint1->position+person[i].bjoint2->position)/2;
}
vel = {};
sprites.MakeSprite(bloodspritedown, .6, 1, .2, .2,bleedloc, vel, 3*person[i].bleeding);
}
}
if (!person[i].skeleton.free) {
// Gun
switch (person[i].type) {
case playertype:
switch (person[i].whichgun) {
case shotgun:
person[i].recoil -= multiplier * 4;
break;
case sniperrifle:
person[i].recoil -= multiplier * 2;
break;
case handgun1:
case handgun2:
person[i].recoil -= multiplier * 5;
break;
case assaultrifle:
person[i].recoil-=multiplier * 10;
break;
}
if (!person[0].aiming || visions)
this->zoom = false;
break;
case eviltype:
switch (person[i].whichgun) {
case shotgun:
case sniperrifle:
person[i].recoil -= multiplier * 1;
break;
case handgun1:
case handgun2:
person[i].recoil -= multiplier * 2;
break;
case assaultrifle:
person[i].recoil-=multiplier * 10;
break;
}
break;
}
if (person[i].recoil < 0)
person[i].recoil = 0;
//Zombie eat
if(i > 0
&& person[i].targetanimation == zombieeatanim
&& person[person[i].killtarget].eaten == i) {
person[person[i].killtarget].skeleton.joints[head].locked=1;
person[person[i].killtarget].skeleton.joints[rightshoulder].locked=1;
for(int k=0;k<2;k++){
person[person[i].killtarget].skeleton.joints[head].position=DoRotation(person[i].skeleton.joints[righthand].position,0,person[i].playerrotation,0)+person[i].playercoords;
person[person[i].killtarget].skeleton.joints[head].velocity = {};
person[person[i].killtarget].skeleton.joints[rightshoulder].position=DoRotation(person[i].skeleton.joints[lefthand].position,0,person[i].playerrotation,0)+person[i].playercoords;
person[person[i].killtarget].skeleton.joints[rightshoulder].velocity = {};
person[person[i].killtarget].skeleton.DoConstraints();
person[person[i].killtarget].skeleton.DoConstraints(&blocksimplecollide[citytype[person[i].whichblockx][person[i].whichblocky]],&move,cityrotation[person[i].whichblockx][person[i].whichblocky]*90);
}
person[person[i].killtarget].skeleton.joints[head].locked=0;
person[person[i].killtarget].skeleton.joints[rightshoulder].locked=0;
person[person[i].killtarget].longdead=1;
}
if(i>0&&enemystate!=1&&person[i].type==zombietype&&person[i].speedmult>.7){
if(findDistancefast(person[i].playercoords,person[1].playercoords)<20000)person[i].killtarget=1;
else person[i].killtarget=-1;
}
if(i>0&&enemystate!=1&&person[i].type==zombietype&&person[i].speedmult<.7){
person[i].killtarget=-1;
}
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
= findDistancefast(person[i].pathtarget,
person[i].playercoords)
> findDistancefast(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(findDistancefast(person[i].playercoords,person[i].pathtarget)= 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(findDistancefast(person[i].playercoords,person[i].pathtarget)findDistancefast(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=findDistancefast(person[i].pathtarget,person[person[i].killtarget].playercoords);
leastdistance=findDistancefast(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;jnum_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;j30000)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(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)>toofar)
person[i].targetanimation=joganim;
if((findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=tooclose&&person[person[i].killtarget].skeleton.free==0)||(tooclose>200&&findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=200)||(tooclose<=200&&findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)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(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)>20||person[i].targetanimation!=idleanim)
person[i].targetanimation=zombiejoganim;
if(findDistancefast(person[i].playercoords, person[person[i].killtarget].playercoords)<=20){
murderer=i;
person[person[i].killtarget].health=0;
person[person[i].killtarget].eaten=i;
}
finaltarget=person[person[i].killtarget].playercoords;
}
}
if(person[i].killtargetvisible||realcheck)person[i].pathtarget=finaltarget;
if(realcheck)person[i].lastdistancevictim=findDistancefast(person[i].pathtarget,person[person[i].killtarget].playercoords);
}
}
if(person[i].targetanimation!=zombieeatanim||person[i].type!=zombietype){
towards=person[i].playercoords-person[i].pathtarget;
Normalise(&towards);
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].longdead0)person[i].DrawSkeleton(i);
if(findDistancefast(person[i].averageloc,person[i].oldaverageloc)<.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=person[i].skeleton.joints[neck].position-person[i].skeleton.joints[groin].position;
Normalise(&firsttop);
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);
}
}
}
XYZ velocity;
if(person[0].attackframe>1||(person[0].attackframe>=0&&person[0].currentanimation==joganim)){
if(person[person[0].killtarget].skeleton.free<1&&person[0].killtarget!=0&&(person[0].aiming<1||person[0].whichgun==nogun||person[0].whichgun==knife||person[0].targetanimation==joganim)){
auto soundpos = person[0].playercoords + flatfacing
- camera.position;
if (person[person[0].killtarget].type != zombietype) {
if (person[0].whichgun != knife) {
playSound(gSourceID[headwhacksound],
soundpos.x, soundpos.y, soundpos.z);
} else {
playSound(gSourceID[knifeslashsound],
soundpos.x, soundpos.y, soundpos.z);
person[person[0].killtarget].bjoint1=&person[person[0].killtarget].skeleton.joints[neck];
person[person[0].killtarget].bjoint2=&person[person[0].killtarget].skeleton.joints[neck];
person[person[0].killtarget].bleeding=1;
person[person[0].killtarget].bleeddelay=1;
person[0].bjoint1=&person[0].skeleton.joints[righthand];
person[0].bjoint2=&person[0].skeleton.joints[righthand];
person[0].bleeding=1;
person[0].bleeddelay=1;
velocity=DoRotation(flatfacing,0,70,0)*50+person[0].velocity*2;
velocity.y+=30;
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.3, 2);
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.2, 3);
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.1, 4);
}
person[person[0].killtarget].health-=100;
person[person[0].killtarget].skeleton.free=1;
person[person[0].killtarget].longdead=1;
for (auto& joint : person[person[0].killtarget].skeleton.joints) {
joint.position = DoRotation(joint.position,
0, person[person[0].killtarget].playerrotation, 0);
joint.position += person[person[0].killtarget].playercoords;
joint.realoldposition = joint.position;
joint.velocity = person[person[0].killtarget].velocity;
joint.velocity.x += randInt(-4, 4);
joint.velocity.y += randInt(-4, 4);
joint.velocity.z += randInt(-4, 4);
}
if(person[0].whichgun!=knife){
person[person[0].killtarget].skeleton.joints[head].velocity+=DoRotation(flatfacing,0,40,0)*50;
person[person[0].killtarget].skeleton.joints[head].velocity+=person[0].velocity*2;
}
} else if (!whacked) {
whacked = true;
if (person[0].whichgun != knife) {
playSound(gSourceID[headwhacksound],
soundpos.x, soundpos.y, soundpos.z);
} else {
playSound(gSourceID[knifeslashsound],
soundpos.x, soundpos.y, soundpos.z);
person[person[0].killtarget].bjoint1=&person[person[0].killtarget].skeleton.joints[neck];
person[person[0].killtarget].bjoint2=&person[person[0].killtarget].skeleton.joints[neck];
person[person[0].killtarget].bleeddelay=1;
person[0].bjoint1=&person[0].skeleton.joints[righthand];
person[0].bjoint2=&person[0].skeleton.joints[righthand];
person[0].bleeding=1;
person[0].bleeddelay=1;
velocity=DoRotation(flatfacing,0,70,0)*50+person[0].velocity*2;
velocity.y+=30;
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.3, 2);
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.2, 3);
sprites.MakeSprite(bloodspritedown, .8, 1, .2, .2,DoRotation(person[person[0].killtarget].skeleton.joints[neck].position,0,person[person[0].killtarget].playerrotation,0)+person[person[0].killtarget].playercoords, velocity*.1, 4);
}
person[person[0].killtarget].health-=200;
person[person[0].killtarget].maxhealth-=20;
person[person[0].killtarget].skeleton.free=1;
person[person[0].killtarget].longdead=1;
for (auto& joint : person[person[0].killtarget].skeleton.joints) {
joint.position = DoRotation(joint.position, 0, person[person[0].killtarget].playerrotation, 0);
joint.position += person[person[0].killtarget].playercoords;
joint.realoldposition = joint.position;
joint.velocity = person[person[0].killtarget].velocity;
joint.velocity.x += randInt(-4, 4);
joint.velocity.y += randInt(-4, 4);
joint.velocity.z += randInt(-4, 4);
}
if(person[0].whichgun!=knife){
person[person[0].killtarget].skeleton.joints[head].velocity+=DoRotation(flatfacing,0,40,0)*50;
person[person[0].killtarget].skeleton.joints[head].velocity+=person[0].velocity*2;
}
}
}
}
//Tackle
if (person[0].currentanimation == diveanim && visions == 0) {
for (int i = 1; i < numpeople; i++) {
if (person[i].skeleton.free > 0
|| findDistancefast(person[i].playercoords,
person[0].playercoords
+ flatfacing) > 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[i].skeleton.free = 1;
person[i].longdead = 1;
for (auto& joint : person[i].skeleton.joints) {
joint.position = DoRotation(joint.position, 0, person[i].playerrotation, 0);
joint.position += person[i].playercoords;
joint.realoldposition = joint.position;
joint.velocity = person[0].velocity;
joint.velocity.y = -10;
joint.velocity.x += randInt(-4, 4);
joint.velocity.y += randInt(-4, 4);
joint.velocity.z += randInt(-4, 4);
}
}
}
// 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;
Normalise(&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;mnum_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.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 = findDistancefast(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 = findDistancefast(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 (findLengthfast(joint.offset) > 36) {
Normalise(&joint.offset);
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;
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
&& findDistancefast(nearest, camera.position) < 10
&& (thirdperson == 2 || j != 0)) {
auto nearsound = nearest - camera.position;
playSound(gSourceID[nearbulletsound],
nearsound.x, nearsound.y, nearsound.z);
}
}
}
}
if(lasersight&&person[0].whichgun!=grenade){
for(int j=0;j=1){
//Firing
XYZ end, aim;
HitStruct hitstruct,temphitstruct;
float olddistance = 0.0f;
float distance;
int whichhit=-1;
if(!zoom||j!=0){
if(person[j].whichgun==assaultrifle)aim=DoRotation(person[j].skeleton.joints[lefthand].position-person[j].skeleton.joints[righthand].position,0,person[j].playerrotation-2.5,0);
if(person[j].whichgun==sniperrifle)aim=DoRotation(person[j].skeleton.joints[lefthand].position-person[j].skeleton.joints[righthand].position,0,person[j].playerrotation+4,0);
if(person[j].whichgun==shotgun)aim=DoRotation(person[j].skeleton.joints[lefthand].position-person[j].skeleton.joints[righthand].position,0,person[j].playerrotation+4,0);
if(person[j].whichgun==handgun1&&!thirdperson&&j==0)aim=DoRotation(person[j].skeleton.joints[righthand].position-(person[j].skeleton.joints[head].position*.65+person[j].skeleton.joints[neck].position*.35),0,person[j].playerrotation-.9,0);
if(person[j].whichgun==handgun1&&(thirdperson||j!=0))aim=DoRotation(person[j].skeleton.joints[righthand].position-(person[j].skeleton.joints[head].position*.35+person[j].skeleton.joints[neck].position*.65),0,person[j].playerrotation-.9,0);
if(person[j].whichgun==handgun2&&!thirdperson&&j==0)aim=DoRotation(person[j].skeleton.joints[righthand].position-(person[j].skeleton.joints[head].position*.65+person[j].skeleton.joints[neck].position*.35),0,person[j].playerrotation-.9,0);
if(person[j].whichgun==handgun2&&(thirdperson||j!=0))aim=DoRotation(person[j].skeleton.joints[righthand].position-(person[j].skeleton.joints[head].position*.35+person[j].skeleton.joints[neck].position*.65),0,person[j].playerrotation-.9,0);
}
if(zoom&&j==0){
start=camera.position;
aim=facing;
}
Normalise(&aim);
if(person[j].whichgun==sniperrifle){
start=person[j].playercoords+DoRotation(person[j].skeleton.joints[lefthand].position,0,person[j].playerrotation,0);
start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(0-.4);
}
if(person[j].whichgun==shotgun){
start=person[j].playercoords+DoRotation(person[j].skeleton.joints[lefthand].position,0,person[j].playerrotation,0);
start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(0-.4);
}
if(person[j].whichgun==handgun1){
start=person[j].playercoords+DoRotation(person[j].skeleton.joints[rightwrist].position,0,person[j].playerrotation,0);
start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.55-.4);
}
if(person[j].whichgun==handgun2){
start=person[j].playercoords+DoRotation(person[j].skeleton.joints[rightwrist].position,0,person[j].playerrotation,0);
start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.55-.4);
}
if(person[j].whichgun==assaultrifle){
start=person[j].playercoords+DoRotation(person[j].skeleton.joints[lefthand].position,0,person[j].playerrotation,0);
start-=DoRotation(DoRotation(DoRotation(aim,0,-person[j].playerrotation,0),90,0,0),0,person[j].playerrotation,0)*(.25-.4);
}
end=start+aim*1000;
// Blocks
wallhit = {};
beginx=(person[j].playercoords.x+block_spacing/2)/block_spacing-2;
if(beginx<0)beginx=0;
beginz=(person[j].playercoords.z+block_spacing/2)/block_spacing-2;
if(beginz<0)beginz=0;
endx=(person[j].playercoords.x+block_spacing/2)/block_spacing+2;
if(endx>num_blocks-1)endx=num_blocks-1;
endz=(person[j].playercoords.z+block_spacing/2)/block_spacing+2;
if(endz>num_blocks-1)endz=num_blocks-1;
if(beginx0){
wherex=(sprites.location[i].x+block_spacing/2)/block_spacing;
wherey=(sprites.location[i].z+block_spacing/2)/block_spacing;
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=1;
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*.02;
ReflectVector(&sprites.velocity[i],&normalrotated);
sprites.velocity[i]*=.3;
if (sprites.type[i] == grenadesprite
&& sprites.size[i] <= 1) {
auto soundpos = sprites.location[i] - camera.position;
auto v = findLengthfast(sprites.velocity[i]) * 0.2f;
ALfloat gLoc[] {
soundpos.x / v / soundscalefactor,
soundpos.y / v / soundscalefactor,
soundpos.z / v / soundscalefactor,
};
whichsound = bouncesound + randUint(2);
alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
alSourcePlay(gSourceID[whichsound]);
}
if (findLengthfast(sprites.velocity[i]) <= 10)
sprites.velocity[i] = {};
}
if(sprites.location[i].y<0){
impact=1;
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 = findLengthfast(sprites.velocity[i]) * 0.2f;
ALfloat gLoc[] {
soundpos.x / v / soundscalefactor,
soundpos.y / v / soundscalefactor,
soundpos.z / v / soundscalefactor,
};
whichsound = bouncesound + randUint(2);
alSourcefv(gSourceID[whichsound], AL_POSITION, gLoc);
if (sprites.size[i] <= 1)
alSourcePlay(gSourceID[whichsound]);
}
if (findLengthfast(sprites.velocity[i]) <= 10)
sprites.velocity[i] = {};
}
if(sprites.type[i]==grenadesprite&&findLengthfast(sprites.velocity[i])>20){
HitStruct hitstruct;
for(int j=0;jlabel==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 = findDistancefast(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 (findLengthfast(joint.offset) > 9) {
Normalise(&joint.offset);
joint.offset *= 3;
}
}
}}
sprites.velocity[i]*=-.3;
}
}
}
}
sprites.oldlocation[i]=sprites.location[i];
}
//Explode
if(sprites.type[i]==grenadesprite){
sprites.brightness[i]-=multiplier*.3;
if(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;
//if(!sprites.size[i]>1){
overpoint=sprites.location[i];
overpoint.y+=3000;
underpoint=sprites.location[i];
underpoint.y-=3000;
wherex=(sprites.location[i].x+block_spacing/2)/block_spacing;
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=1)){
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((findDistancefast(person[k].playercoords,sprites.location[i])<600&&person[k].skeleton.free<1)||(findDistancefast(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 = joint.position - sprites.location[i];
Normalise(&relation);
auto distance = findDistance(joint.position, sprites.location[i]);
if (distance > 1)
joint.velocity += relation / distance * 300;
else
joint.velocity += relation * 300;
// Sever stuff
if (findLengthfast(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;i0&&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;
}