mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-10-26 11:27:39 +00:00
Implemented the shmup versions of Ruined City and Jelly Kingdom.
This commit is contained in:
@@ -784,6 +784,7 @@ monstertype minf[motypes] = {
|
|||||||
{ '*', 0xFFFF00, "Fireball", "This magical missile burns whatever it hits."},
|
{ '*', 0xFFFF00, "Fireball", "This magical missile burns whatever it hits."},
|
||||||
{ '*', 0xFFFF00, "Tongue", "Some monsters have long tongues, which allow them to attack enemies in nearby cells."},
|
{ '*', 0xFFFF00, "Tongue", "Some monsters have long tongues, which allow them to attack enemies in nearby cells."},
|
||||||
{ '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."},
|
{ '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."},
|
||||||
|
{ '*', 0x0060E0, "Blueball", "A powerful missile from a Blue Raider."},
|
||||||
// technical
|
// technical
|
||||||
{ '?', 0x00C000, "dead bug", NODESC},
|
{ '?', 0x00C000, "dead bug", NODESC},
|
||||||
{ '?', 0xFFFF00, "electric discharge", elecdesc}, // appears as 'killed by electric discharge'
|
{ '?', 0xFFFF00, "electric discharge", elecdesc}, // appears as 'killed by electric discharge'
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
static const int motypes = 161;
|
static const int motypes = 162;
|
||||||
|
|
||||||
struct monstertype {
|
struct monstertype {
|
||||||
char glyph;
|
char glyph;
|
||||||
@@ -56,7 +56,7 @@ enum eMonster {
|
|||||||
moPair, moHexDemon, moAltDemon, moMonk, moCrusher,
|
moPair, moHexDemon, moAltDemon, moMonk, moCrusher,
|
||||||
moSwitch1, moSwitch2,
|
moSwitch1, moSwitch2,
|
||||||
// shmup specials
|
// shmup specials
|
||||||
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
|
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moCrushball,
|
||||||
// temporary
|
// temporary
|
||||||
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning, moArrowTrap,
|
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning, moArrowTrap,
|
||||||
moRogueviz
|
moRogueviz
|
||||||
|
|||||||
20
game.cpp
20
game.cpp
@@ -842,12 +842,24 @@ bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
|
|||||||
return passable(w, from, extra) && !cellUnstable(w) && ((m != moWorm && m != moTentacle) || !cellEdgeUnstable(w));
|
return passable(w, from, extra) && !cellUnstable(w) && ((m != moWorm && m != moTentacle) || !cellEdgeUnstable(w));
|
||||||
if(m == moVoidBeast)
|
if(m == moVoidBeast)
|
||||||
return passable(w, from, extra | P_VOID);
|
return passable(w, from, extra | P_VOID);
|
||||||
if(m == moHexDemon)
|
if(m == moHexDemon) {
|
||||||
|
if(extra & P_ONPLAYER) {
|
||||||
|
if(isPlayerOn(w)) return true;
|
||||||
|
}
|
||||||
return !ctof(w) && passable(w, from, extra);
|
return !ctof(w) && passable(w, from, extra);
|
||||||
if(m == moAltDemon)
|
}
|
||||||
return (!w || !from || ctof(w) || ctof(from)) && passable(w, from, extra);
|
if(m == moAltDemon) {
|
||||||
if(m == moMonk)
|
if(extra & P_ONPLAYER) {
|
||||||
|
if(isPlayerOn(w)) return true;
|
||||||
|
}
|
||||||
|
return (!w || !from || w==from || ctof(w) || ctof(from)) && passable(w, from, extra);
|
||||||
|
}
|
||||||
|
if(m == moMonk) {
|
||||||
|
if(extra & P_ONPLAYER) {
|
||||||
|
if(isPlayerOn(w)) return true;
|
||||||
|
}
|
||||||
return notNearItem(w) && passable(w, from, extra);
|
return notNearItem(w) && passable(w, from, extra);
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
hyper.h
3
hyper.h
@@ -526,6 +526,9 @@ namespace shmup {
|
|||||||
void addShmupHelp(string& out);
|
void addShmupHelp(string& out);
|
||||||
void activateArrow(cell *c);
|
void activateArrow(cell *c);
|
||||||
transmatrix& ggmatrix(cell *c);
|
transmatrix& ggmatrix(cell *c);
|
||||||
|
|
||||||
|
void pushmonsters();
|
||||||
|
void popmonsters();
|
||||||
}
|
}
|
||||||
|
|
||||||
// graph
|
// graph
|
||||||
|
|||||||
@@ -1938,7 +1938,7 @@ void giantLandSwitch(cell *c, int d, cell *from) {
|
|||||||
forCellEx(c2, c) if(out_ruin(c2))
|
forCellEx(c2, c) if(out_ruin(c2))
|
||||||
c->wall = waRuinWall;
|
c->wall = waRuinWall;
|
||||||
}
|
}
|
||||||
if(hrand(40000) < kf && !c->monst && !c->wall) {
|
if(hrand(40000) < kf && !c->monst && !c->wall && !shmup::on) {
|
||||||
cell *c1 = c;
|
cell *c1 = c;
|
||||||
cell *c2 = createMov(c1, hrand(c1->type));
|
cell *c2 = createMov(c1, hrand(c1->type));
|
||||||
if(c2->monst || c2->wall) return;
|
if(c2->monst || c2->wall) return;
|
||||||
|
|||||||
@@ -1257,10 +1257,6 @@ int isLandValid(eLand l) {
|
|||||||
if(l == laStorms && torus)
|
if(l == laStorms && torus)
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
// not yet implemented in Shmup
|
|
||||||
if(shmup::on && (l == laSwitch || l == laRuins))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if(l == laMagnetic)
|
if(l == laMagnetic)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
4
orbs.cpp
4
orbs.cpp
@@ -1116,6 +1116,7 @@ eItem targetRangedOrb(cell *c, orbAction a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(items[itOrbPhasing] && c->cpdist == 2) {
|
if(items[itOrbPhasing] && c->cpdist == 2) {
|
||||||
|
if(shmup::on) shmup::pushmonsters();
|
||||||
jumpstate = 21;
|
jumpstate = 21;
|
||||||
int i = items[itOrbAether];
|
int i = items[itOrbAether];
|
||||||
if(i) items[itOrbAether] = i-1;
|
if(i) items[itOrbAether] = i-1;
|
||||||
@@ -1136,8 +1137,9 @@ eItem targetRangedOrb(cell *c, orbAction a) {
|
|||||||
if(jumpstate == 23 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.c)) {
|
if(jumpstate == 23 && !monstersnearO(a, c, NULL, moPlayer, NULL, cwt.c)) {
|
||||||
jumpstate = 24;
|
jumpstate = 24;
|
||||||
if(!isCheck(a)) jumpTo(c, itOrbPhasing);
|
if(!isCheck(a)) jumpTo(c, itOrbPhasing);
|
||||||
return itOrbPhasing;
|
|
||||||
}
|
}
|
||||||
|
if(shmup::on) shmup::popmonsters();
|
||||||
|
if(jumpstate == 24) return itOrbPhasing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (1) switch with an illusion
|
// (1) switch with an illusion
|
||||||
|
|||||||
64
shmup.cpp
64
shmup.cpp
@@ -1596,7 +1596,15 @@ void movePlayer(monster *m, int delta) {
|
|||||||
|
|
||||||
// don't have several players in one spot
|
// don't have several players in one spot
|
||||||
// also don't let them run too far from each other!
|
// also don't let them run too far from each other!
|
||||||
monster* crashintomon = m->isVirtual ? NULL : playerCrash(m, nat*C0);
|
monster* crashintomon = NULL;
|
||||||
|
|
||||||
|
if(!m->isVirtual) {
|
||||||
|
crashintomon = playerCrash(m, nat*C0);
|
||||||
|
for(monster *m2: nonvirtual) if(m2!=m && m2->type == passive_switch) {
|
||||||
|
double d = intval(m2->pat*C0, nat*C0);
|
||||||
|
if(d < SCALE2 * 0.2) crashintomon = m2;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(crashintomon) go = false;
|
if(crashintomon) go = false;
|
||||||
|
|
||||||
if(go && c2 != m->base) {
|
if(go && c2 != m->base) {
|
||||||
@@ -2082,6 +2090,8 @@ void moveBullet(monster *m, int delta) {
|
|||||||
m->vel = 1/300.;
|
m->vel = 1/300.;
|
||||||
else if(m->type == moFireball)
|
else if(m->type == moFireball)
|
||||||
m->vel = 1/500.;
|
m->vel = 1/500.;
|
||||||
|
else if(m->type == moCrushball)
|
||||||
|
m->vel = 1/1000.;
|
||||||
else if(m->type == moAirball)
|
else if(m->type == moAirball)
|
||||||
m->vel = 1/200.;
|
m->vel = 1/200.;
|
||||||
else if(m->type == moArrowTrap)
|
else if(m->type == moArrowTrap)
|
||||||
@@ -2127,6 +2137,8 @@ void moveBullet(monster *m, int delta) {
|
|||||||
else if(isActivable(c2))
|
else if(isActivable(c2))
|
||||||
activateActiv(c2, true);
|
activateActiv(c2, true);
|
||||||
}
|
}
|
||||||
|
if(m->type == moCrushball && c2->wall == waRuinWall)
|
||||||
|
c2->wall = waNone;
|
||||||
if(m->type == moFireball) {
|
if(m->type == moFireball) {
|
||||||
makeflame(c2, 20, false) || makeflame(m->base, 20, false);
|
makeflame(c2, 20, false) || makeflame(m->base, 20, false);
|
||||||
}
|
}
|
||||||
@@ -2144,6 +2156,10 @@ void moveBullet(monster *m, int delta) {
|
|||||||
if(m2 == m || (m2 == m->parent && m->vel >= 0) || m2->parent == m->parent)
|
if(m2 == m || (m2 == m->parent && m->vel >= 0) || m2->parent == m->parent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
eMonster ptype = parentOrSelf(m)->type;
|
||||||
|
bool slayer = m->type == moCrushball ||
|
||||||
|
(markOrb(itOrbSlaying) && (markOrb(itOrbEmpathy) ? isPlayerOrImage(ptype) : ptype == moPlayer));
|
||||||
|
|
||||||
// Flailers only killable by themselves
|
// Flailers only killable by themselves
|
||||||
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...
|
||||||
@@ -2156,6 +2172,9 @@ void moveBullet(monster *m, int delta) {
|
|||||||
double d = intval(m2->pat*C0, m->pat*C0);
|
double d = intval(m2->pat*C0, m->pat*C0);
|
||||||
|
|
||||||
if(d < SCALE2 * 0.1) {
|
if(d < SCALE2 * 0.1) {
|
||||||
|
|
||||||
|
if(m2->type == passive_switch) { m->dead = true; continue; }
|
||||||
|
|
||||||
if(m->type == moAirball && isBlowableMonster(m2->type)) {
|
if(m->type == moAirball && isBlowableMonster(m2->type)) {
|
||||||
|
|
||||||
if(m2->blowoff < curtime) {
|
if(m2->blowoff < curtime) {
|
||||||
@@ -2167,7 +2186,7 @@ void moveBullet(monster *m, int delta) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Hedgehog Warriors only killable outside of the 45 degree angle
|
// Hedgehog Warriors only killable outside of the 45 degree angle
|
||||||
if(m2->type == moHedge && !peace::on) {
|
if(m2->type == moHedge && !peace::on && !slayer) {
|
||||||
hyperpoint h = inverse(m2->pat) * m->pat * C0;
|
hyperpoint h = inverse(m2->pat) * m->pat * C0;
|
||||||
if(h[0] > fabsl(h[1])) { m->dead = true; continue; }
|
if(h[0] > fabsl(h[1])) { m->dead = true; continue; }
|
||||||
}
|
}
|
||||||
@@ -2176,10 +2195,10 @@ void moveBullet(monster *m, int delta) {
|
|||||||
m2->stunoff = curtime + 600;
|
m2->stunoff = curtime + 600;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//
|
// multi-HP monsters
|
||||||
if((m2->type == moPalace || m2->type == moFatGuard || m2->type == moSkeleton ||
|
if((m2->type == moPalace || m2->type == moFatGuard || m2->type == moSkeleton ||
|
||||||
m2->type == moVizier || isMetalBeast(m2->type) || m2->type == moTortoise ||
|
m2->type == moVizier || isMetalBeast(m2->type) || m2->type == moTortoise ||
|
||||||
m2->type == moReptile || m2->type == moSalamander || m2->type == moTerraWarrior) && m2->hitpoints > 1) {
|
m2->type == moReptile || m2->type == moSalamander || m2->type == moTerraWarrior) && m2->hitpoints > 1 && !slayer) {
|
||||||
m2->rebasePat(m2->pat * rspintox(inverse(m2->pat) * nat0 * C0));
|
m2->rebasePat(m2->pat * rspintox(inverse(m2->pat) * nat0 * C0));
|
||||||
if(m2->type != moSkeleton && !isMetalBeast(m2->type) && m2->type != moReptile && m2->type != moSalamander)
|
if(m2->type != moSkeleton && !isMetalBeast(m2->type) && m2->type != moReptile && m2->type != moSalamander)
|
||||||
m2->hitpoints--;
|
m2->hitpoints--;
|
||||||
@@ -2202,8 +2221,14 @@ void moveBullet(monster *m, int delta) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// conventional missiles cannot hurt some monsters
|
// conventional missiles cannot hurt some monsters
|
||||||
bool conv = (m->type == moBullet || m->type == moFlailBullet || m->type == moTongue || m->type == moArrowTrap);
|
bool conv = (m->type == moBullet || m->type == moFlailBullet || m->type == moTongue || m->type == moArrowTrap) && !slayer;
|
||||||
|
|
||||||
|
// Raiders are unaffected
|
||||||
|
if((m2->type == moCrusher || m2->type == moPair || m2->type == moMonk ||
|
||||||
|
m2->type == moAltDemon || m2->type == moHexDemon) && conv) {
|
||||||
|
m->dead = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(m2->type == moGreater && conv) {
|
if(m2->type == moGreater && conv) {
|
||||||
m->dead = true;
|
m->dead = true;
|
||||||
continue;
|
continue;
|
||||||
@@ -2326,6 +2351,10 @@ void moveMonster(monster *m, int delta) {
|
|||||||
step /= 3;
|
step /= 3;
|
||||||
else if(isBull(m->type))
|
else if(isBull(m->type))
|
||||||
step *= 1.5;
|
step *= 1.5;
|
||||||
|
else if(m->type == moAltDemon || m->type == moHexDemon || m->type == moCrusher || m->type == moMonk)
|
||||||
|
step *= 1.4;
|
||||||
|
|
||||||
|
if(m->type == passive_switch) step = 0;
|
||||||
|
|
||||||
if(items[itOrbBeauty] && !m->isVirtual) {
|
if(items[itOrbBeauty] && !m->isVirtual) {
|
||||||
bool nearplayer = false;
|
bool nearplayer = false;
|
||||||
@@ -2395,7 +2424,7 @@ void moveMonster(monster *m, int delta) {
|
|||||||
closerTo = m->pat * C0;
|
closerTo = m->pat * C0;
|
||||||
sort(bugtargets.begin(), bugtargets.end(), closer);
|
sort(bugtargets.begin(), bugtargets.end(), closer);
|
||||||
|
|
||||||
for(monster *m2: bugtargets)
|
if(step) for(monster *m2: bugtargets)
|
||||||
if(trackroute(m, m2->pat, step)) {
|
if(trackroute(m, m2->pat, step)) {
|
||||||
goal = m2->pat;
|
goal = m2->pat;
|
||||||
direct = true;
|
direct = true;
|
||||||
@@ -2441,7 +2470,7 @@ void moveMonster(monster *m, int delta) {
|
|||||||
}
|
}
|
||||||
else if(!direct && !invismove && !peace::on) {
|
else if(!direct && !invismove && !peace::on) {
|
||||||
for(int i=0; i<players; i++)
|
for(int i=0; i<players; i++)
|
||||||
if(trackroute(m, pc[i]->pat, step) && (!direct || intval(pc[i]->pat*C0, m->pat*C0) < intval(goal*C0,m->pat*C0))) {
|
if(step && trackroute(m, pc[i]->pat, step) && (!direct || intval(pc[i]->pat*C0, m->pat*C0) < intval(goal*C0,m->pat*C0))) {
|
||||||
goal = pc[i]->pat;
|
goal = pc[i]->pat;
|
||||||
direct = true;
|
direct = true;
|
||||||
directi = i;
|
directi = i;
|
||||||
@@ -2450,7 +2479,7 @@ void moveMonster(monster *m, int delta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!direct && !peace::on) while(true) {
|
if(!direct && !peace::on) while(true) {
|
||||||
if(trackroute(m, gmatrix[c], step))
|
if(step && trackroute(m, gmatrix[c], step))
|
||||||
goal = gmatrix[c];
|
goal = gmatrix[c];
|
||||||
cell *cnext = c;
|
cell *cnext = c;
|
||||||
for(int i=0; i<c->type; i++) {
|
for(int i=0; i<c->type; i++) {
|
||||||
@@ -2581,6 +2610,8 @@ void moveMonster(monster *m, int delta) {
|
|||||||
if(c2->wall == waChasm && !survivesChasm(m->type)) usetongue = true;
|
if(c2->wall == waChasm && !survivesChasm(m->type)) usetongue = true;
|
||||||
if(isFireOrMagma(c2) && !survivesFire(m->type) && !m->inBoat) usetongue = true;
|
if(isFireOrMagma(c2) && !survivesFire(m->type) && !m->inBoat) usetongue = true;
|
||||||
if(isBird(m->type) && !passable_for(moEagle, c2, c, 0)) usetongue = true;
|
if(isBird(m->type) && !passable_for(moEagle, c2, c, 0)) usetongue = true;
|
||||||
|
if((m->type == moMonk || m->type == moAltDemon || m->type == moHexDemon) && !passable_for(m->type, c2, c, 0))
|
||||||
|
usetongue = true;
|
||||||
if(usetongue) {
|
if(usetongue) {
|
||||||
if(curtime < m->nextshot) return;
|
if(curtime < m->nextshot) return;
|
||||||
// m->nextshot = curtime + 25;
|
// m->nextshot = curtime + 25;
|
||||||
@@ -2786,6 +2817,18 @@ void moveMonster(monster *m, int delta) {
|
|||||||
additional.push_back(bullet);
|
additional.push_back(bullet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
for(int i=0; i<players; i++) if(!pc[i]->isVirtual)
|
||||||
|
if(m->type == moCrusher && intval(m->pat*C0, pc[i]->pat*C0) < SCALE2 * .75) {
|
||||||
|
m->stunoff = curtime + 1500;
|
||||||
|
monster* bullet = new monster;
|
||||||
|
bullet->base = m->base;
|
||||||
|
bullet->at = m->at;
|
||||||
|
bullet->type = moCrushball;
|
||||||
|
bullet->parent = m;
|
||||||
|
bullet->pid = i;
|
||||||
|
additional.push_back(bullet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2830,6 +2873,7 @@ void fixStorage() {
|
|||||||
|
|
||||||
void turn(int delta) {
|
void turn(int delta) {
|
||||||
|
|
||||||
|
passive_switch = (gold() & 1) ? moSwitch1 : moSwitch2;
|
||||||
lmousetarget = NULL;
|
lmousetarget = NULL;
|
||||||
if(mousetarget && !mousetarget->isVirtual && intval(mouseh, mousetarget->pat*C0) < 0.1)
|
if(mousetarget && !mousetarget->isVirtual && intval(mouseh, mousetarget->pat*C0) < 0.1)
|
||||||
lmousetarget = mousetarget;
|
lmousetarget = mousetarget;
|
||||||
@@ -2875,7 +2919,7 @@ void turn(int delta) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case moBullet: case moFlailBullet: case moFireball: case moTongue: case moAirball:
|
case moBullet: case moFlailBullet: case moFireball: case moTongue: case moAirball:
|
||||||
case moArrowTrap:
|
case moArrowTrap: case moCrushball:
|
||||||
moveBullet(m, delta);
|
moveBullet(m, delta);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3205,7 +3249,7 @@ bool drawMonster(const transmatrix& V, cell *c, const transmatrix*& Vboat, trans
|
|||||||
ShadowV(view, shPHead);
|
ShadowV(view, shPHead);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case moFlailBullet: {
|
case moFlailBullet: case moCrushball: {
|
||||||
transmatrix t = view * spin(curtime / 50.0);
|
transmatrix t = view * spin(curtime / 50.0);
|
||||||
queuepoly(mmscale(t, 1.15), shFlailMissile, (minf[m->type].color << 8) | 0xFF);
|
queuepoly(mmscale(t, 1.15), shFlailMissile, (minf[m->type].color << 8) | 0xFF);
|
||||||
ShadowV(view, shFlailMissile);
|
ShadowV(view, shFlailMissile);
|
||||||
|
|||||||
Reference in New Issue
Block a user