diff --git a/source/src/bot/ac_bot.cpp b/source/src/bot/ac_bot.cpp index e6469117..a763a120 100644 --- a/source/src/bot/ac_bot.cpp +++ b/source/src/bot/ac_bot.cpp @@ -10,6 +10,8 @@ // // +#include "pch.h" +#include "cube.h" #include "bot.h" #ifdef AC_CUBE diff --git a/source/src/bot/ac_bot_ai.cpp b/source/src/bot/ac_bot_ai.cpp index a3bdfc77..8ca5f5d3 100644 --- a/source/src/bot/ac_bot_ai.cpp +++ b/source/src/bot/ac_bot_ai.cpp @@ -8,7 +8,8 @@ // - +#include "pch.h" +#include "cube.h" #include "bot.h" #ifdef AC_CUBE @@ -83,8 +84,8 @@ bool CACBot::ChoosePreferredWeapon() SelectGun(bestWeapon); if(!m_pMyEnt->mag[bestWeapon]) { - reload(m_pMyEnt); - m_iShootDelay = lastmillis + reloadtime(bestWeapon) + 10; + tryreload(m_pMyEnt); + m_iShootDelay = lastmillis + reloadtime(bestWeapon) + 10; } return true; } diff --git a/source/src/bot/bot.cpp b/source/src/bot/bot.cpp index 2cd11207..d6289296 100644 --- a/source/src/bot/bot.cpp +++ b/source/src/bot/bot.cpp @@ -10,6 +10,8 @@ // // +#include "pch.h" +#include "cube.h" #include "bot.h" vector bots; @@ -302,7 +304,7 @@ float CBot::GetDistance(entity *e) bool CBot::SelectGun(int Gun) { - if(m_pMyEnt->reloading) return false; + if(m_pMyEnt->weaponsel->reloading) return false; if (m_pMyEnt->gunselect != Gun) playsound(S_GUNCHANGE, m_pMyEnt); m_pMyEnt->gunselect = Gun; return true; diff --git a/source/src/bot/bot_ai.cpp b/source/src/bot/bot_ai.cpp index c71079a1..4c299a87 100644 --- a/source/src/bot/bot_ai.cpp +++ b/source/src/bot/bot_ai.cpp @@ -10,6 +10,8 @@ // Code of CBot - Start +#include "pch.h" +#include "cube.h" #include "bot.h" extern weaponinfo_s WeaponInfoTable[MAX_WEAPONS]; @@ -771,7 +773,7 @@ void CBot::CheckReload() // reload gun if no enemies are around { if(m_pMyEnt->enemy) return; SelectGun(m_pMyEnt->primary); - reload(m_pMyEnt); + tryreload(m_pMyEnt); return; } diff --git a/source/src/bot/bot_util.cpp b/source/src/bot/bot_util.cpp index 27511af1..224843fa 100644 --- a/source/src/bot/bot_util.cpp +++ b/source/src/bot/bot_util.cpp @@ -10,6 +10,8 @@ // // +#include "pch.h" +#include "cube.h" #include "bot.h" // Function code by PMB - Begin diff --git a/source/src/bot/bot_waypoint.cpp b/source/src/bot/bot_waypoint.cpp index 9512b868..110389e8 100644 --- a/source/src/bot/bot_waypoint.cpp +++ b/source/src/bot/bot_waypoint.cpp @@ -7,6 +7,8 @@ // Author: Rick // +#include "pch.h" +#include "cube.h" #include "bot.h" vec v_debuggoal = g_vecZero; diff --git a/source/src/bot/botmanager.cpp b/source/src/bot/botmanager.cpp index 1de2a744..72e373a3 100644 --- a/source/src/bot/botmanager.cpp +++ b/source/src/bot/botmanager.cpp @@ -10,8 +10,11 @@ // // +#include "pch.h" +#include "cube.h" #include "bot.h" + #ifndef VANILLA_CUBE // UNDONE bool dedserv = false; #define CS_DEDHOST 0xFF diff --git a/source/src/client.cpp b/source/src/client.cpp index 14498fcc..8b8a2d75 100644 --- a/source/src/client.cpp +++ b/source/src/client.cpp @@ -1,5 +1,6 @@ // client.cpp, mostly network related client game code +#include "pch.h" #include "cube.h" #include "bot/bot.h" @@ -342,7 +343,7 @@ void sendintro() putint(p, SV_CONNECT); sendstring(clientpassword, p); clientpassword[0] = '\0'; - putint(p, player1->nextprimary); + putint(p, player1->nextprimweap->type); enet_packet_resize(packet, p.length()); sendpackettoserv(1, packet); } diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 409b73df..05b8cc5b 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -1,5 +1,6 @@ // clientgame.cpp: core game related stuff +#include "pch.h" #include "cube.h" #include "bot/bot.h" @@ -126,7 +127,7 @@ COMMANDN(team, newteam, ARG_1STR); COMMANDN(name, newname, ARG_1STR); COMMANDN(skin, newskin, ARG_1INT); -extern void thrownade(playerent *d, const vec &vel, bounceent *p); +//extern void thrownade(playerent *d, const vec &vel, bounceent *p); void deathstate(playerent *pl) { @@ -162,6 +163,7 @@ playerent *newplayerent() // create a new blank player d->lastupdate = lastmillis; setskin(d, rnd(6)); spawnstate(d); + weapon::equipplayer(d); return d; } @@ -171,6 +173,7 @@ botent *newbotent() // create a new blank player d->lastupdate = lastmillis; setskin(d, rnd(6)); spawnstate(d); + weapon::equipplayer(d); loopv(players) if(i!=getclientnum() && !players[i]) { players[i] = d; @@ -191,18 +194,6 @@ void freebotent(botent *d) } } -void checkakimbo() -{ - if(player1->akimbo && player1->akimbomillis && player1->akimbomillis<=lastmillis) - { - player1->akimbo = 0; - player1->akimbomillis = 0; - player1->mag[GUN_PISTOL] = min(magsize(GUN_PISTOL), player1->mag[GUN_PISTOL]); - if(player1->gunselect==GUN_PISTOL) weaponswitch(GUN_PISTOL); - playsoundc(S_PUPOUT); - } -} - void zapplayer(playerent *&d) { removebounceents(d); @@ -266,16 +257,13 @@ void updateworld(int curtime, int lastmillis) // main game update loop } } physicsframe(); - checkakimbo(); checkweaponswitch(); - //if(m_arena) arenarespawn(); - //arenarespawn(); + checkakimbo(); moveprojectiles((float)curtime); if(getclientnum()>=0) shoot(player1, worldpos); // only shoot when connected to server gets2c(); // do this first, so we have most accurate information when our player moves movebounceents(); moveotherplayers(); - //monsterthink(); // Added by Rick: let bots think if(m_botmode) BotManager.Think(); @@ -370,8 +358,8 @@ bool tryrespawn() player1->attacking = false; if(m_arena) { conoutf("waiting for new round to start..."); return false; } respawnself(); - weaponswitch(player1->primary); - player1->lastaction -= WEAPONCHANGE_TIME/2; + weaponswitch(player1->primweap); + player1->lastaction -= weapon::weaponchangetime/2; return true; } return false; @@ -427,12 +415,13 @@ void dokill(playerent *pl, playerent *act, bool gib) if(pl==player1) { - if(pl->inhandnade) thrownade(pl, vec(0,0,0), pl->inhandnade); + // FIXME!!! + //if(pl->inhandnade) thrownade(pl, vec(0,0,0), pl->inhandnade); if(m_ctf) tryflagdrop(pl!=act && isteam(act->team, pl->team)); } if(gib) { - if(pl!=act && act->gunselect == GUN_SNIPER) playsound(S_HEADSHOT); + if(pl!=act && act->weaponsel->type == GUN_SNIPER) playsound(S_HEADSHOT); addgib(pl); } if(!m_mp(gamemode)) diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 1cc05783..56743828 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -1,5 +1,6 @@ // client processing of the incoming network stream +#include "pch.h" #include "cube.h" #include "bot/bot.h" @@ -243,8 +244,8 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) int ls = getint(p), gunselect = getint(p); if(!d) break; d->lifesequence = ls; - d->gunselect = gunselect; d->state = CS_SPAWNING; + d->selectweapon(gunselect); break; } @@ -257,8 +258,8 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) player1->lifesequence = getint(p); player1->health = getint(p); player1->armour = getint(p); - player1->primary = getint(p); - player1->gunselect = getint(p); + player1->setprimary(getint(p)); + player1->selectweapon(getint(p)); loopi(NUMGUNS) player1->ammo[i] = getint(p); loopi(NUMGUNS) player1->mag[i] = getint(p); player1->state = CS_ALIVE; @@ -269,7 +270,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) conoutf("new round starting... fight!"); if(m_botmode) BotManager.RespawnBots(); } - addmsg(SV_SPAWN, "rii", player1->lifesequence, player1->gunselect); + addmsg(SV_SPAWN, "rii", player1->lifesequence, player1->weaponsel->type); break; } @@ -283,8 +284,12 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) if(!s) break; if(gun==GUN_SHOTGUN) createrays(from, to); s->lastaction = lastmillis; - s->lastattackgun = s->gunselect; - shootv(gun, from, to, s, false, -1); + //s->lastattackweapon = s->weaponsel; + if(s->weapons[gun]) + { + s->lastattackweapon = s->weapons[gun]; + s->weapons[gun]->attackfx(from, to, -1); + } break; } @@ -296,8 +301,8 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) int nademillis = getint(p); if(!d) break; d->lastaction = lastmillis; - d->lastattackgun = GUN_GRENADE; - shootv(GUN_GRENADE, from, to, d, false, nademillis); + d->lastattackweapon = d->weapons[GUN_GRENADE]; + if(d->weapons[GUN_GRENADE]) d->weapons[GUN_GRENADE]->attackfx(from, to, nademillis); break; } @@ -351,9 +356,9 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) if(!d) continue; if(d!=player1) d->state = state; d->lifesequence = lifesequence; - d->gunselect = gunselect; d->flagscore = flagscore; d->frags = frags; + d->selectweapon(gunselect); } break; } @@ -437,7 +442,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) case SV_WEAPCHANGE: { if(!d) return; - d->gunselect = getint(p); + d->selectweapon(getint(p)); break; } diff --git a/source/src/command.cpp b/source/src/command.cpp index 1801a881..e8ad58a9 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -1,6 +1,7 @@ // command.cpp: implements the parsing and execution of a tiny script language which // is largely backwards compatible with the quake console language. +#include "pch.h" #include "cube.h" char *exchangestr(char *o, char *n) { delete[] o; return newstring(n); } diff --git a/source/src/console.cpp b/source/src/console.cpp index 17cd6354..871ff663 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -1,5 +1,6 @@ // console.cpp: the console buffer, its display, and command line control +#include "pch.h" #include "cube.h" #define CONSPAD (FONTH/3) diff --git a/source/src/cube.h b/source/src/cube.h index bef3bdde..d622bc0b 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -1,61 +1,13 @@ #ifndef __CUBE_H__ #define __CUBE_H__ -#ifdef __GNUC__ -#define gamma __gamma -#endif - -#include - -#ifdef __GNUC__ -#undef gamma -#endif - -#include -#ifdef WIN32 - #define strcasecmp(a,b) _stricmp(a,b) -#endif -#include -#include -#include -#include -#include -#ifdef __GNUC__ -#include -#else -#include -#endif - -#ifdef WIN32 - #define WIN32_LEAN_AND_MEAN - #include "windows.h" - #define _WINDOWS - #define ZLIB_DLL -#endif - -#ifndef STANDALONE -#include -#include - -#define GL_GLEXT_LEGACY -#define __glext_h__ -#define NO_SDL_GLEXT -#include -#undef __glext_h__ - -#include "GL/glext.h" -#endif - -#include - -#include - #include "tools.h" #include "geom.h" #include "world.h" #include "model.h" #include "protocol.h" #include "sound.h" +#include "weapon.h" #include "entity.h" #include "command.h" #include "vote.h" diff --git a/source/src/docs.cpp b/source/src/docs.cpp index fc7f7282..c8a35fa2 100644 --- a/source/src/docs.cpp +++ b/source/src/docs.cpp @@ -1,5 +1,6 @@ // docs.cpp: ingame command documentation system +#include "pch.h" #include "cube.h" void renderdocsection(void *menu, bool init); diff --git a/source/src/editing.cpp b/source/src/editing.cpp index 1afc87b7..3ca132e7 100644 --- a/source/src/editing.cpp +++ b/source/src/editing.cpp @@ -1,5 +1,6 @@ // editing.cpp: most map editing commands go here, entity editing commands are in world.cpp +#include "pch.h" #include "cube.h" bool editmode = false; diff --git a/source/src/entities.cpp b/source/src/entities.cpp index db53eb81..a6d5fdc6 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -1,5 +1,6 @@ // entities.cpp: map entity related functions (pickup etc.) +#include "pch.h" #include "cube.h" vector ents; @@ -12,6 +13,7 @@ char *entnames[] = "mapmodel", "trigger", "ladder", "ctf-flag", "sound", "?", "?", }; + char *entmdlnames[] = { //FIXME : fix the "pickups" infront @@ -81,27 +83,20 @@ void pickupeffects(int n, playerent *d) if(d==player1) playsoundc(is.sound); else playsound(is.sound, d); } + + weapon *w = NULL; switch(e.type) { - case I_GRENADE: - d->thrownademillis = 0; - break; - - case I_AKIMBO: - d->akimbomillis = lastmillis+30000; - if(d==player1) - { - if(d->gunselect!=GUN_SNIPER && !d->inhandnade) weaponswitch(GUN_PISTOL); - addmsg(SV_AKIMBO, "ri", lastmillis); - } - break; + case I_AKIMBO: w = d->weapons[GUN_AKIMBO]; break; + case I_CLIPS: w = d->weapons[GUN_PISTOL]; break; + case I_AMMO: w = d->primweap; break; + case I_GRENADE: w = d->weapons[GUN_GRENADE]; break; } + if(w) w->onammopicked(); } // these functions are called when the client touches the item -// these functions are called when the client touches the item - void trypickup(int n, playerent *d) { entity &e = ents[n]; @@ -141,68 +136,6 @@ void trypickup(int n, playerent *d) } } -#if 0 -void additem(playerent *d, int i, int &v, int spawnsec, int t) -{ - if(vtype==ENT_PLAYER) addmsg(SV_ITEMPICKUP, "rii", i, spawnsec); - else if(d->type==ENT_BOT && serverpickup(i, spawnsec, -1)) realpickup(i, d); - ents[i].spawned = false; - } -} - -void pickup(int n, playerent *d) -{ - int np = 1; - loopv(players) if(players[i]) np++; - np = np<3 ? 4 : (np>4 ? 2 : 3); // spawn times are dependent on number of players - int ammo = np*2; - switch(ents[n].type) - { - case I_CLIPS: - additem(d, n, d->ammo[1], ammo, 1); - break; - case I_AMMO: - additem(d, n, d->ammo[d->primary], ammo, d->primary); - break; - case I_GRENADE: additem(d, n, d->mag[6], ammo, 6); break; - case I_HEALTH: additem(d, n, d->health, np*5, 7); break; - - case I_ARMOUR: - additem(d, n, d->armour, 20, 8); - break; - - case I_AKIMBO: - additem(d, n, d->akimbo, 60, 9); - break; - - case LADDER: - d->onladder = true; - break; - - case CTF_FLAG: - { - if(d==player1) - { - int flag = ents[n].attr2; - flaginfo &f = flaginfos[flag]; - flaginfo &of = flaginfos[team_opposite(flag)]; - if(f.state == CTFF_STOLEN) break; - - if(flag == team_int(d->team)) // its the own flag - { - if(f.state == CTFF_DROPPED) flagreturn(); - else if(f.state == CTFF_INBASE && of.state == CTFF_STOLEN && of.actor == d && of.ack) flagscore(); - } - else flagpickup(); - } - break; - } - } -} -#endif - void checkitems(playerent *d) { if(editmode) return; @@ -254,7 +187,7 @@ void resetspawns() } void setspawn(int i, bool on) { if(ents.inrange(i)) ents[i].spawned = on; } -void item(int num) +void selectnextprimary(int num) { switch(num) { @@ -267,12 +200,12 @@ void item(int num) break; default: - conoutf("sorry, you can't use that item yet"); + conoutf("this is not a valid primary weapon"); break; } } -COMMAND(item,ARG_1INT); +COMMANDN(nextprimary, selectnextprimary, ARG_1INT); // Added by Rick bool intersect(entity *e, vec &from, vec &to, vec *end) // if lineseg hits entity bounding box(entity version) diff --git a/source/src/entity.h b/source/src/entity.h index ae1364cd..bc1b4589 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -38,40 +38,40 @@ static itemstat ammostats[] = {60, 90, 90, S_ITEMAMMO}, //subgun {10, 20, 15, S_ITEMAMMO}, //sniper {30, 60, 60, S_ITEMAMMO}, //assault - {2, 0, 2, S_ITEMAMMO} //grenade + {2, 0, 2, S_ITEMAMMO}, //grenade + {72, 0, 72, S_ITEMAKIMBO} //akimbo }; static itemstat powerupstats[] = { {33, 100, 100, S_ITEMHEALTH}, //health {50, 100, 100, S_ITEMARMOUR}, //armour - {16, 0, 72, S_ITEMPUP} //powerup + //{16, 0, 72, S_ITEMPUP} //powerup }; -enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSAULT, GUN_GRENADE, NUMGUNS }; +enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSAULT, GUN_GRENADE, GUN_AKIMBO, NUMGUNS }; #define reloadable_gun(g) (g != GUN_KNIFE && g != GUN_GRENADE) #define SGRAYS 21 #define SGSPREAD 2 #define EXPDAMRAD 10 -struct guninfo { short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back, recoilincrease, recoilbase, maxrecoil, recoilbackfade; bool isauto; }; +struct guninfo { string modelname; short sound, reload, reloadtime, attackdelay, damage, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back, recoilincrease, recoilbase, maxrecoil, recoilbackfade; bool isauto; }; static guninfo guns[NUMGUNS] = { - { S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, false }, - { S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, 1, 40, 75, 150, false }, // *SGRAYS - { S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, 1, 130, 500, 150, false }, //reload time is for 1 shell from 7 too powerful to 6 - { S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, 3, 20, 60, 200, true }, - { S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, 1, 100, 500, 100, false }, - { S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, 2, 25, 60, 150, true }, //recoil was 44 - { S_NULL, S_NULL, 1000, 650, 150, 20, 6, 1, 1, 1, 3, 1, 0, 0, 0, 0, false }, + { "knife", S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, false }, + { "pistol", S_PISTOL, S_RPISTOL, 1400, 170, 19, 0, 0, 80, 10, 8, 6, 5, 1, 40, 75, 150, false }, + { "shotgun", S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, 1, 130, 500, 150, false }, + { "subgun", S_SUBGUN, S_RSUBGUN, 1650, 80, 16, 0, 0, 70, 15, 30, 1, 2, 3, 20, 60, 200, true }, + { "sniper", S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 60, 50, 5, 4, 4, 1, 100, 500, 100, false }, + { "assault", S_ASSAULT, S_RASSAULT, 2000, 130, 24, 0, 0, 20, 40, 15, 0, 2, 2, 25, 60, 150, true }, + { "grenade", S_NULL, S_NULL, 1000, 650, 150, 20, 6, 1, 1, 1, 3, 1, 0, 0, 0, 0, false }, + { "pistol", S_PISTOL, S_RAKIMBO, 1400, 85, 19, 0, 0, 80, 10, 16, 6, 5, 1, 40, 75, 150, true }, }; static inline int reloadtime(int gun) { return guns[gun].reloadtime; } static inline int attackdelay(int gun) { return guns[gun].attackdelay; } static inline int magsize(int gun) { return guns[gun].magsize; } -static inline int kick_rot(int gun) { return guns[gun].mdl_kick_rot; } -static inline int kick_back(int gun) { return guns[gun].mdl_kick_back; } #define isteam(a,b) (m_teammode && strcmp(a, b)==0) @@ -204,7 +204,7 @@ struct playerstate int health, armour; int primary, nextprimary; int gunselect; - int akimbo; + bool akimbo; int ammo[NUMGUNS], mag[NUMGUNS], gunwait[NUMGUNS]; playerstate() : primary(GUN_ASSAULT), nextprimary(GUN_ASSAULT) {} @@ -216,10 +216,9 @@ struct playerstate case I_CLIPS: return ammostats[GUN_PISTOL]; case I_AMMO: return ammostats[primary]; case I_GRENADE: return ammostats[GUN_GRENADE]; + case I_AKIMBO: return ammostats[GUN_AKIMBO]; case I_HEALTH: case I_ARMOUR: - case I_AKIMBO: - return powerupstats[type-I_HEALTH]; default: return *(itemstat *)0; } @@ -255,9 +254,9 @@ struct playerstate case I_HEALTH: additem(powerupstats[type-I_HEALTH], health); break; case I_ARMOUR: additem(powerupstats[type-I_HEALTH], armour); break; case I_AKIMBO: - akimbo = 1; - mag[GUN_PISTOL] = 2*magsize(GUN_PISTOL); - additem(powerupstats[type-I_HEALTH], ammo[GUN_PISTOL]); + akimbo = true; + mag[GUN_AKIMBO] = guns[GUN_AKIMBO].magsize; + additem(ammostats[GUN_AKIMBO], ammo[GUN_AKIMBO]); break; break; } } @@ -267,12 +266,12 @@ struct playerstate health = 100; armour = 0; gunselect = GUN_PISTOL; - akimbo = 0; + akimbo = false; loopi(NUMGUNS) ammo[i] = mag[i] = gunwait[i] = 0; ammo[GUN_KNIFE] = mag[GUN_KNIFE] = 1; } - void spawnstate(int gamemode) + virtual void spawnstate(int gamemode) { if(m_pistol) primary = GUN_PISTOL; else if(m_osok) primary = GUN_SNIPER; @@ -314,28 +313,27 @@ struct playerent : dynent, playerstate int lifesequence; // sequence id for each respawn, used in damage test int frags, flagscore; int deaths() { return lifesequence + (state==CS_DEAD ? 1 : 0); } - int lastaction, lastattackgun, lastmove, lastpain, lastteamkill; + int lastaction, lastmove, lastpain, lastteamkill; int clientrole; bool attacking; string name, team; - int shots; //keeps track of shots from auto weapons - int reloading, weaponchanging; + int weaponchanging; int nextweapon; // weapon we switch to int skin, nextskin; // skin after respawning int spectating, followplayercn; virtual float dyneyeheight() { return (state==CS_DEAD || state==CS_SPECTATE) && spectating==SM_FLY ? 1.0f : physent::dyneyeheight(); } bool allowmove() { return state!=CS_DEAD || spectating==SM_FLY; } + + weapon *weapons[NUMGUNS]; + weapon *weaponsel, *nextweaponsel, *primweap, *nextprimweap, *lastattackweapon; - int thrownademillis; struct bounceent *inhandnade; - int akimbolastaction[2]; - int akimbomillis; poshist history; // Previous stored locations of this player playerent() : clientnum(-1), plag(0), ping(0), lifesequence(0), frags(0), flagscore(0), lastpain(0), lastteamkill(0), clientrole(CR_DEFAULT), - shots(0), reloading(0), - skin(0), nextskin(0), spectating(SM_NONE), followplayercn(0), inhandnade(NULL) + skin(0), nextskin(0), spectating(SM_NONE), followplayercn(0), inhandnade(NULL), + weaponsel(NULL), nextweaponsel(NULL), primweap(NULL), nextprimweap(NULL), lastattackweapon(NULL) { type = ENT_PLAYER; name[0] = team[0] = 0; @@ -364,14 +362,26 @@ struct playerent : dynent, playerstate dynent::reset(); playerstate::respawn(); history.reset(); - lastaction = akimbolastaction[0] = akimbolastaction[1] = 0; - lastattackgun = -1; - akimbomillis = 0; + if(weaponsel) weaponsel->reset(); + lastaction = 0; + lastattackweapon = NULL; attacking = false; weaponchanging = 0; spectating = SM_NONE; followplayercn = 0; } + + void spawnstate(int gamemode) + { + playerstate::spawnstate(gamemode); + weaponsel = weapons[gunselect]; + primweap = weapons[primary]; + nextprimweap = weapons[nextprimary]; + } + + void selectweapon(int w) { weaponsel = weapons[(gunselect = w)]; } + void setprimary(int w) { primweap = weapons[(primary = w)]; } + void setnextprimary(int w) { nextprimweap = weapons[(nextprimary = w)]; } }; class CBot; @@ -422,12 +432,11 @@ struct bounceent : physent // nades, gibs eyeheight = 0.3f; aboveeye = 0.0f; } + + virtual ~bounceent() {} + + bool isalive(int lastmillis) { return lastmillis - millis < timetolife; } + virtual void destroy() {} }; -#define NADE_IN_HAND (player1->gunselect==GUN_GRENADE && player1->inhandnade) -#define NADE_THROWING (player1->gunselect==GUN_GRENADE && player1->thrownademillis && !player1->inhandnade) -#define NADE_THROW_TIME ((13*1000)/40) -#define has_akimbo(d) ((d)->gunselect==GUN_PISTOL && (d)->akimbo) - -#define WEAPONCHANGE_TIME 400 diff --git a/source/src/hudgun.cpp b/source/src/hudgun.h similarity index 56% rename from source/src/hudgun.cpp rename to source/src/hudgun.h index 9ad25242..049cb06b 100644 --- a/source/src/hudgun.cpp +++ b/source/src/hudgun.h @@ -1,5 +1,3 @@ -#include "cube.h" - VARP(nosway, 0, 0, 1); VARP(swayspeeddiv, 1, 105, 1000); VARP(swaymovediv, 1, 200, 1000); @@ -42,45 +40,36 @@ struct weaponmove if(player1->weaponchanging) { anim = ANIM_GUN_RELOAD; - float progress = (lastmillis - player1->weaponchanging)/(float) WEAPONCHANGE_TIME; - if(progress >= 1.0f || progress < 0.0f) progress = 1.0f; + float progress = max(0.0f, min(1.0f, (lastmillis - player1->weaponchanging)/(float) weapon::weaponchangetime)); k_rot = -(sinf((float)(progress*2*90.0f)*PI/180.0f)*90); } - else if(player1->reloading) + else if(player1->weaponsel->reloading) { anim = ANIM_GUN_RELOAD; - float progress = (lastmillis - player1->reloading)/(float)reloadtime(player1->gunselect); - if(progress >= 1.0f || progress < 0) progress = 1.0f; + float progress = max(0.0f, min(1.0f, (lastmillis - player1->weaponsel->reloading)/(float)player1->weaponsel->info.reloadtime)); k_rot = -(sinf((float)(progress*2*90.0f)*PI/180.0f)*90); } else { int timediff = lastmillis-basetime, - animtime = min(player1->gunwait[player1->gunselect], attackdelay(player1->gunselect)); + animtime = min(player1->weaponsel->gunwait, player1->weaponsel->info.attackdelay); vec sway = base; float progress = 0.0f; float k_back = 0.0f; - if(player1->gunselect==player1->lastattackgun) + if(player1->weaponsel==player1->lastattackweapon) { - progress = timediff/(float)animtime; - if(progress > 100.0f || progress < 0) progress = 1.0f; + progress = max(0.0f, min(1.0f, timediff/(float)animtime)); // f(x) = -sin(x-1.5)^3 kick = -sinf(pow((1.5f*progress)-1.5f,3)); if(player1->crouching) kick *= 0.75f; + if(player1->lastaction) anim = player1->weaponsel->modelanim(); } - if(player1->lastaction && player1->lastattackgun==player1->gunselect) + if(player1->weaponsel->info.mdl_kick_rot || player1->weaponsel->info.mdl_kick_back) { - if(NADE_THROWING && timedifflastactiongunselect!=GUN_KNIFE && player1->gunselect!=GUN_GRENADE ? ANIM_LOOP : 0); - } - - if(player1->gunselect!=GUN_GRENADE && player1->gunselect!=GUN_KNIFE) - { - k_rot = kick_rot(player1->gunselect)*kick; - k_back = kick_back(player1->gunselect)*kick/10; + k_rot = player1->weaponsel->info.mdl_kick_rot*kick; + k_back = player1->weaponsel->info.mdl_kick_back*kick/10; } if(nosway) sway.x = sway.y = sway.z = 0; @@ -117,45 +106,11 @@ struct weaponmove vec weaponmove::swaydir(0, 0, 0); int weaponmove::lastsway = 0, weaponmove::swaymillis = 0; -VARP(hudgun,0,1,1); - -void renderhudgun(int gun, int lastaction, int index = 0) -{ - vec unitv; - float dist = worldpos.dist(player1->o, unitv); - unitv.div(dist); - - weaponmove wm; - if(!intermission) wm.calcmove(unitv, lastaction); - s_sprintfd(path)("weapons/%s", gunnames[gun]); - static int lastanim[2], lastswitch[2]; - if(lastanim[index]!=(wm.anim|(gun<<16))) - { - lastanim[index] = wm.anim|(gun<<16); - lastswitch[index] = lastmillis; - } - rendermodel(path, wm.anim|(index ? ANIM_MIRROR : 0), 0, 0, wm.pos, player1->yaw+90, player1->pitch+wm.k_rot, 40.0f, lastswitch[index], NULL, NULL, 1.28f); -} - -void renderhudgun() -{ - if(!hudgun) return; - if(player1->akimbo && player1->gunselect==GUN_PISTOL) // akimbo - { - renderhudgun(GUN_PISTOL, player1->akimbolastaction[0], 0); - renderhudgun(GUN_PISTOL, player1->akimbolastaction[1], 1); - } - else - { - renderhudgun(player1->gunselect, player1->lastaction); - } -} - void preload_hudguns() { loopi(NUMGUNS) { - s_sprintfd(path)("weapons/%s", gunnames[i]); + s_sprintfd(path)("weapons/%s", guns[i].modelname); loadmodel(path); } } diff --git a/source/src/main.cpp b/source/src/main.cpp index f84adec5..14719c3a 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -1,5 +1,6 @@ // main.cpp: initialisation & main loop +#include "pch.h" #include "cube.h" void cleanup(char *msg) // single program exit point; diff --git a/source/src/menus.cpp b/source/src/menus.cpp index 06301cbb..b3e47361 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -1,5 +1,6 @@ // menus.cpp: ingame menu system (also used for scores and serverlist) +#include "pch.h" #include "cube.h" hashtable menus; diff --git a/source/src/pch.cpp b/source/src/pch.cpp index 5b241e7f..1d9f38c5 100644 --- a/source/src/pch.cpp +++ b/source/src/pch.cpp @@ -1 +1 @@ -#include "cube.h" +#include "pch.h" diff --git a/source/src/pch.h b/source/src/pch.h new file mode 100644 index 00000000..5f924215 --- /dev/null +++ b/source/src/pch.h @@ -0,0 +1,49 @@ +#ifdef __GNUC__ +#define gamma __gamma +#endif + +#include + +#ifdef __GNUC__ +#undef gamma +#endif + +#include +#ifdef WIN32 + #define strcasecmp(a,b) _stricmp(a,b) +#endif +#include +#include +#include +#include +#include +#ifdef __GNUC__ +#include +#else +#include +#endif + +#ifdef WIN32 + #define WIN32_LEAN_AND_MEAN + #include "windows.h" + #define _WINDOWS + #define ZLIB_DLL +#endif + +#ifndef STANDALONE +#include +#include + +#define GL_GLEXT_LEGACY +#define __glext_h__ +#define NO_SDL_GLEXT +#include +#undef __glext_h__ + +#include "GL/glext.h" +#else +#include "SDL_endian.h" +#endif + +#include +#include \ No newline at end of file diff --git a/source/src/physics.cpp b/source/src/physics.cpp index ac12b559..8c1c013c 100644 --- a/source/src/physics.cpp +++ b/source/src/physics.cpp @@ -3,6 +3,7 @@ // they "felt right", and have no basis in reality. Collision detection is simplistic but // very robust (uses discrete steps at fixed fps). +#include "pch.h" #include "cube.h" float raycube(const vec &o, const vec &ray, vec &surface) @@ -425,12 +426,13 @@ void moveplayer(physent *pl, int moveres, bool local, int curtime) } // smooth pitch - if(pl == player1) + if(pl==player1) { + const float fric = 6.0f/curtime*20.0f; pl->pitch += pl->pitchvel*(curtime/1000.0f)*pl->maxspeed*(pl->crouching ? 0.75f : 1.0f); - pl->pitchvel *= fpsfric-3; - pl->pitchvel /= fpsfric; - if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= guns[((playerent *)pl)->gunselect].recoilbackfade/100.0f; // slide back + pl->pitchvel *= fric-3; + pl->pitchvel /= fric; + if(pl->pitchvel < 0.05f && pl->pitchvel > 0.001f) pl->pitchvel -= ((playerent *)pl)->weaponsel->info.recoilbackfade/100.0f; // slide back if(pl->pitchvel) fixcamerarange(pl); // fix pitch if necessary } } diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 2f841c0c..d1338e1e 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -1,5 +1,6 @@ // misc useful functions used by the server +#include "pch.h" #include "cube.h" // all network traffic is in 32bit ints, which are then compressed using the following simple scheme (assumes that most values are small). diff --git a/source/src/protos.h b/source/src/protos.h index 5a2c740d..f463367c 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -369,18 +369,11 @@ extern void renderclients(); extern void renderclient(playerent *d); extern void renderclient(playerent *d, char *mdlname, char *vwepname, int tex = 0); -// hudgun -extern char *gunnames[]; -extern void renderhudgun(); - // weapon extern bool scoped; - extern void shoot(playerent *d, vec &to); -extern void shootv(int gun, vec &from, vec &to, playerent *d = 0, bool local = false, int nademillis=0); extern void createrays(vec &from, vec &to); extern void moveprojectiles(float time); -extern bounceent *newbounceent(); extern void removebounceents(playerent *owner); extern void movebounceents(); extern void clearbounceents(); @@ -389,19 +382,15 @@ extern void addgib(playerent *d); extern void projreset(); extern void removeprojectiles(playerent *d); extern playerent *playerincrosshair(); -extern int reloadtime(int gun); -extern void reload(playerent *d); -extern int attackdelay(int gun); extern int magsize(int gun); -extern int kick_rot(int gun); -extern int kick_back(int gun); -extern bool akimboside; extern void checkweaponswitch(); -extern void weaponswitch(int gun); +extern void weaponswitch(weapon *w); extern void setscope(bool activate); extern bool intersect(dynent *d, const vec &from, const vec &to, vec *end = NULL); extern bool intersect(entity *e, const vec &from, const vec &to, vec *end = NULL); extern void damageeffect(int damage, playerent *d); +extern void tryreload(playerent *p); +extern void checkakimbo(); // entities extern char *entnames[]; diff --git a/source/src/rendercubes.cpp b/source/src/rendercubes.cpp index 572c2fad..4131e86b 100644 --- a/source/src/rendercubes.cpp +++ b/source/src/rendercubes.cpp @@ -1,5 +1,6 @@ // rendercubes.cpp: sits in between worldrender.cpp and rendergl.cpp and fills the vertex array for different cube surfaces. +#include "pch.h" #include "cube.h" vector verts; diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index ba8aeaa2..27bf3aaf 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -1,5 +1,6 @@ // rendergl.cpp: core opengl rendering stuff +#include "pch.h" #include "cube.h" #include "bot/bot.h" @@ -546,16 +547,18 @@ void drawminimap(int w, int h) int xtraverts; +VARP(hudgun, 0, 1, 1); + void drawhudgun(int w, int h, float aspect, int farplane) { - if(scoped && player1->gunselect==GUN_SNIPER) return; + if(scoped && player1->weaponsel->type==GUN_SNIPER) return; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective((float)100.0f*h/w, aspect, 0.3f, farplane); // fov fixed at 100° glMatrixMode(GL_MODELVIEW); - if(player1->state==CS_ALIVE) renderhudgun(); + if(hudgun && player1->state==CS_ALIVE) player1->weaponsel->renderhudmodel(); rendermenumdl(); glMatrixMode(GL_PROJECTION); diff --git a/source/src/renderhud.cpp b/source/src/renderhud.cpp index f933e47b..96734f0f 100644 --- a/source/src/renderhud.cpp +++ b/source/src/renderhud.cpp @@ -1,5 +1,6 @@ // renderhud.cpp: HUD rendering +#include "pch.h" #include "cube.h" void drawicon(Texture *tex, float x, float y, float s, int col, int row, float ts) @@ -112,7 +113,7 @@ void drawcrosshair(bool showteamwarning) else if(player1->health<=50) glColor3ub(255,128,0); } } - float chsize = (float)crosshairsize * (player1->gunselect==GUN_ASSAULT && player1->shots > 3 ? 1.4f : 1.0f) * (showteamwarning ? 2.0f : 1.0f); + float chsize = (float)crosshairsize * (player1->weaponsel->type==GUN_ASSAULT && player1->weaponsel->shots > 3 ? 1.4f : 1.0f) * (showteamwarning ? 2.0f : 1.0f); glTexCoord2i(0, 0); glVertex2f(VIRTW/2 - chsize, VIRTH/2 - chsize); glTexCoord2i(1, 0); glVertex2f(VIRTW/2 + chsize, VIRTH/2 - chsize); glTexCoord2i(1, 1); glVertex2f(VIRTW/2 + chsize, VIRTH/2 + chsize); @@ -131,11 +132,11 @@ void drawequipicons() drawequipicon(20, 1650, 1, 0, (player1->state!=CS_DEAD && player1->health<=20 && !m_osok)); // weapons - int c = player1->gunselect, r = 1; + int c = player1->weaponsel->type, r = 1; if(c==GUN_GRENADE) c = r = 0; else if(c>2) { c -= 3; r = 2; } - drawequipicon(1220, 1650, c, r, (!player1->mag[player1->gunselect] && player1->gunselect != GUN_KNIFE && player1->gunselect != GUN_GRENADE)); + drawequipicon(1220, 1650, c, r, (!player1->weaponsel->mag && player1->weaponsel->type != GUN_KNIFE && player1->weaponsel->type != GUN_GRENADE)); glEnable(GL_BLEND); } @@ -333,11 +334,11 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat bool menu = menuvisible(); bool command = getcurcommand() ? true : false; - if(player1->state==CS_ALIVE && !player1->reloading && !didteamkill && !menu) + if(player1->state==CS_ALIVE && !player1->weaponsel->reloading && !didteamkill && !menu) { bool drawteamwarning = targetplayer ? (isteam(targetplayer->team, player1->team) && targetplayer->state!=CS_DEAD) : false; - if(player1->gunselect==GUN_SNIPER && scoped) drawscope(); - else if((player1->gunselect!=GUN_SNIPER || drawteamwarning)) drawcrosshair(drawteamwarning); + if(player1->weaponsel->type==GUN_SNIPER && scoped) drawscope(); + else if((player1->weaponsel->type!=GUN_SNIPER || drawteamwarning)) drawcrosshair(drawteamwarning); } if(player1->state==CS_ALIVE) drawequipicons(); @@ -403,13 +404,7 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat glOrtho(0, VIRTW/2, VIRTH/2, 0, -1, 1); draw_textf("%d", 90, 827, player1->health); if(player1->armour) draw_textf("%d", 390, 827, player1->armour); - if(player1->gunselect!=GUN_KNIFE) - { - char gunstats[64]; - if(player1->gunselect!=GUN_GRENADE) sprintf(gunstats,"%i/%i",player1->mag[player1->gunselect],player1->ammo[player1->gunselect]); - else sprintf(gunstats,"%i",player1->mag[player1->gunselect]); - draw_text(gunstats, 690, 827); - } + player1->weaponsel->renderstats(); if(m_ctf && !hidectfhud) { diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 231a5e19..954a18af 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -1,3 +1,4 @@ +#include "pch.h" #include "cube.h" VARP(animationinterpolationtime, 0, 150, 1000); @@ -294,7 +295,7 @@ void preload_playermodels() if(dynshadow && playermdl) playermdl->genshadows(8.0f, 4.0f); loopi(NUMGUNS) { - s_sprintfd(vwep)("weapons/%s/world", gunnames[i]); + s_sprintfd(vwep)("weapons/%s/world", guns[i].modelname); model *vwepmdl = loadmodel(vwep); if(dynshadow && vwepmdl) vwepmdl->genshadows(8.0f, 4.0f); } @@ -360,7 +361,7 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) else if(d->state==CS_LAGGED) { anim = ANIM_SALUTE|ANIM_LOOP; } else if(lastmillis-d->lastpain<300) { anim = d->crouching ? ANIM_CROUCH_PAIN : ANIM_PAIN; speed = 300.0f/4; varseed += d->lastpain; basetime = d->lastpain; } else if(!d->onfloor && d->timeinair>50) { anim = ANIM_JUMP|ANIM_END; } - else if(d->gunselect==d->lastattackgun && lastmillis-d->lastaction<300) { anim = d->crouching ? ANIM_CROUCH_ATTACK : ANIM_ATTACK; speed = 300.0f/8; basetime = d->lastaction; } + else if(d->weaponsel==d->lastattackweapon && lastmillis-d->lastaction<300) { anim = d->crouching ? ANIM_CROUCH_ATTACK : ANIM_ATTACK; speed = 300.0f/8; basetime = d->lastaction; } else if(!d->move && !d->strafe) { anim = (d->crouching ? ANIM_CROUCH_IDLE : ANIM_IDLE)|ANIM_LOOP; } else { anim = (d->crouching ? ANIM_CROUCH_WALK : ANIM_RUN)|ANIM_LOOP; speed = 1860/d->maxspeed; } @@ -383,7 +384,7 @@ void renderclient(playerent *d) case 2: default: s_sprintf(skin)("%s/%s/%s.jpg", skinbase, team_string(team), team ? "blue" : "red"); break; } string vwep; - if(d->gunselect>=0 && d->gunselectgunselect]); + if(d->weaponsel) s_sprintf(vwep)("weapons/%s/world", d->weaponsel->info.modelname); else vwep[0] = 0; renderclient(d, "playermodels", vwep[0] ? vwep : NULL, -(int)textureload(skin)->id); } diff --git a/source/src/renderparticles.cpp b/source/src/renderparticles.cpp index ea5deb04..db32a5cb 100644 --- a/source/src/renderparticles.cpp +++ b/source/src/renderparticles.cpp @@ -1,5 +1,6 @@ // renderparticles.cpp +#include "pch.h" #include "cube.h" static GLushort *hemiindices = NULL; diff --git a/source/src/rendertext.cpp b/source/src/rendertext.cpp index aa6ffac4..99f9e44d 100644 --- a/source/src/rendertext.cpp +++ b/source/src/rendertext.cpp @@ -1,5 +1,6 @@ // rendertext.cpp: font rendering +#include "pch.h" #include "cube.h" int VIRTW; diff --git a/source/src/rndmap.cpp b/source/src/rndmap.cpp index 7da5d011..ea082fdb 100644 --- a/source/src/rndmap.cpp +++ b/source/src/rndmap.cpp @@ -1,5 +1,6 @@ // rndmap.cpp: perlin noise landscape generation and some experimental random map stuff, currently not used +#include "pch.h" #include "cube.h" float noise(int x, int y, int seed) diff --git a/source/src/scoreboard.cpp b/source/src/scoreboard.cpp index cd00108a..75d91e24 100644 --- a/source/src/scoreboard.cpp +++ b/source/src/scoreboard.cpp @@ -1,7 +1,8 @@ -#include "cube.h" - // creation of scoreboard pseudo-menu +#include "pch.h" +#include "cube.h" + void *scoremenu = NULL, *teammenu = NULL, *ctfmenu = NULL; void showscores(bool on) diff --git a/source/src/server.cpp b/source/src/server.cpp index 03bac7c5..70a8a5b2 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -9,6 +9,7 @@ #define _fileno fileno #endif +#include "pch.h" #include "cube.h" #include "servercontroller.h" diff --git a/source/src/serverbrowser.cpp b/source/src/serverbrowser.cpp index 76821614..dcaab123 100644 --- a/source/src/serverbrowser.cpp +++ b/source/src/serverbrowser.cpp @@ -1,5 +1,6 @@ // serverbrowser.cpp: eihrul's concurrent resolver, and server browser window management +#include "pch.h" #include "cube.h" #ifdef __APPLE__ #include diff --git a/source/src/serverms.cpp b/source/src/serverms.cpp index 1a19be90..9bc207aa 100644 --- a/source/src/serverms.cpp +++ b/source/src/serverms.cpp @@ -1,5 +1,6 @@ // all server side masterserver and pinging functionality +#include "pch.h" #include "cube.h" #ifdef STANDALONE diff --git a/source/src/sound.cpp b/source/src/sound.cpp index f1cbcefe..03922aaa 100644 --- a/source/src/sound.cpp +++ b/source/src/sound.cpp @@ -1,5 +1,6 @@ // sound.cpp: uses fmod on windows and sdl_mixer on unix (both had problems on the other platform) +#include "pch.h" #include "cube.h" //#ifndef WIN32 // NOTE: fmod not being supported for the moment as it does not allow stereo pan/vol updating during playback @@ -478,4 +479,3 @@ void playsoundc(int n) addmsg(SV_SOUND, "i", n); playsound(n); } - diff --git a/source/src/sound.h b/source/src/sound.h index 065292c6..f353b4de 100644 --- a/source/src/sound.h +++ b/source/src/sound.h @@ -10,8 +10,8 @@ enum S_SNIPER, S_RSNIPER, S_ASSAULT, S_RASSAULT, S_ITEMAMMO, S_ITEMHEALTH, - S_ITEMARMOUR, S_ITEMPUP, - S_NOAMMO, S_PUPOUT, + S_ITEMARMOUR, S_ITEMAKIMBO, + S_NOAMMO, S_AKIMBOOUT, S_PAIN1, S_PAIN2, S_PAIN3, S_PAIN4, S_PAIN5, S_PAIN6, //24 S_DIE1, S_DIE2, S_FEXPLODE, diff --git a/source/src/texture.cpp b/source/src/texture.cpp index b0ee5192..b7b8323c 100644 --- a/source/src/texture.cpp +++ b/source/src/texture.cpp @@ -1,5 +1,6 @@ // texture.cpp: texture management +#include "pch.h" #include "cube.h" Texture *notexture = NULL; diff --git a/source/src/tools.cpp b/source/src/tools.cpp index 74de3fec..fb8369e2 100644 --- a/source/src/tools.cpp +++ b/source/src/tools.cpp @@ -1,5 +1,6 @@ // implementation of generic tools +#include "pch.h" #include "cube.h" ///////////////////////// file system /////////////////////// @@ -246,15 +247,12 @@ bool cmpf(char *fn, enet_uint32 c) void endianswap(void *memory, int stride, int length) // little endian as storage format { -#ifdef SDL_BYTEORDER -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - loop(w, length) loop(i, stride/2) + static const int littleendian = 1; + if(!*(const char *)&littleendian) loop(w, length) loop(i, stride/2) { uchar *p = (uchar *)memory+w*stride; uchar t = p[i]; p[i] = p[stride-i-1]; p[stride-i-1] = t; } -#endif -#endif } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index ca9a8980..1e48f0f2 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -1,83 +1,65 @@ // weapon.cpp: all shooting and effects code +#include "pch.h" #include "cube.h" #include "bot/bot.h" +#include "hudgun.h" + +VARP(autoreload, 0, 1, 1); vec sg[SGRAYS]; -char *gunnames[NUMGUNS] = { "knife", "pistol", "shotgun", "subgun", "sniper", "assault", "grenade" }; - -int nadetimer = 2000; // detonate after $ms - -void updatelastaction(playerent *d, int millis = 0, bool akimbo = false) +void updatelastaction(playerent *d) { - millis += lastmillis; - loopi(NUMGUNS) if(d->gunwait[i]) d->gunwait[i] = max(d->gunwait[i] - (millis-d->lastaction), 0); - d->lastaction = millis; - if(akimbo) loopi(2) d->akimbolastaction[i] = millis; + loopi(NUMGUNS) d->weapons[i]->updatetimers(); + d->lastaction = lastmillis; } void checkweaponswitch() { if(!player1->weaponchanging) return; int timeprogress = lastmillis-player1->weaponchanging; - if(timeprogress>WEAPONCHANGE_TIME) + if(timeprogress>weapon::weaponchangetime) { - addmsg(SV_WEAPCHANGE, "ri", player1->gunselect); + addmsg(SV_WEAPCHANGE, "ri", player1->weaponsel->type); player1->weaponchanging = 0; } - else if(timeprogress>WEAPONCHANGE_TIME/2) - { - if((!player1->akimbo && player1->akimbomillis && player1->nextweapon==GUN_PISTOL) || - (player1->akimbo && !player1->akimbomillis && player1->gunselect==GUN_PISTOL)) - player1->akimbo = !player1->akimbo; - player1->gunselect = player1->nextweapon; - } + else if(timeprogress>weapon::weaponchangetime/2) player1->weaponsel = player1->nextweaponsel; } -void weaponswitch(int gun) +void weaponswitch(weapon *w) { + if(!w) return; + player1->weaponsel->ondeselecting(); player1->weaponchanging = lastmillis; - player1->thrownademillis = 0; - player1->nextweapon = gun; - playsound(S_GUNCHANGE); + player1->nextweaponsel = w; + w->onselecting(); } -void weapon(int gun) -{ - if(gun == player1->gunselect) return; - if(player1->state!=CS_ALIVE || player1->weaponchanging || NADE_IN_HAND || player1->reloading) return; - if(gun != GUN_KNIFE && gun != GUN_GRENADE && gun != GUN_PISTOL && gun != player1->primary) return; - - if(m_noguns && gun != GUN_KNIFE && gun != GUN_GRENADE) return; - if(m_noprimary && gun != GUN_KNIFE && gun != GUN_GRENADE && gun != GUN_PISTOL) return; - if(m_nopistol && gun == GUN_PISTOL) return; - if(gun == GUN_GRENADE && !player1->mag[GUN_GRENADE]) return; - - setscope(false); - weaponswitch(gun); -} +void selectweapon(weapon *w) { if(w && w->selectable()) weaponswitch(w); } +void selectweaponi(int w) { if(w >= 0 && w < NUMGUNS) selectweapon(player1->weapons[w]); } void shiftweapon(int s) { - if(player1->state==CS_ALIVE) + if(player1->state == CS_ALIVE) { for(int i = 0; i < NUMGUNS && !player1->weaponchanging; i++) { - int trygun = player1->gunselect + s + (s < 0 ? -i : i); + int trygun = player1->weaponsel->type + s + (s < 0 ? -i : i); if((trygun %= NUMGUNS) < 0) trygun += NUMGUNS; - weapon(trygun); + selectweapon(player1->weapons[trygun]); } } else toggledeathcam(); } -int currentprimary() { return player1->primary; } -int curweapon() { return player1->gunselect; } -int magcontent(int gun) { if(gun > 0 && gun < NUMGUNS) return player1->mag[gun]; else return -1;} -int magreserve(int gun) { if(gun > 0 && gun < NUMGUNS) return player1->ammo[gun]; else return -1;} +int currentprimary() { return player1->primweap->type; } +int curweapon() { return player1->weaponsel->type; } -COMMAND(weapon, ARG_1INT); +int magcontent(int w) { if(w > 0 && w < NUMGUNS) return player1->weapons[w]->mag; else return -1;} +int magreserve(int w) { if(w > 0 && w < NUMGUNS) return player1->weapons[w]->ammo; else return -1;} + +COMMANDN(weapon, selectweaponi, ARG_1INT); COMMAND(shiftweapon, ARG_1INT); COMMAND(currentprimary, ARG_1EST); COMMAND(curweapon, ARG_1EXP); @@ -90,7 +72,7 @@ int oldfov = 100; void setscope(bool activate) { - if(player1->gunselect != GUN_SNIPER || player1->state == CS_DEAD || player1->reloading) return; + if(player1->weaponsel->type != GUN_SNIPER || player1->state == CS_DEAD || player1->weaponsel->reloading) return; if(activate == scoped) return; if(activate) { @@ -106,30 +88,13 @@ void setscope(bool activate) COMMAND(setscope, ARG_1INT); -void reload(playerent *d) +void tryreload(playerent *p) { - if(!d || d->state!=CS_ALIVE || d->reloading || d->weaponchanging) return; - if(!reloadable_gun(d->gunselect) || d->ammo[d->gunselect]<=0) return; - if(d->mag[d->gunselect] >= (has_akimbo(d) ? 2 : 1)*guns[d->gunselect].magsize) return; - if(d == player1) setscope(false); - - updatelastaction(d, 0, true); - d->reloading = lastmillis; - d->gunwait[d->gunselect] += guns[d->gunselect].reloadtime; - - int numbullets = (has_akimbo(d) ? 2 : 1)*guns[d->gunselect].magsize - d->mag[d->gunselect]; - if(numbullets > d->ammo[d->gunselect]) numbullets = d->ammo[d->gunselect]; - d->mag[d->gunselect] += numbullets; - d->ammo[d->gunselect] -= numbullets; - - if(has_akimbo(d)) playsoundc(S_RAKIMBO); - else if(d->type==ENT_BOT) playsound(guns[d->gunselect].reload, d); - else playsoundc(guns[d->gunselect].reload); - - if(d==player1) addmsg(SV_RELOAD, "ri2", lastmillis, d->gunselect); + if(!p || p->state!=CS_ALIVE || p->weaponsel->reloading || p->weaponchanging) return; + p->weaponsel->reload(); } -void selfreload() { reload(player1); } +void selfreload() { tryreload(player1); } COMMANDN(reload, selfreload, ARG_NONE); void createrays(vec &from, vec &to) // create random spread of rays for the shotgun @@ -256,8 +221,11 @@ struct hitmsg int target, lifesequence, info; ivec dir; }; + vector hits; + + void hit(int damage, playerent *d, playerent *at, const vec &vel, int gun, bool gib, int info) { if(d==player1 || d->type==ENT_BOT || !m_mp(gamemode)) d->hitpush(damage, vel, at, gun); @@ -404,33 +372,22 @@ void moveprojectiles(float time) vector bounceents; -bounceent *newbounceent() -{ - bounceent *p = new bounceent; - bounceents.add(p); - return p; -} - void removebounceents(playerent *owner) { loopv(bounceents) if(bounceents[i]->owner==owner) { delete bounceents[i]; bounceents.remove(i--); } } -void explode_nade(bounceent *i); - void movebounceents() { loopv(bounceents) if(bounceents[i]) { bounceent *p = bounceents[i]; if(p->bouncestate == NADE_THROWED || p->bouncestate == GIB) moveplayer(p, 2, false); - - if(lastmillis - p->millis >= p->timetolife) + if(!p->isalive(lastmillis)) { - if(p->bouncestate==NADE_ACTIVATED || p->bouncestate==NADE_THROWED) explode_nade(bounceents[i]); + p->destroy(); delete p; - bounceents.remove(i); - i--; + bounceents.remove(i--); } } } @@ -486,7 +443,7 @@ void addgib(playerent *d) loopi(gibnum) { - bounceent *p = newbounceent(); + bounceent *p = bounceents.add(new bounceent()); p->owner = d; p->millis = lastmillis; p->timetolife = gibttl+rnd(10)*100; @@ -511,118 +468,6 @@ void addgib(playerent *d) } } -void thrownade(playerent *d, const vec &vel, bounceent *p) -{ - if(!d || !p) return; - vec dir(vel); - dir.mul(1.1f*d->radius); - p->vel = vel; - p->o.add(dir); - p->o.add(d->o); - loopi(10) moveplayer(p, 10, true, 10); - - p->bouncestate = NADE_THROWED; - d->thrownademillis = lastmillis; - d->inhandnade = NULL; - - playsound(S_GRENADETHROW); - - if(d==player1) - { - updatelastaction(player1); - addmsg(SV_THROWNADE, "ri7", int(d->o.x*DMF), int(d->o.y*DMF), int(d->o.z*DMF), int(vel.x*DMF), int(vel.y*DMF), int(vel.z*DMF), lastmillis-p->millis); - } -} - -void thrownade(playerent *d, bounceent *p) -{ - if(!d || !p) return; - const float speed = cosf(RAD*d->pitch); - vec vel(sinf(RAD*d->yaw)*speed, -cosf(RAD*d->yaw)*speed, sinf(RAD*d->pitch)); - vel.mul(1.5f); - thrownade(d, vel, p); -} - -bounceent *newnade(playerent *d, int millis = 0) -{ - bounceent *p = newbounceent(); - p->owner = d; - p->millis = lastmillis; - p->timetolife = 2000-millis; - p->bouncestate = NADE_ACTIVATED; - p->maxspeed = 27.0f; - p->rotspeed = 6.0f; - - d->inhandnade = p; - d->thrownademillis = 0; - return p; -} - -void explode_nade(bounceent *i) -{ - if(!i) return; - if(i->bouncestate != NADE_THROWED) thrownade(i->owner, vec(0,0,0), i); - playsound(S_FEXPLODE, NULL, NULL, &i->o); - newprojectile(i->o, i->o, 1, i->owner==player1, i->owner, GUN_GRENADE, i->millis); -} - -void shootv(int gun, vec &from, vec &to, playerent *d, bool local, int nademillis) // create visual effect from a shot -{ - if(guns[gun].sound != S_NULL) playsound(guns[gun].sound, d==player1 ? NULL : d); - switch(gun) - { - case GUN_KNIFE: - break; - - case GUN_SHOTGUN: - { - loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]); - if(addbullethole(from, to)) - { - int holes = 3+rnd(5); - loopi(holes) addbullethole(from, sg[i], 0); - } - break; - } - - case GUN_PISTOL: - case GUN_SUBGUN: - case GUN_ASSAULT: - { - addbullethole(from, to); - addshotline(d, from, to); - particle_splash(0, 5, 250, to); - break; - } - - case GUN_GRENADE: - { - if(d!=player1) - { - if(nademillis == -1) // activate - { - playsoundc(S_GRENADEPULL); - } - else if(nademillis >= 0) // throw - { - bounceent *p = newnade(d, nademillis); - thrownade(d, to, p); - } - } - break; - } - - case GUN_SNIPER: - { - addbullethole(from, to); - addshotline(d, from, to); - particle_splash(0, 50, 200, to); - particle_trail(1, 500, from, to); - break; - } - } -} - void shorten(vec &from, vec &to, vec &target) { target.sub(from).normalize().mul(from.dist(to)).add(from); @@ -633,9 +478,9 @@ vec hitpos; void raydamage(vec &from, vec &to, playerent *d) { - int gdam = guns[d->gunselect].damage; + int gdam = d->weaponsel->info.damage; playerent *o = NULL; - if(d->gunselect==GUN_SHOTGUN) + if(d->weaponsel->type==GUN_SHOTGUN) { uint done = 0; playerent *cl = NULL; @@ -655,15 +500,15 @@ void raydamage(vec &from, vec &to, playerent *d) } else raysleft = true; } - if(hitrays) hitpush(hitrays*gdam, o, d, from, to, d->gunselect, false, hitrays); + if(hitrays) hitpush(hitrays*gdam, o, d, from, to, d->weaponsel->type, false, hitrays); if(!raysleft) break; } } else if((o = intersectclosest(from, to, d))) { bool gib = false; - if(d->gunselect==GUN_KNIFE) gib = true; - else if(d==player1 && d->gunselect==GUN_SNIPER + if(d->weaponsel->type==GUN_KNIFE) gib = true; + else if(d==player1 && d->weaponsel->type==GUN_SNIPER && worldpos!=hitpos && hitpos.z>=o->o.z+o->aboveeye-HEADSIZE && intersect(o, from, hitpos)) { @@ -671,164 +516,533 @@ void raydamage(vec &from, vec &to, playerent *d) gib = true; } - hitpush(gdam, o, d, from, to, d->gunselect, gib, gib ? 1 : 0); + hitpush(gdam, o, d, from, to, d->weaponsel->type, gib, gib ? 1 : 0); shorten(from, o->o, to); } } -void spreadandrecoil(vec &from, vec &to, playerent *d) +weapon::weapon(struct playerent *owner, int type) : type(type), info(guns[type]), owner(owner), reloading(0), + ammo(owner->ammo[type]), mag(owner->mag[type]), gunwait(owner->gunwait[type]) { - if(d->gunselect==GUN_KNIFE || d->gunselect==GUN_GRENADE) return; //nothing special for a knife - guninfo &g = guns[d->gunselect]; +} +const int weapon::weaponchangetime = 400; +const float weapon::weaponbeloweye = 0.2f; + +void weapon::sendshoot(vec &from, vec &to) +{ + if(owner!=player1) return; + addmsg(SV_SHOOT, "ri2i6iv", lastmillis, owner->weaponsel->type, + (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), + (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), + hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); +} + +bool weapon::modelattacking() +{ + // FIXME!!! + int animtime = info.attackdelay; //min(owner->gunwait[owner->weaponsel->type], owner->weaponsel->info.attackdelay); + if(lastmillis - owner->lastaction < animtime) return true; + else return false; +} + +void weapon::attacksound() +{ + if(info.sound != S_NULL) playsound(info.sound, owner==player1 ? NULL : owner); +} + +bool weapon::reload() +{ + if(mag>=info.magsize || ammo<=0) return false; + updatelastaction(owner); + reloading = lastmillis; + gunwait += info.reloadtime; + + int numbullets = min(info.magsize - mag, ammo); + mag += numbullets; + ammo -= numbullets; + + if(owner->type==ENT_BOT) playsound(info.reload, owner); + else playsoundc(info.reload); + if(owner==player1) addmsg(SV_RELOAD, "ri2", lastmillis, owner->weaponsel->type); + return true; +} + +void weapon::renderstats() +{ + char gunstats[64]; + sprintf(gunstats, "%i/%i", mag, ammo); + draw_text(gunstats, 690, 827); +} + +void weapon::attackphysics(vec &from, vec &to) // physical fx to the owner +{ + const guninfo &g = info; vec unitv; float dist = to.dist(from, unitv); float f = dist/1000; - int spd = g.spread; - float rcl = g.recoil*-0.01f; + int spread = dynspread(); + float recoil = dynrecoil()*-0.01f; - if(d->gunselect==GUN_ASSAULT) + // spread + if(spread>1) { - if(d->shots > 3) spd = 70; - rcl += (rnd(8)*-0.01f); - } - - if((d->gunselect==GUN_SNIPER) && scoped) - { - spd = 1; - rcl = rcl / 3; - } - - if(d->gunselect!=GUN_SHOTGUN) // no spread on shotgun - { - #define RNDD (rnd(spd)-spd/2)*f + #define RNDD (rnd(spread)-spread/2)*f vec r(RNDD, RNDD, RNDD); to.add(r); #undef RNDD } - - // kickback - d->vel.add(vec(unitv).mul(rcl/dist).mul(d->crouching ? 0.75 : 1.0f)); - // recoil - d->pitchvel = min(pow(d->shots/(float)(g.recoilincrease), 2.0f)+(float)(g.recoilbase)/10.0f, (float)(g.maxrecoil)/10.0f); + // kickback & recoil + owner->vel.add(vec(unitv).mul(recoil/dist).mul(owner->crouching ? 0.75 : 1.0f)); + owner->pitchvel = min(pow(shots/(float)(g.recoilincrease), 2.0f)+(float)(g.recoilbase)/10.0f, (float)(g.maxrecoil)/10.0f); } -bool hasammo(playerent *d) // bot mod -{ - if(!d->mag[d->gunselect]) - { - if(d->type==ENT_BOT) playsound(S_NOAMMO, d); - else playsoundc(S_NOAMMO); - updatelastaction(d); - d->gunwait[d->gunselect] += 250; - d->lastattackgun = -1; - return false; - } else return true; +void weapon::renderhudmodel(int lastaction, int index) +{ + vec unitv; + float dist = worldpos.dist(owner->o, unitv); + unitv.div(dist); + + weaponmove wm; + if(!intermission) wm.calcmove(unitv, lastaction); + s_sprintfd(path)("weapons/%s", info.modelname); + static int lastanim[2], lastswitch[2]; + if(lastanim[index]!=(wm.anim|(type<<16))) + { + lastanim[index] = wm.anim|(type<<16); + lastswitch[index] = lastmillis; + } + rendermodel(path, wm.anim|(index ? ANIM_MIRROR : 0), 0, 0, wm.pos, player1->yaw+90, player1->pitch+wm.k_rot, 40.0f, lastswitch[index], NULL, NULL, 1.28f); } -VARP(autoreload, 0, 1, 1); - -bool akimboside = false; - -void shoot(playerent *d, vec &targ) +void weapon::updatetimers() { - if(d->state != CS_ALIVE) return; + if(gunwait) gunwait = max(gunwait - (lastmillis-owner->lastaction), 0); +} - int attacktime = lastmillis-d->lastaction; +void weapon::onselecting() +{ + owner->lastaction = lastmillis; + playsound(S_GUNCHANGE); +} - vec from = d->o; - vec to = targ; +void weapon::renderhudmodel() { renderhudmodel(owner->lastaction); } +int weapon::dynspread() { return info.spread; } +int weapon::dynrecoil() { return info.recoil; } +bool weapon::selectable() { return !reloading && this != owner->weaponsel && owner->state == CS_ALIVE && !owner->weaponchanging; } - if(d->gunselect==GUN_GRENADE) - { - d->shots = 0; - if(d->thrownademillis && attacktime >= NADE_THROW_TIME) + +struct grenadeent : bounceent +{ + grenadeent (playerent *owner, int millis = 0) + { + ASSERT(owner); + bounceent::owner = owner; + bounceent::millis = lastmillis; + timetolife = 2000-millis; + bouncestate = NADE_ACTIVATED; + maxspeed = 27.0f; + rotspeed = 6.0f; + } + + void explode() + { + if(bouncestate != NADE_THROWED) owner->weapons[GUN_GRENADE]->attack(vec(0,0,0)); + playsound(S_FEXPLODE, NULL, NULL, &o); + newprojectile(o, o, 1, owner==player1, owner, GUN_GRENADE, millis); + } + + virtual void destroy() + { + if(bouncestate==NADE_ACTIVATED || bouncestate==NADE_THROWED) explode(); + } +}; + +struct grenades : weapon +{ + const int throwwait; + int throwmillis; + + grenades(playerent *owner) : weapon(owner, GUN_GRENADE), throwwait((13*1000)/40), throwmillis(0) {} + + bool attack(vec &targ) + { + int attackmillis = lastmillis-owner->lastaction; + vec &from = owner->o; + vec &to = targ; + + if(throwmillis && attackmillis >= throwwait) { - if(!d->mag[GUN_GRENADE]) + throwmillis = 0; + if(!mag) { - d->weaponchanging = lastmillis-1-WEAPONCHANGE_TIME/2; - d->nextweapon = d->gunselect = d->primary; + owner->weaponchanging = lastmillis-1-(weaponchangetime/2); + owner->nextweaponsel = owner->weaponsel = owner->primweap; } - d->thrownademillis = 0; - return; + return false; } - if(attacktimegunwait[d->gunselect]) return; - d->gunwait[d->gunselect] = 0; - d->reloading = 0; + if(attackmillisattacking && !d->inhandnade) // activate + gunwait = reloading = 0; + + if(owner->attacking && !owner->inhandnade) // activate { - if(!hasammo(d)) return; - d->mag[d->gunselect]--; - newnade(d); - updatelastaction(d); - d->gunwait[d->gunselect] = attackdelay(d->gunselect); - d->lastattackgun = d->gunselect; - - addmsg(SV_SHOOT, "ri2i6i", lastmillis, d->gunselect, + if(!mag) return false; + throwmillis = 0; + owner->inhandnade = bounceents.add(new grenadeent(owner)); + updatelastaction(owner); + mag--; + gunwait = info.attackdelay; + owner->lastattackweapon = this; + addmsg(SV_SHOOT, "ri2i6i", lastmillis, owner->weaponsel->type, (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), 0); + playsound(S_GRENADEPULL); } - else if(!d->attacking && d->inhandnade && attacktime>attackdelay(d->gunselect)) thrownade(d, d->inhandnade); - return; - } - else - { - if(autoreload && d == player1 && !d->mag[d->gunselect] && lastmillis-d->lastaction>guns[d->gunselect].attackdelay) { reload(d); return; } - if(d->weaponchanging || attacktimegunwait[d->gunselect]) return; - d->gunwait[d->gunselect] = 0; - d->reloading = 0; - - if(!d->attacking) { d->shots = 0; return; } - updatelastaction(d); - d->lastattackgun = d->gunselect; - - if(d->gunselect!=GUN_KNIFE && !hasammo(d)) { d->shots = 0; return; } - - if(guns[d->gunselect].isauto) d->shots++; - else d->attacking = false; - - if(d->gunselect==GUN_PISTOL && d->akimbo) - { - d->attacking = true; // make akimbo auto - d->akimbolastaction[akimboside?1:0] = lastmillis; - akimboside = !akimboside; - } - - if(d->gunselect!=GUN_KNIFE) d->mag[d->gunselect]--; - from.z -= 0.2f; // below eye - } - - spreadandrecoil(from,to,d); - vec unitv; - float dist = to.dist(from, unitv); - unitv.div(dist); - - if(d->gunselect==GUN_KNIFE) - { - unitv.mul(3); // punch range - to = from; - to.add(unitv); - } - if(d->gunselect==GUN_SHOTGUN) createrays(from, to); - - hits.setsizenodelete(0); - - if(!guns[d->gunselect].projspeed) raydamage(from, to, d); - - d->gunwait[d->gunselect] = attackdelay(d->gunselect); - if(has_akimbo(d)) d->gunwait[d->gunselect] /= 2; // make akimbo pistols shoot twice as fast as normal pistol - - shootv(d->gunselect, from, to, d, true, 0); - if(d==player1) - { - addmsg(SV_SHOOT, "ri2i6iv", lastmillis, d->gunselect, - (int)(from.x*DMF), (int)(from.y*DMF), (int)(from.z*DMF), - (int)(to.x*DMF), (int)(to.y*DMF), (int)(to.z*DMF), - hits.length(), hits.length()*sizeof(hitmsg)/sizeof(int), hits.getbuf()); + else if(!owner->attacking && owner->inhandnade && attackmillis>info.attackdelay) thrownade(); + return true; } + + void attackfx(vec &from, vec &to, int millis) // other player's grenades + { + throwmillis = millis; + if(millis == 0) playsound(S_GRENADEPULL, owner); // activate + else if(millis > 0) // throw + { + owner->inhandnade = bounceents.add(new grenadeent(owner, millis)); + thrownade(from, to, owner->inhandnade); + } + } + + void selecting() { throwmillis = 0; } + void onammopicked() { throwmillis = 0; } + + int modelanim() + { + if(throwing()) return ANIM_GUN_THROW; + else + { + int animtime = min(gunwait, info.attackdelay); + if(inhand() || lastmillis - owner->lastaction < animtime) return ANIM_GUN_SHOOT; + } + return ANIM_GUN_IDLE; + } + + bool throwing() { return throwmillis && !owner->inhandnade; } + bool inhand() { return throwmillis <= 0 && owner->inhandnade; } + + void thrownade() + { + const float speed = cosf(RAD*owner->pitch); + vec vel(sinf(RAD*owner->yaw)*speed, -cosf(RAD*owner->yaw)*speed, sinf(RAD*owner->pitch)); + vel.mul(1.5f); + vec from(vel); + from.mul(1.1f*owner->radius); + from.add(owner->o); + thrownade(from, vel, owner->inhandnade); + } + + void thrownade(const vec &from, const vec &vel, bounceent *p) + { + if(!p) return; + p->vel = vel; + p->o = from; + p->bouncestate = NADE_THROWED; + loopi(10) moveplayer(p, 10, true, 10); + + p->bouncestate = NADE_THROWED; + owner->inhandnade = NULL; + + throwmillis = lastmillis; + + if(owner==player1) + { + playsound(S_GRENADETHROW); + updatelastaction(player1); + addmsg(SV_THROWNADE, "ri7", int(p->o.x*DMF), int(p->o.y*DMF), int(p->o.z*DMF), int(p->vel.x*DMF), int(p->vel.y*DMF), int(p->vel.z*DMF), lastmillis-p->millis); + } + else playsound(S_GRENADETHROW, owner); + } + + void drawstats() + { + char gunstats[64]; + sprintf(gunstats, "%i", mag); + draw_text(gunstats, 690, 827); + } + + bool selectable() { return weapon::selectable() && !inhand() && mag; } +}; + +struct gun : weapon +{ + gun(playerent *owner, int type) : weapon(owner, type) {} + + virtual bool attack(vec &targ) + { + int attackmillis = lastmillis-owner->lastaction; + if(attackmillisattacking) { shots = 0; return false; } + updatelastaction(owner); + if(!mag) + { + playsoundc(S_NOAMMO); + ASSERT(owner->type!=ENT_BOT); + gunwait += 250; + owner->lastattackweapon = NULL; + shots = 0; + checkautoreload(); + return false; + } + + owner->lastattackweapon = this; + shots++; + + if(!info.isauto) owner->attacking = false; + + vec from = owner->o; + vec to = targ; + from.z -= weaponbeloweye; + + attackphysics(from, to); + + hits.setsizenodelete(0); + raydamage(from, to, owner); + attackfx(from, to, 0); + + gunwait = info.attackdelay; + mag--; + + sendshoot(from, to); + return true; + } + + virtual void attackfx(vec &from, vec &to, int millis) + { + addbullethole(from, to); + addshotline(owner, from, to); + particle_splash(0, 5, 250, to); + attacksound(); + } + + int modelanim() { return modelattacking() ? ANIM_GUN_SHOOT|ANIM_LOOP : ANIM_GUN_IDLE; }; + + void checkautoreload() + { + if(autoreload && owner==player1 && !mag) reload(); + } +}; + +struct shotgun : gun +{ + shotgun(playerent *owner) : gun(owner, GUN_SHOTGUN) {} + + bool attack(vec &targ) + { + vec from = owner->o; + from.z -= weaponbeloweye; + createrays(from, targ); + return gun::attack(targ); + } + + void attackfx(vec &from, vec &to, int millis) + { + loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]); + if(addbullethole(from, to)) + { + int holes = 3+rnd(5); + loopi(holes) addbullethole(from, sg[i], 0); + } + attacksound(); + } + + bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } +}; + +struct subgun : gun +{ + subgun(playerent *owner) : gun(owner, GUN_SUBGUN) {} + bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } +}; + +struct sniperrifle : gun +{ + sniperrifle(playerent *owner) : gun(owner, GUN_SNIPER) {} + + void attackfx(vec &from, vec &to, int millis) + { + addbullethole(from, to); + addshotline(owner, from, to); + particle_splash(0, 50, 200, to); + particle_trail(1, 500, from, to); + attacksound(); + } + + bool reload() + { + bool r = weapon::reload(); + if(owner==player1 && r) setscope(false); + return r; + } + + int dynspread() { return scoped ? 1 : info.spread; } + int dynrecoil() { return scoped ? info.recoil / 3 : info.recoil; } + bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } + void onselecting() { weapon::onselecting(); setscope(false); } + void ondeselecting() { setscope(false); } +}; + +struct assaultrifle : gun +{ + assaultrifle(playerent *owner) : gun(owner, GUN_ASSAULT) {} + + int dynspread() { return shots > 3 ? 70 : info.spread; } + int dynrecoil() { return info.recoil + (rnd(8)*-0.01f); } + bool selectable() { return weapon::selectable() && !m_noprimary && this == owner->primweap; } +}; + +struct pistol : gun +{ + pistol(playerent *owner) : gun(owner, GUN_PISTOL) {} + bool selectable() { return weapon::selectable() && !m_nopistol; } +}; + +struct akimbo : gun +{ + akimbo(playerent *owner) : gun(owner, GUN_AKIMBO), akimbomillis(0) + { + akimbolastaction[0] = akimbolastaction[1] = 0; + } + + bool akimboside; + int akimbomillis; + int akimbolastaction[2]; + + bool attack(vec &targ) + { + if(gun::attack(targ)) + { + akimbolastaction[akimboside?1:0] = lastmillis; + akimboside = !akimboside; + return true; + } + return false; + } + + void onammopicked() + { + akimbomillis = lastmillis + 30000; + if(owner==player1) + { + if(owner->weaponsel->type!=GUN_SNIPER && !owner->inhandnade) weaponswitch(this); + addmsg(SV_AKIMBO, "ri", lastmillis); + } + } + + void onselecting() + { + gun::onselecting(); + akimbolastaction[0] = akimbolastaction[1] = lastmillis; + } + + bool selectable() { return weapon::selectable() && !m_nopistol && owner->akimbo; } + void updatetimers() { weapon::updatetimers(); /*loopi(2) akimbolastaction[i] = lastmillis;*/ } + void reset() { akimbolastaction[0] = akimbolastaction[1] = akimbomillis = 0; akimboside = false; } + + void renderhudmodel() + { + weapon::renderhudmodel(akimbolastaction[0], 0); + weapon::renderhudmodel(akimbolastaction[1], 1); + } + + bool timerout() { return akimbomillis && akimbomillis <= lastmillis; } +}; + +struct knife : weapon +{ + knife(playerent *owner) : weapon(owner, GUN_KNIFE) {} + + bool attack(vec &targ) + { + int attackmillis = lastmillis-owner->lastaction; + if(attackmillisattacking) return false; + updatelastaction(owner); + + owner->lastattackweapon = this; + owner->attacking = false; + + vec from = owner->o; + vec to = targ; + from.z -= weaponbeloweye; + + vec unitv; + float dist = to.dist(from, unitv); + unitv.div(dist); + unitv.mul(3); // punch range + to = from; + to.add(unitv); + + hits.setsizenodelete(0); + raydamage(from, to, owner); + attackfx(from, to, 0); + sendshoot(from, to); + gunwait = info.attackdelay; + return true; + }; + + int modelanim() { return modelattacking() ? ANIM_GUN_SHOOT : ANIM_GUN_IDLE; }; + + void drawstats() {} + void attackfx(vec &from, vec &to, int millis) { attacksound(); } +}; + + +void shoot(playerent *p, vec &targ) +{ + if(p->state==CS_DEAD || p->weaponchanging) return; + weapon *weap = p->weaponsel; + if(weap) weap->attack(targ); } +void weapon::equipplayer(playerent *pl) +{ + if(!pl) return; + pl->weapons[GUN_ASSAULT] = new assaultrifle(pl); + pl->weapons[GUN_GRENADE] = new grenades(pl); + pl->weapons[GUN_KNIFE] = new knife(pl); + pl->weapons[GUN_PISTOL] = new pistol(pl); + pl->weapons[GUN_SHOTGUN] = new shotgun(pl); + pl->weapons[GUN_SNIPER] = new sniperrifle(pl); + pl->weapons[GUN_SUBGUN] = new subgun(pl); + pl->weapons[GUN_AKIMBO] = new akimbo(pl); + pl->selectweapon(GUN_ASSAULT); + pl->setprimary(GUN_ASSAULT); + pl->setnextprimary(GUN_ASSAULT); +} + +void checkakimbo() +{ + if(player1->akimbo) + { + akimbo &a = *((akimbo *)player1->weapons[GUN_AKIMBO]); + if(a.timerout()) + { + weapon &p = *player1->weapons[GUN_PISTOL]; + player1->akimbo = false; + a.reset(); + // transfer ammo to pistol + p.mag = min(p.info.magsize, max(a.mag, p.mag)); + p.ammo = max(p.ammo, p.ammo); + if(player1->weaponsel->type==GUN_AKIMBO) weaponswitch(&p); + playsoundc(S_AKIMBOOUT); + } + } +} \ No newline at end of file diff --git a/source/src/weapon.h b/source/src/weapon.h new file mode 100644 index 00000000..116aa956 --- /dev/null +++ b/source/src/weapon.h @@ -0,0 +1,38 @@ +struct playerent; + +struct weapon +{ + const static int weaponchangetime; + const static float weaponbeloweye; + static void equipplayer(playerent *pl); + + weapon(struct playerent *owner, int type); + + int type; + playerent *owner; + const struct guninfo &info; + int &ammo, &mag, &gunwait, shots; + virtual int dynspread(), dynrecoil(); + int reloading, lastaction; + + virtual bool attack(vec &targ) = 0; + virtual void attackfx(vec &from, vec &to, int millis) = 0; + virtual void attackphysics(vec &from, vec &to); + virtual void attacksound(); + virtual bool reload(); + virtual void reset() {}; + + virtual int modelanim() = 0; + virtual void updatetimers(); + virtual bool selectable(); + virtual void renderstats(); + virtual void renderhudmodel(); + + virtual void onselecting(); + virtual void ondeselecting() {}; + virtual void onammopicked() {}; + + void sendshoot(vec &from, vec &to); + bool modelattacking(); + void renderhudmodel(int lastaction, int index = 0); +}; \ No newline at end of file diff --git a/source/src/world.cpp b/source/src/world.cpp index d4d6986f..ca314801 100644 --- a/source/src/world.cpp +++ b/source/src/world.cpp @@ -1,5 +1,6 @@ // world.cpp: core map management stuff +#include "pch.h" #include "cube.h" #include "bot/bot.h" diff --git a/source/src/worldio.cpp b/source/src/worldio.cpp index cccbafff..3175c646 100644 --- a/source/src/worldio.cpp +++ b/source/src/worldio.cpp @@ -1,5 +1,6 @@ // worldio.cpp: loading & saving of maps and savegames +#include "pch.h" #include "cube.h" void backup(char *name, char *backupname) diff --git a/source/src/worldlight.cpp b/source/src/worldlight.cpp index a3df6dd9..9318369f 100644 --- a/source/src/worldlight.cpp +++ b/source/src/worldlight.cpp @@ -1,5 +1,6 @@ // worldlight.cpp +#include "pch.h" #include "cube.h" VAR(lightscale,1,4,100); diff --git a/source/src/worldocull.cpp b/source/src/worldocull.cpp index 80f0632f..27e35fb9 100644 --- a/source/src/worldocull.cpp +++ b/source/src/worldocull.cpp @@ -1,5 +1,6 @@ // worldocull.cpp: occlusion map and occlusion test +#include "pch.h" #include "cube.h" #define NUMRAYS 512 diff --git a/source/src/worldrender.cpp b/source/src/worldrender.cpp index a08130d3..abef70b2 100644 --- a/source/src/worldrender.cpp +++ b/source/src/worldrender.cpp @@ -1,6 +1,7 @@ // worldrender.cpp: goes through all cubes in top down quad tree fashion, determines what has to // be rendered and how (depending on neighbouring cubes), then calls functions in rendercubes.cpp +#include "pch.h" #include "cube.h" void render_wall(sqr *o, sqr *s, int x1, int y1, int x2, int y2, int mip, sqr *d1, sqr *d2, bool topleft)