From 0b63d7d07ed18dce645f305611f036d3e6e578e9 Mon Sep 17 00:00:00 2001 From: flowtron Date: Mon, 17 Jan 2011 18:27:53 +0000 Subject: [PATCH] new shotgun behaviour git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@6012 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/clientgame.cpp | 8 +- source/src/cube.h | 2 +- source/src/entity.h | 10 ++- source/src/main.cpp | 9 +-- source/src/server.h | 21 +----- source/src/serverevents.h | 2 +- source/src/weapon.cpp | 154 +++++++++++++++++++++++++++++--------- 7 files changed, 140 insertions(+), 66 deletions(-) diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 9afee044..ddce4613 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -590,7 +590,7 @@ void respawnself() spawnplayer(player1); player1->lifesequence++; player1->weaponswitch(player1->primweap); - player1->weaponchanging -= weapon::weaponchangetime/2; + player1->weaponchanging -= player1->weapons[player1->gunselect]->weaponchangetime/2; // 2011jan16:ft: for a little no-shoot after spawn } } @@ -608,14 +608,14 @@ inline const char * spawn_message() if (spawnpermission == SP_WRONGMAP) { // Don't use "/n" within these messages. If you do, the words won't align to the middle of the screen. - if (securemapcheck(getclientmap())) + if (securemapcheck(getclientmap())) return "3Server will NOT allow spawning or getmap!"; // Also see client.cpp which has a conoutf message else return "3You must be on the correct map to spawn. Type /getmap to download it."; } else if (m_coop) return "3Type /getmap or send a map and vote for it to start co-op edit."; else return "4Awaiting permission to spawn. \f2DON\'T PANIC!"; - // Despite its many glaring (and occasionally fatal) inaccuracies, AssaultCube itself has outsold the - // Encyclopedia Galactica because it is slightly cheaper, and because it has the words "Don't Panic" + // Despite its many glaring (and occasionally fatal) inaccuracies, AssaultCube itself has outsold the + // Encyclopedia Galactica because it is slightly cheaper, and because it has the words "Don't Panic" // in large, friendly letters. } diff --git a/source/src/cube.h b/source/src/cube.h index be828131..c0e64e2b 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -52,7 +52,7 @@ extern int verbose; #include "protos.h" // external function decls -#define AC_VERSION 1110 +#define AC_VERSION 1111 #define AC_MASTER_URI "assault.cubers.net" #define AC_MASTER_PORT 28760 #define MAXCL 20 diff --git a/source/src/entity.h b/source/src/entity.h index 4a81553c..b3a28547 100644 --- a/source/src/entity.h +++ b/source/src/entity.h @@ -49,6 +49,13 @@ enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_RIFLE, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER #define reloadable_gun(g) (g != GUN_KNIFE && g != GUN_GRENADE) #define SGRAYS 21 +// WIP shotty +#define SGMAXDMGABS 105 +#define SGMAXDMGLOC 84 +#define SGBONUSDIST 60 +#define SGSEGDMG_O 3 +#define SGSEGDMG_M 4 +#define SGSEGDMG_C 5 #define SGSPREAD 2.25 #define EXPDAMRAD 10 @@ -472,7 +479,8 @@ public: lastaction = 0; lastattackweapon = NULL; attacking = false; - weaponchanging = 0; + extern int lastmillis; + weaponchanging = lastmillis - weapons[gunselect]->weaponchangetime/2; // 2011jan16:ft: for a little no-shoot after spawn resetspec(); eardamagemillis = 0; eyeheight = maxeyeheight; diff --git a/source/src/main.cpp b/source/src/main.cpp index 7985d783..73437ae3 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -595,13 +595,8 @@ bool needsautoscreenshot = false; void makeautoscreenshot() { - extern void *scoremenu, *teammenu, *ctfmenu, *curmenu; - bool scoresee = (curmenu == scoremenu || curmenu == teammenu || curmenu == ctfmenu); - if(scoresee) - { - needsautoscreenshot = false; - screenshot(NULL); - } + needsautoscreenshot = false; + screenshot(NULL); } COMMAND(screenshot, ARG_1STR); diff --git a/source/src/server.h b/source/src/server.h index 46fe879e..653a9b32 100644 --- a/source/src/server.h +++ b/source/src/server.h @@ -480,26 +480,13 @@ guninfo guns[NUMGUNS] = { "knife", S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, false }, { "pistol", S_PISTOL, S_RPISTOL, 1400, 160, 18, 0, 0, 53, 10, 10, 6, 5, 6, 35, 58, 125, 1, false }, // CHANGED : magsize { "rifle", S_RIFLE, S_RRIFLE, 1800, 720, 60, 0, 0, 10, 60, 10, 4, 4, 10, 60, 60, 150, 1, false }, - { "shotgun", S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, 10, 140, 140, 125, 1, false }, // CHANGED + { "shotgun", S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 1, 0, 0, 1, 35, 7, 9, 9, 10, 140, 140, 125, 1, false }, // CHANGED : CAUTION dmg only sane for server! { "subgun", S_SUBGUN, S_RSUBGUN, 1650, 80, 15, 0, 0, 45, 15, 30, 1, 2, 4, 30, 50, 188, 1, true }, // CHANGED : [reI,reB,reM] + spread - { "sniper", S_SNIPER, S_RSNIPER, 1950, 1500, 85, 0, 0, 47, 50, 5, 4, 4, 10, 85, 85, 100, 1, false }, // CHANGED : damage, spread - { "assault", S_ASSAULT, S_RASSAULT, 2000, 120, 24, 0, 0, 20, 40, 20, 0, 2, 2, 22, 55, 115, 1, true }, // CHANGED + { "sniper", S_SNIPER, S_RSNIPER, 1950, 1500, 84, 0, 0, 47, 50, 5, 4, 4, 10, 85, 85, 100, 1, false }, // CHANGED : damage, spread // 2011jan17:ft: 85=>84 + { "assault", S_ASSAULT, S_RASSAULT, 2000, 120, 22, 0, 0, 20, 40, 20, 0, 2, 2, 22, 55, 115, 1, true }, // CHANGED // 2011jan17:ft: 24=>22 { "cpistol", S_PISTOL, S_RPISTOL, 1400, 120, 19, 0, 0, 35, 10, 15, 6, 5, 6, 35, 58, 125, 1, false }, // temporary { "grenade", S_NULL, S_NULL, 1000, 650, 200, 20, 6, 1, 1, 1, 3, 1, 0, 0, 0, 0, 3, false }, - { "pistol", S_PISTOL, S_RAKIMBO, 1400, 80, 19, 0, 0, 50, 10, 10, 6, 5, 10, 10, 18, 115, 1, true }, // CHANGED -/* -1.1.0.4: - { "knife", S_KNIFE, S_NULL, 0, 500, 50, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, false }, - { "pistol", S_PISTOL, S_RPISTOL, 1400, 160, 18, 0, 0, 55, 10, 8, 6, 5, 6, 35, 58, 125, 1, false }, - { "rifle", S_RIFLE, S_RRIFLE, 1800, 720, 60, 0, 0, 10, 60, 10, 4, 4, 10, 60, 60, 150, 1, false }, - { "shotgun", S_SHOTGUN, S_RSHOTGUN, 2400, 1000, 5, 0, 0, 1, 35, 7, 9, 9, 10, 115, 115, 150, 1, false }, - { "subgun", S_SUBGUN, S_RSUBGUN, 1650, 80, 15, 0, 0, 40, 15, 30, 1, 2, 4, 15, 40, 175, 1, true }, - { "sniper", S_SNIPER, S_RSNIPER, 1950, 1500, 80, 0, 0, 60, 50, 5, 4, 4, 10, 85, 85, 100, 1, false }, - { "assault", S_ASSAULT, S_RASSAULT, 2000, 120, 24, 0, 0, 20, 40, 20, 0, 2, 2, 18, 50, 125, 1, true }, - { "cpistol", S_PISTOL, S_RPISTOL, 1400, 120, 19, 0, 0, 35, 10, 15, 6, 5, 6, 35, 58, 125, 1, false }, // temporary - { "grenade", S_NULL, S_NULL, 1000, 650, 200, 20, 6, 1, 1, 1, 3, 1, 0, 0, 0, 0, 3, false }, - { "pistol", S_PISTOL, S_RAKIMBO, 1400, 80, 19, 0, 0, 45, 10, 16, 6, 5, 8, 10, 18, 150, 1, true }, -*/ + { "pistol", S_PISTOL, S_RAKIMBO, 1400, 80, 19, 0, 0, 50, 10, 20, 6, 5, 10, 10, 18, 115, 1, true }, // CHANGED }; const char *teamnames[TEAM_NUM+1] = {"CLA", "RVSF", "CLA-SPECT", "RVSF-SPECT", "SPECTATOR", "void"}; diff --git a/source/src/serverevents.h b/source/src/serverevents.h index ba1cbd8c..faa48ac3 100644 --- a/source/src/serverevents.h +++ b/source/src/serverevents.h @@ -57,7 +57,7 @@ void processevent(client *c, shotevent &e) case GUN_GRENADE: gs.grenades.add(e.id); break; default: { - int totalrays = 0, maxrays = e.gun==GUN_SHOTGUN ? SGRAYS : 1; + int totalrays = 0, maxrays = e.gun==GUN_SHOTGUN ? SGMAXDMGABS: 1; for(int i = 1; ievents.length() && c->events[i].type==GE_HIT; i++) { hitevent &h = c->events[i].hit; diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index da080aa0..8cbb368c 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -6,7 +6,11 @@ VARP(autoreload, 0, 1, 1); VARP(akimboendaction, 0, 0, 2); // 0: stay with pistol, 1: back to primary, 2: grenade - all fallback to previous one w/o ammo for target -vec sg[SGRAYS]; +struct sgray { + int ds; // damage flag: outer, medium, center: SGSEGDMG_* + vec rv; // ray vector +}; +sgray sgr[SGRAYS*3]; void updatelastaction(playerent *d) { @@ -143,18 +147,41 @@ void tryreload(playerent *p) void selfreload() { tryreload(player1); } COMMANDN(reload, selfreload, ARG_NONE); -void createrays(vec &from, vec &to) // create random spread of rays for the shotgun +void createrays(vec &from, vec &to) // create random spread of rays for the shotgun { - float f = to.dist(from)*SGSPREAD/1000; - if(1==0)conoutf("shotgun distance: %.2f", f); // DEBUG 2010nov19 - loopi(SGRAYS) - { - #define RNDD (rndscale(100)-50)*f - vec r(RNDD, RNDD, RNDD); - sg[i] = to; - sg[i].add(r); - #undef RNDD - } + // 2011jan17:ft: once this basic approach has been agreed upon this function should be optimized + vec dir = vec(from).sub(to); + float f = dir.magnitude() / 10.0f; + dir.normalize(); + vec spoke; + spoke.orthogonal(dir); + spoke.normalize(); + spoke.mul(f); + int circseg = -1; + loopk(3) + loopi(SGRAYS) + { + circseg = k; + int j = k * SGRAYS; + sgr[j+i].ds = k==0 ? SGSEGDMG_O : (k==1? SGSEGDMG_M: SGSEGDMG_C); + vec p(spoke); + float base = 3.14f; + int wrange = 50; + switch(sgr[j+i].ds) + { + case SGSEGDMG_O: base = 1.35f; wrange = 40; break; + case SGSEGDMG_M: base = 0.50f; wrange = 85; break; + case SGSEGDMG_C: + default: base = 0.00f; wrange = 50; break; + } + int rndmul = rnd(wrange); + p.mul( base + rndmul/100.0f ); + int rnddir = rnd(15); + p.rotate( 2*M_PI/SGRAYS * i + rnddir , dir ); + vec rray = vec(to); + rray.add(p); + sgr[j+i].rv = rray; + } } static inline bool intersectbox(const vec &o, const vec &rad, const vec &from, const vec &to, vec *end) // if lineseg hits entity bounding box @@ -536,25 +563,76 @@ void raydamage(vec &from, vec &to, playerent *d) bool hitted=false; if(d->weaponsel->type==GUN_SHOTGUN) { - playerent *hits[SGRAYS]; - loopi(SGRAYS) + + + uint done = 0; + playerent *cl = NULL; + vec dir(from); + dir.sub(to).normalize(); + vec spoke; + spoke.orthogonal(dir); + spoke.normalize().mul(0.2f); + sgray tbp[SGRAYS*3]; + loopk(3) + loop(r, SGRAYS) + { + int j = k * SGRAYS; + vec p(spoke); + int rndmul = rnd(5); + p.mul( 0.25 + rndmul/10.0f ); + int rndjit = rnd(360); + p.rotate( 2*M_PI/360 * rndjit, dir ); + tbp[j+r].rv = from; + if(sgr[j+r].ds != SGSEGDMG_C) tbp[j+r].rv.add(p); + } + for(;;) { - if((hits[i] = intersectclosest(from, sg[i], d, dist, hitzone))) - shorten(from, sg[i], dist); - } - loopi(SGRAYS) if(hits[i]) - { - o = hits[i]; - hits[i] = NULL; - int numhits = 1; - for(int j = i+1; j < SGRAYS; j++) if(hits[j] == o) + bool raysleft = false; + int hitrays_o = 0; + int hitrays_m = 0; + int hitrays_c = 0; + o = NULL; + loopk(3) { - hits[j] = NULL; - numhits++; + done = 0; + loop(r, SGRAYS) + { + int j = k * SGRAYS; + if((done&(1<weaponsel->type, numhits == SGRAYS, numhits); - if(d==player1) hitted = true; + int hitrays = hitrays_o + hitrays_m + hitrays_c; + int dmgtotal = SGSEGDMG_O * hitrays_o + SGSEGDMG_M * hitrays_m + SGSEGDMG_C * hitrays_c; + int dmgrealt = dmgtotal / 3; // needs to possibly factorize the ray-segments seperately - but always: dmgrealt <= SGMAXDMG(ABS) !! + float d2o = SGBONUSDIST; + if(o) d2o = vec(from).sub(o->o).magnitude(); + if(d2o <= (SGBONUSDIST/10.0f) && hitrays) + { + dmgrealt += (SGMAXDMGABS-SGMAXDMGLOC); + dmgrealt = min(dmgrealt, SGMAXDMGABS); // maximum damage of the shotgun + } + if(hitrays) hitpush( dmgrealt, o, d, from, to, d->weaponsel->type, hitrays == SGMAXDMGABS, dmgrealt); + if(d==player1 && hitrays) hitted=true; + if(!raysleft) break; } + + } else if((o = intersectclosest(from, to, d, dist, hitzone))) { @@ -566,7 +644,7 @@ void raydamage(vec &from, vec &to, playerent *d) case GUN_SUBGUN: if(flag4subgunDMGalt) dam +=1; break; default: break; } - bool info = gib || (GUN_SUBGUN && flag4subgunDMGalt); + bool info = gib || (d->weaponsel->type==GUN_SUBGUN && flag4subgunDMGalt); hitpush(dam, o, d, from, to, d->weaponsel->type, gib, info ? 1 : 0); if(d==player1) hitted=true; shorten(from, to, dist); @@ -1066,8 +1144,11 @@ bool gun::attack(vec &targ) if(!owner->attacking) { shots = 0; - if(lastmillis-timer4subgunDMGalt>=750) flag4subgunDMGalt = true; // 1st shot 16, 2nd 15, .. reset on "end burst" (timed) - if(!timer4subgunDMGalt) timer4subgunDMGalt = lastmillis; + if(type==GUN_SUBGUN) + { + if(lastmillis-timer4subgunDMGalt>=750) flag4subgunDMGalt = true; // 1st shot 16, 2nd 15, .. reset on "end burst" (timed) + if(!timer4subgunDMGalt) timer4subgunDMGalt = lastmillis; + } checkautoreload(); return false; } @@ -1085,7 +1166,7 @@ bool gun::attack(vec &targ) owner->lastattackweapon = this; shots++; - flag4subgunDMGalt = !flag4subgunDMGalt; + if(type==GUN_SUBGUN) flag4subgunDMGalt = !flag4subgunDMGalt; if(!info.isauto) owner->attacking = false; @@ -1131,17 +1212,20 @@ void shotgun::attackphysics(vec &from, vec &to) bool shotgun::attack(vec &targ) { - if(1==0)conoutf("shotgun:attack(%.2f, %.2f, %.2f)", targ.x, targ.y, targ.z); // 2010nov19 return gun::attack(targ); } void shotgun::attackfx(const vec &from, const vec &to, int millis) { - loopi(SGRAYS) particle_splash(0, 5, 200, sg[i]); + loopi(SGRAYS) particle_splash(0, 5, 200, sgr[i].rv); if(addbullethole(owner, from, to)) { - int holes = 3+rnd(5); - loopi(holes) addbullethole(owner, from, sg[i], 0, false); + loopk(3) + { + int holes = 1+rnd(3); + loopi(holes) addbullethole(owner, from, sgr[k*SGRAYS+i].rv, 0, false); + } + } adddynlight(owner, from, 4, 100, 50, 96, 80, 64); attacksound();