multi:: PvP, friendly-fire, and self-hits options
This commit is contained in:
parent
248c48613e
commit
a6cbedc944
|
@ -135,6 +135,8 @@ EX bool wrongMode(char flags) {
|
||||||
dls = lsChaos;
|
dls = lsChaos;
|
||||||
|
|
||||||
if(land_structure != dls) return true;
|
if(land_structure != dls) return true;
|
||||||
|
if(numplayers() > 1 && !multi::friendly_fire) return true;
|
||||||
|
if(numplayers() > 1 && multi::pvp_mode) return true;
|
||||||
if((numplayers() > 1) != (flags == rg::multi)) return true;
|
if((numplayers() > 1) != (flags == rg::multi)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -777,6 +779,9 @@ EX void achievement_final(bool really_final) {
|
||||||
if(ineligible_starting_land) return;
|
if(ineligible_starting_land) return;
|
||||||
if(geometry) return;
|
if(geometry) return;
|
||||||
if(NONSTDVAR) return;
|
if(NONSTDVAR) return;
|
||||||
|
|
||||||
|
if(numplayers() > 1 && !multi::friendly_fire) return;
|
||||||
|
if(numplayers() > 1 && multi::pvp) return;
|
||||||
|
|
||||||
// determine the correct leaderboard ID for 'total score'
|
// determine the correct leaderboard ID for 'total score'
|
||||||
// or return if no leaderboard for the current mode
|
// or return if no leaderboard for the current mode
|
||||||
|
|
|
@ -168,7 +168,7 @@ EX int lightat, safetyat;
|
||||||
EX void drawLightning() { lightat = ticks; }
|
EX void drawLightning() { lightat = ticks; }
|
||||||
EX void drawSafety() { safetyat = ticks; }
|
EX void drawSafety() { safetyat = ticks; }
|
||||||
|
|
||||||
void drawShield(const shiftmatrix& V, eItem it) {
|
EX void drawShield(const shiftmatrix& V, eItem it) {
|
||||||
#if CAP_CURVE
|
#if CAP_CURVE
|
||||||
float ds = ptick(300);
|
float ds = ptick(300);
|
||||||
color_t col = iinf[it].color;
|
color_t col = iinf[it].color;
|
||||||
|
|
39
multi.cpp
39
multi.cpp
|
@ -29,6 +29,9 @@ EX namespace multi {
|
||||||
EX charstyle scs[MAXPLAYER];
|
EX charstyle scs[MAXPLAYER];
|
||||||
|
|
||||||
EX bool split_screen;
|
EX bool split_screen;
|
||||||
|
EX bool pvp_mode;
|
||||||
|
EX bool friendly_fire = true;
|
||||||
|
EX bool self_hits;
|
||||||
|
|
||||||
EX int players = 1;
|
EX int players = 1;
|
||||||
EX cellwalker player[MAXPLAYER];
|
EX cellwalker player[MAXPLAYER];
|
||||||
|
@ -39,7 +42,7 @@ EX namespace multi {
|
||||||
EX bool flipped[MAXPLAYER];
|
EX bool flipped[MAXPLAYER];
|
||||||
|
|
||||||
// treasure collection, kill, and death statistics
|
// treasure collection, kill, and death statistics
|
||||||
EX int treasures[MAXPLAYER], kills[MAXPLAYER], deaths[MAXPLAYER];
|
EX int treasures[MAXPLAYER], kills[MAXPLAYER], deaths[MAXPLAYER], pkills[MAXPLAYER], suicides[MAXPLAYER];
|
||||||
|
|
||||||
EX bool alwaysuse = false;
|
EX bool alwaysuse = false;
|
||||||
|
|
||||||
|
@ -194,18 +197,21 @@ string listkeys(int id) {
|
||||||
#define SCJOY 16
|
#define SCJOY 16
|
||||||
|
|
||||||
string dsc(int id) {
|
string dsc(int id) {
|
||||||
char buf[64];
|
string buf = XLAT(" (%d $$$, %d kills, %d deaths)",
|
||||||
sprintf(buf, " (%d $$$, %d kills, %d deaths)",
|
its(multi::treasures[id]),
|
||||||
multi::treasures[id],
|
its(multi::kills[id]),
|
||||||
multi::kills[id],
|
its(multi::deaths[id])
|
||||||
multi::deaths[id]
|
|
||||||
);
|
);
|
||||||
|
if(friendly_fire)
|
||||||
|
buf += XLAT(" (%d pkills)", its(multi::pkills[id]));
|
||||||
|
if(self_hits)
|
||||||
|
buf += XLAT(" (%d self)", its(multi::suicides[id]));
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
EX void resetScores() {
|
EX void resetScores() {
|
||||||
for(int i=0; i<MAXPLAYER; i++)
|
for(int i=0; i<MAXPLAYER; i++)
|
||||||
multi::treasures[i] = multi::kills[i] = multi::deaths[i] = 0;
|
multi::treasures[i] = multi::kills[i] = multi::deaths[i] = multi::pkills[i] = multi::suicides[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool configdead;
|
bool configdead;
|
||||||
|
@ -522,6 +528,19 @@ EX void showConfigureMultiplayer() {
|
||||||
dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k');
|
dialog::addSelItem(XLAT("keyboard & joysticks"), "", 'k');
|
||||||
dialog::add_action(multi::configure);
|
dialog::add_action(multi::configure);
|
||||||
add_edit(split_screen);
|
add_edit(split_screen);
|
||||||
|
if(shmup::on && !racing::on) {
|
||||||
|
add_edit(pvp_mode);
|
||||||
|
add_edit(friendly_fire);
|
||||||
|
add_edit(self_hits);
|
||||||
|
if(pvp_mode)
|
||||||
|
dialog::addInfo(XLAT("PvP grants infinite lives -- achievements disabled"));
|
||||||
|
else if(friendly_fire)
|
||||||
|
dialog::addInfo(XLAT("friendly fire off -- achievements disabled"));
|
||||||
|
else
|
||||||
|
dialog::addBreak(100);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dialog::addInfo(XLAT("PvP available only in shmup"));
|
||||||
}
|
}
|
||||||
else dialog::addBreak(200);
|
else dialog::addBreak(200);
|
||||||
|
|
||||||
|
@ -695,6 +714,12 @@ EX void initConfig() {
|
||||||
addsaver(multi::players, "mode-number of players");
|
addsaver(multi::players, "mode-number of players");
|
||||||
param_b(multi::split_screen, "splitscreen", false)
|
param_b(multi::split_screen, "splitscreen", false)
|
||||||
->editable("split screen mode", 's');
|
->editable("split screen mode", 's');
|
||||||
|
param_b(multi::pvp_mode, "pvp_mode", false)
|
||||||
|
->editable("player vs player", 'v');
|
||||||
|
param_b(multi::friendly_fire, "friendly_fire", true)
|
||||||
|
->editable("friendly fire", 'f');
|
||||||
|
param_b(multi::self_hits, "self_hits", false)
|
||||||
|
->editable("self hits", 'h');
|
||||||
addsaver(alwaysuse, "use configured keys");
|
addsaver(alwaysuse, "use configured keys");
|
||||||
// unfortunately we cannot use key names here because SDL is not yet initialized
|
// unfortunately we cannot use key names here because SDL is not yet initialized
|
||||||
for(int i=0; i<512; i++)
|
for(int i=0; i<512; i++)
|
||||||
|
|
46
shmup.cpp
46
shmup.cpp
|
@ -50,8 +50,9 @@ struct monster {
|
||||||
int nextshot; ///< when will it be able to shot (players/flailers)
|
int nextshot; ///< when will it be able to shot (players/flailers)
|
||||||
int pid; ///< player ID
|
int pid; ///< player ID
|
||||||
int hitpoints; ///< hitpoints; or time elapsed in Asteroids
|
int hitpoints; ///< hitpoints; or time elapsed in Asteroids
|
||||||
int stunoff;
|
int stunoff; ///< when does the stun end
|
||||||
int blowoff;
|
int blowoff; ///< when does the blow end
|
||||||
|
int fragoff; ///< when does the frag end in PvP
|
||||||
double swordangle; ///< sword angle wrt at
|
double swordangle; ///< sword angle wrt at
|
||||||
double vel; ///< velocity, for flail balls
|
double vel; ///< velocity, for flail balls
|
||||||
double footphase;
|
double footphase;
|
||||||
|
@ -65,8 +66,8 @@ struct monster {
|
||||||
|
|
||||||
monster() {
|
monster() {
|
||||||
dead = false; inBoat = false; parent = NULL; nextshot = 0;
|
dead = false; inBoat = false; parent = NULL; nextshot = 0;
|
||||||
stunoff = 0; blowoff = 0; footphase = 0; no_targetting = false;
|
stunoff = 0; blowoff = 0; fragoff = 0; footphase = 0; no_targetting = false;
|
||||||
swordangle = 0; inertia = Hypc; ori = Id; refs = 1;
|
swordangle = 0; inertia = Hypc; ori = Id; refs = 1;
|
||||||
split_tick = -1; split_owner = -1;
|
split_tick = -1; split_owner = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +271,12 @@ void killMonster(monster* m, eMonster who_kills, flagtype flags = 0) {
|
||||||
if(callhandlers(false, hooks_kill, m)) return;
|
if(callhandlers(false, hooks_kill, m)) return;
|
||||||
if(m->dead) return;
|
if(m->dead) return;
|
||||||
m->dead = true;
|
m->dead = true;
|
||||||
|
if(isPlayer(m)) {
|
||||||
|
if(multi::cpid == m->pid)
|
||||||
|
multi::suicides[multi::cpid]++;
|
||||||
|
else if(multi::cpid >= 0)
|
||||||
|
multi::pkills[multi::cpid]++;
|
||||||
|
}
|
||||||
if(isBullet(m) || isPlayer(m)) return;
|
if(isBullet(m) || isPlayer(m)) return;
|
||||||
m->stk = m->base->monst;
|
m->stk = m->base->monst;
|
||||||
if(m->inBoat && isWatery(m->base)) {
|
if(m->inBoat && isWatery(m->base)) {
|
||||||
|
@ -400,6 +407,9 @@ ld bullet_velocity(eMonster t) {
|
||||||
|
|
||||||
int frontdir() { return WDIM == 2 ? 0 : 2; }
|
int frontdir() { return WDIM == 2 ? 0 : 2; }
|
||||||
|
|
||||||
|
/** cannot hit yourself during first 100ms after shooting a bullet */
|
||||||
|
const int bullet_time = 100;
|
||||||
|
|
||||||
void shootBullet(monster *m) {
|
void shootBullet(monster *m) {
|
||||||
monster* bullet = new monster;
|
monster* bullet = new monster;
|
||||||
bullet->base = m->base;
|
bullet->base = m->base;
|
||||||
|
@ -412,6 +422,7 @@ void shootBullet(monster *m) {
|
||||||
bullet->inertia = m->inertia;
|
bullet->inertia = m->inertia;
|
||||||
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
|
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
|
||||||
bullet->hitpoints = 0;
|
bullet->hitpoints = 0;
|
||||||
|
bullet->fragoff = ticks + bullet_time;
|
||||||
|
|
||||||
additional.push_back(bullet);
|
additional.push_back(bullet);
|
||||||
|
|
||||||
|
@ -429,6 +440,7 @@ void shootBullet(monster *m) {
|
||||||
bullet->set_parent(m);
|
bullet->set_parent(m);
|
||||||
bullet->pid = m->pid;
|
bullet->pid = m->pid;
|
||||||
bullet->hitpoints = 0;
|
bullet->hitpoints = 0;
|
||||||
|
bullet->fragoff = ticks + bullet_time;
|
||||||
bullet->inertia = cspin(0, WDIM-1, -M_PI/4 * i) * m->inertia;
|
bullet->inertia = cspin(0, WDIM-1, -M_PI/4 * i) * m->inertia;
|
||||||
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
|
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
|
||||||
additional.push_back(bullet);
|
additional.push_back(bullet);
|
||||||
|
@ -1755,8 +1767,10 @@ void moveBullet(monster *m, int delta) {
|
||||||
|
|
||||||
// items[itOrbWinter] = 100; items[itOrbLife] = 100;
|
// items[itOrbWinter] = 100; items[itOrbLife] = 100;
|
||||||
|
|
||||||
|
bool no_self_hits = !multi::self_hits || m->fragoff > ticks;
|
||||||
|
|
||||||
if(!m->isVirtual) for(monster* m2: nonvirtual) {
|
if(!m->isVirtual) for(monster* m2: nonvirtual) {
|
||||||
if(m2 == m || (m2 == m->parent && m->vel >= 0) || m2->parent == m->parent)
|
if(m2 == m || (m2 == m->parent && no_self_hits) || (m2->parent == m->parent && no_self_hits))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(m2->dead) continue;
|
if(m2->dead) continue;
|
||||||
|
@ -1765,7 +1779,9 @@ void moveBullet(monster *m, int delta) {
|
||||||
if(m2->type == moFlailer && m2 != m->parent) continue;
|
if(m2->type == moFlailer && m2 != m->parent) continue;
|
||||||
// be nice to your images! would be too hard otherwise...
|
// be nice to your images! would be too hard otherwise...
|
||||||
if(isPlayerOrImage(parentOrSelf(m)->type) && isPlayerOrImage(parentOrSelf(m2)->type) &&
|
if(isPlayerOrImage(parentOrSelf(m)->type) && isPlayerOrImage(parentOrSelf(m2)->type) &&
|
||||||
m2->pid == m->pid)
|
m2->pid == m->pid && no_self_hits)
|
||||||
|
continue;
|
||||||
|
if(isPlayer(parentOrSelf(m)) && isPlayer(m2) && m2->pid != m->pid && !friendly_fire)
|
||||||
continue;
|
continue;
|
||||||
// fireballs/airballs don't collide
|
// fireballs/airballs don't collide
|
||||||
if(m->type == moFireball && m2->type == moFireball) continue;
|
if(m->type == moFireball && m2->type == moFireball) continue;
|
||||||
|
@ -2538,6 +2554,9 @@ EX void fixStorage() {
|
||||||
|
|
||||||
EX hookset<bool(int)> hooks_turn;
|
EX hookset<bool(int)> hooks_turn;
|
||||||
|
|
||||||
|
/** the amount of time chars are disabled in PvP */
|
||||||
|
EX int pvp_delay = 2000;
|
||||||
|
|
||||||
EX void turn(int delta) {
|
EX void turn(int delta) {
|
||||||
|
|
||||||
if(split_screen && subscreens::split( [delta] () { turn(delta); })) return;
|
if(split_screen && subscreens::split( [delta] () { turn(delta); })) return;
|
||||||
|
@ -2753,6 +2772,15 @@ EX void turn(int delta) {
|
||||||
items[itOrbShield] = 1;
|
items[itOrbShield] = 1;
|
||||||
orbused[itOrbShield] = true;
|
orbused[itOrbShield] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(pc[i]->dead && pvp_mode) {
|
||||||
|
pc[i]->dead = false;
|
||||||
|
if(ticks > pc[i]->fragoff) {
|
||||||
|
pc[i]->fragoff = ticks + pvp_delay;
|
||||||
|
pc[i]->nextshot = min(pc[i]->nextshot, pc[i]->fragoff);
|
||||||
|
multi::deaths[i]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(pc[i]->dead && items[itOrbLife]) {
|
if(pc[i]->dead && items[itOrbLife]) {
|
||||||
multi::deaths[i]++;
|
multi::deaths[i]++;
|
||||||
|
@ -3033,7 +3061,11 @@ bool celldrawer::draw_shmup_monster() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m->inBoat) m->footphase = 0;
|
if(m->inBoat) m->footphase = 0;
|
||||||
if(mapeditor::drawplayer) drawMonsterType(moPlayer, c, view, 0xFFFFFFC0, m->footphase, 0xFFFFFFC0);
|
if(mapeditor::drawplayer) {
|
||||||
|
if(m->fragoff > ticks)
|
||||||
|
drawShield(view, itWarning);
|
||||||
|
drawMonsterType(moPlayer, c, view, 0xFFFFFFC0, m->footphase, 0xFFFFFFC0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ths && h) first_cell_to_draw = false;
|
if(ths && h) first_cell_to_draw = false;
|
||||||
|
|
Loading…
Reference in New Issue