mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-11 09:50:34 +00:00
Theming Ruins. Implemented Orb of Slaying (also cleaning up some kill/stun/Vizier code).
This commit is contained in:
parent
86e760a562
commit
a8460b1ac7
20
classes.cpp
20
classes.cpp
@ -759,11 +759,11 @@ monstertype minf[motypes] = {
|
||||
"When your plan has clearly failed, it is better to abandon it and go to a safe place, to have a chance of succeeding next time. This dog clearly knows this."},
|
||||
{ 'B', 0xC00000, "North Pole", NODESCYET},
|
||||
{ 'B', 0x0000C0, "South Pole", NODESCYET},
|
||||
{ 'P', 0xC0D000, "Pair Demon", NODESCYET},
|
||||
{ 'H', 0x00C0D0, "Hex Demon", NODESCYET},
|
||||
{ 'A', 0xD000C0, "Alt Demon", NODESCYET},
|
||||
{ 'M', 0x904000, "Monk", NODESCYET},
|
||||
{ 'C', 0x004070, "Crusher", NODESCYET},
|
||||
{ 'P', 0xC03000, "Red Raider", NODESCYET},
|
||||
{ 'H', 0xC0C0C0, "Gray Raider", NODESCYET},
|
||||
{ 'A', 0x80B080, "Green Raider", NODESCYET},
|
||||
{ 'M', 0x904000, "Brown Raider", NODESCYET},
|
||||
{ 'C', 0x0060E0, "Blue Raider", NODESCYET},
|
||||
{ '@', 0xC00000, "Switcher A", NODESCYET},
|
||||
{ '@', 0x0000C0, "Switcher B", NODESCYET},
|
||||
|
||||
@ -1213,12 +1213,13 @@ itemtype iinf[ittypes] = {
|
||||
{ '!', 0x80FF00, "Glowing Crystal", crystaldesc},
|
||||
{ '!', 0x80FF80, "Snake Oil", NODESCYET},
|
||||
{ '*', 0x80FF80, "Sea Glass", NODESCYET},
|
||||
{ '*', 0xFFFFFF, "Invix Treasure", NODESCYET},
|
||||
{ '*', 0xD0D8ED, "Chalcedony", NODESCYET},
|
||||
{ '*', 0x80FF80, "Monopole", NODESCYET},
|
||||
{ '*', 0xFFFF80, "Junk", NODESCYET},
|
||||
{ '*', 0xBBCC99, "Chrysoberyl", NODESCYET},
|
||||
{ 'o', 0x80FF80, "Orb of Phasing", NODESCYET},
|
||||
{ 'o', 0xFFFF80, "Orb of Magnetism", NODESCYET},
|
||||
{ 'o', 0xFFFF80, "Orb of Destruction", NODESCYET},
|
||||
{ 'o', 0x202020, "Orb of Slaying", NODESCYET},
|
||||
// { '*', 0x26619C, "Lapis Lazuli", NODESCYET},
|
||||
};
|
||||
|
||||
// --- wall types ---
|
||||
@ -1398,6 +1399,7 @@ walltype winf[walltypes] = {
|
||||
{ '&', 0xD00000, "lava", lavadesc},
|
||||
{ '=', 0x804000, "dock", "A dock."},
|
||||
{ '^', 0xFF8000, "burning dock", "A burning dock."},
|
||||
{ '#', 0xE07070, "ruin wall", "A ruin wall."},
|
||||
};
|
||||
|
||||
// --- land types ---
|
||||
@ -1585,7 +1587,7 @@ const landtype linf[landtypes] = {
|
||||
{ 0x80FF00, "Crystal World", crystaldesc},
|
||||
{ 0x306030, "Snake Nest", NODESCYET},
|
||||
{ 0x80FF00, "Docks", NODESCYET},
|
||||
{ 0x306030, "Invincible", NODESCYET},
|
||||
{ 0x306030, "Ruined City", NODESCYET},
|
||||
{ 0x306030, "Magnetosphere", NODESCYET},
|
||||
{ 0x306030, "Switch", NODESCYET},
|
||||
};
|
||||
|
@ -117,10 +117,10 @@ enum eItem {
|
||||
itOrbSide1, itOrbSide2, itOrbSide3,
|
||||
itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
|
||||
itDock, itInvix, itMagnet, itSwitch,
|
||||
itOrbPhasing, itOrbMagnetism, itOrbDestruction
|
||||
itOrbPhasing, itOrbMagnetism, itOrbSlaying
|
||||
};
|
||||
|
||||
static const int walltypes = 107;
|
||||
static const int walltypes = 108;
|
||||
|
||||
struct walltype {
|
||||
char glyph;
|
||||
@ -161,7 +161,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
|
||||
waTempBridgeBlocked,
|
||||
waTerraWarrior, waBubble,
|
||||
waArrowTrap, waMercury, waMagma,
|
||||
waDock, waBurningDock
|
||||
waDock, waBurningDock, waRuinWall
|
||||
};
|
||||
|
||||
static const int landtypes = 83;
|
||||
|
10
complex.cpp
10
complex.cpp
@ -1199,7 +1199,7 @@ namespace mirror {
|
||||
c->monst = moMimic;
|
||||
eMonster m2 = c2->monst;
|
||||
if(!peace::on && canAttack(c,moMimic,c2,m2, 0)) {
|
||||
attackMonster(c2, AF_MSG | AF_ORSTUN, moMimic);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, moMimic);
|
||||
if(!fwd) produceGhost(c2, m2, moMimic);
|
||||
sideAttack(c, m.second.spin, m2, 0);
|
||||
}
|
||||
@ -1642,7 +1642,7 @@ namespace hive {
|
||||
if(isBug(killed)) battlecount++;
|
||||
else if(killed != moPlayer && !fightspam(c2))
|
||||
addMessage(XLAT("%The1 fights with %the2!", c->monst, killed));
|
||||
attackMonster(c2, AF_ORSTUN | AF_GETPLAYER, c->monst);
|
||||
attackMonster(c2, AF_NORMAL | AF_GETPLAYER, c->monst);
|
||||
// killMonster(c);
|
||||
if(isBug(killed)) {
|
||||
c2->monst = moDeadBug, deadbug.push_back(c2);
|
||||
@ -2020,7 +2020,7 @@ namespace heat {
|
||||
c->wparam++;
|
||||
if(c->wparam == 3) {
|
||||
if(canAttack(c, moArrowTrap, c, c->monst, AF_GETPLAYER))
|
||||
attackMonster(c, AF_ORSTUN | AF_MSG | AF_GETPLAYER, moArrowTrap);
|
||||
attackMonster(c, AF_NORMAL | AF_MSG | AF_GETPLAYER, moArrowTrap);
|
||||
}
|
||||
if(c->wparam == 4) c->wparam = 0;
|
||||
}
|
||||
@ -2589,7 +2589,7 @@ namespace kraken {
|
||||
if(c->monst == moKrakenT && !c->stuntime) forCellEx(c2, c) {
|
||||
bool dboat = false;
|
||||
if(c2->monst && canAttack(c, moKrakenT, c2, c2->monst, AF_ONLY_FBUG)) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, c->monst);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, c->monst);
|
||||
sleep(c);
|
||||
}
|
||||
else for(int i=0; i<numplayers(); i++) if(playerpos(i) == c2) {
|
||||
@ -2869,7 +2869,7 @@ namespace prairie {
|
||||
cell *cn = whirlline[q+1];
|
||||
if(cp->monst == moHerdBull && !cp->stuntime) {
|
||||
forCellEx(c2, cp) {
|
||||
int flags = AF_GETPLAYER | AF_BULL | AF_ORSTUN;
|
||||
int flags = AF_GETPLAYER | AF_BULL;
|
||||
if(c2 != cn) flags |= AF_ONLY_FBUG;
|
||||
if(canAttack(c, moHerdBull, c2, c2->monst, flags))
|
||||
attackMonster(c2, flags | AF_MSG, moHerdBull);
|
||||
|
14
flags.cpp
14
flags.cpp
@ -117,7 +117,8 @@ bool isMetalBeast(eMonster m) {
|
||||
bool isStunnable(eMonster m) {
|
||||
return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) ||
|
||||
isMetalBeast(m) || m == moTortoise || isDragon(m) ||
|
||||
m == moReptile || m == moTerraWarrior || m == moSalamander;
|
||||
m == moReptile || m == moTerraWarrior || m == moSalamander ||
|
||||
m == moVizier;
|
||||
}
|
||||
|
||||
bool hasHitpoints(eMonster m) {
|
||||
@ -555,7 +556,8 @@ bool isOffensiveOrb(eItem it) {
|
||||
return it == itOrbLightning || it == itOrbFlash || it == itOrbThorns ||
|
||||
it == itOrbDragon || it == itOrbStunning ||
|
||||
it == itOrbFreedom || it == itOrbPsi ||
|
||||
it == itOrbSide1 || it == itOrbSide2 || it == itOrbSide3;
|
||||
it == itOrbSide1 || it == itOrbSide2 || it == itOrbSide3 ||
|
||||
it == itOrbSlaying;
|
||||
}
|
||||
|
||||
bool isRangedOrb(eItem i) {
|
||||
@ -575,7 +577,8 @@ bool isEmpathyOrb(eItem i) {
|
||||
i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield ||
|
||||
i == itOrbAether || i == itOrbInvis || i == itOrbThorns ||
|
||||
i == itOrbWater || i == itOrbStone ||
|
||||
i == itOrbSide1 || i == itOrbSide2 || i == itOrbSide3;
|
||||
i == itOrbSide1 || i == itOrbSide2 || i == itOrbSide3 ||
|
||||
i == itOrbSlaying;
|
||||
}
|
||||
|
||||
bool isUtilityOrb(eItem i) {
|
||||
@ -720,8 +723,9 @@ bool hornStuns(cell *c) {
|
||||
return
|
||||
m == moRagingBull || m == moSleepBull || m == moHerdBull ||
|
||||
m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr ||
|
||||
m == moHedge || m == moFlailer || m == moVizier ||
|
||||
attackJustStuns(c);
|
||||
m == moHedge || m == moFlailer || m == moVizier || m == moReptile || m == moSalamander ||
|
||||
m == moPair || m == moAltDemon || m == moHexDemon || m == moMonk || m == moCrusher ||
|
||||
attackJustStuns(c, AF_NORMAL);
|
||||
}
|
||||
|
||||
// generate all the world first in the quotient geometry
|
||||
|
107
game.cpp
107
game.cpp
@ -928,6 +928,9 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
|
||||
|
||||
if(m2 == moPlayer && peace::on) return false;
|
||||
|
||||
if((flags & AF_MUSTKILL) && attackJustStuns(c2, flags))
|
||||
return false;
|
||||
|
||||
if((flags & AF_ONLY_FRIEND) && m2 != moPlayer && !isFriendly(c2)) return false;
|
||||
if((flags & AF_ONLY_FBUG) && m2 != moPlayer && !isFriendlyOrBug(c2)) return false;
|
||||
if((flags & AF_ONLY_ENEMY) && (m2 == moPlayer || isFriendlyOrBug(c2))) return false;
|
||||
@ -943,7 +946,7 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
|
||||
(m2 == moKrakenT || m2 == moKrakenH))
|
||||
return false;
|
||||
|
||||
if(m2 == moDraugr && !(flags & (AF_SWORD | AF_MAGIC | AF_SWORD_INTO | AF_HORNS))) return false;
|
||||
if(m2 == moDraugr && !(flags & (AF_SWORD | AF_MAGIC | AF_SWORD_INTO | AF_HORNS | AF_CRUSH))) return false;
|
||||
|
||||
// if(m2 == moHerdBull && !(flags & AF_MAGIC)) return false;
|
||||
if(isBull(m2) && !(flags & (AF_MAGIC | AF_HORNS | AF_SWORD_INTO | AF_CRUSH))) return false;
|
||||
@ -998,7 +1001,7 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
|
||||
// if(m2 == moTortoise && !(flags & AF_MAGIC)) return false;
|
||||
|
||||
if(m2 == moRoseBeauty)
|
||||
if(!(flags & (AF_MAGIC | AF_LANCE | AF_GUN | AF_SWORD_INTO | AF_BULL)))
|
||||
if(!(flags & (AF_MAGIC | AF_LANCE | AF_GUN | AF_SWORD_INTO | AF_BULL | AF_CRUSH)))
|
||||
if(!isMimic(m1))
|
||||
if(!checkOrb(m1, itOrbBeauty) && !checkOrb(m1, itOrbAether) && !checkOrb(m1, itOrbShield))
|
||||
if(!c1 || !c2 || !withRose(c1,c2))
|
||||
@ -1007,7 +1010,7 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
|
||||
if(m2 == moFlailer && !c2->stuntime)
|
||||
if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_SWORD_INTO | AF_BULL | AF_CRUSH))) return false;
|
||||
|
||||
if(m2 == moVizier && c2->hitpoints > 1)
|
||||
if(m2 == moVizier && c2->hitpoints > 1 && !c2->stuntime)
|
||||
if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_FAST | AF_BULL | AF_CRUSH))) return false;
|
||||
|
||||
return true;
|
||||
@ -1800,7 +1803,7 @@ void stunMonster(cell *c2) {
|
||||
(c2->monst == moGreater || c2->monst == moGreaterM) ? 5 :
|
||||
c2->monst == moButterfly ? 2 :
|
||||
c2->monst == moDraugr ? 1 :
|
||||
c2->monst == moVizier ? 1 :
|
||||
c2->monst == moVizier ? 0 :
|
||||
c2->monst == moHedge ? 1 :
|
||||
c2->monst == moFlailer ? 1 :
|
||||
c2->monst == moSalamander ? 6 :
|
||||
@ -1816,8 +1819,15 @@ void stunMonster(cell *c2) {
|
||||
checkStunKill(c2);
|
||||
}
|
||||
|
||||
bool attackJustStuns(cell *c2) {
|
||||
return isStunnable(c2->monst) && c2->hitpoints > 1;
|
||||
bool attackJustStuns(cell *c2, flagtype f) {
|
||||
if(f & AF_HORNS)
|
||||
return hornStuns(c2);
|
||||
else if((f & AF_SWORD) && c2->monst == moSkeleton)
|
||||
return false;
|
||||
else if(f & (AF_CRUSH | AF_MAGIC | AF_FALL | AF_EAT | AF_GUN))
|
||||
return false;
|
||||
else
|
||||
return isStunnable(c2->monst) && c2->hitpoints > 1;
|
||||
}
|
||||
|
||||
void moveEffect(cell *ct, cell *cf, eMonster m);
|
||||
@ -2306,17 +2316,13 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
|
||||
|
||||
int tkt = killtypes();
|
||||
|
||||
bool dostun = (flags & AF_ORSTUN) && attackJustStuns(c);
|
||||
bool dostun = attackJustStuns(c, flags);
|
||||
|
||||
if((flags & AF_HORNS) && hornStuns(c)) dostun = true;
|
||||
if((flags & AF_BULL) && c->monst == moVizier && c->hitpoints > 1) {
|
||||
dostun = true;
|
||||
c->stuntime = 2;
|
||||
}
|
||||
|
||||
if(c->monst == moSkeleton && (flags & AF_SWORD)) dostun = false;
|
||||
if(c->monst == moSkeleton && killer == moCrusher) dostun = false;
|
||||
|
||||
bool eu = elementalUnlocked();
|
||||
bool tu = trollUnlocked();
|
||||
|
||||
@ -3400,7 +3406,7 @@ void moveMonster(cell *ct, cell *cf) {
|
||||
for(int u=2; u<=ct->type-2; u++) {
|
||||
cell *c3 = ct->mov[(ct->mondir+u)%ct->type];
|
||||
if(canAttack(ct, moLancer, c3, c3->monst, AF_LANCE | AF_GETPLAYER)) {
|
||||
attackMonster(c3, AF_LANCE | AF_ORSTUN | AF_MSG | AF_GETPLAYER, m);
|
||||
attackMonster(c3, AF_LANCE | AF_MSG | AF_GETPLAYER, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3480,7 +3486,7 @@ void moveMonster(cell *ct, cell *cf) {
|
||||
fallMonster(ct);
|
||||
}
|
||||
if(sword::at(ct) && canAttack(NULL, moPlayer, ct, m, AF_SWORD_INTO)) {
|
||||
attackMonster(ct, AF_SWORD_INTO | AF_ORSTUN | AF_MSG, moPlayer);
|
||||
attackMonster(ct, AF_SWORD_INTO | AF_MSG, moPlayer);
|
||||
achievement_gain("GOSWORD");
|
||||
}
|
||||
}
|
||||
@ -3819,7 +3825,7 @@ void beastAttack(cell *c, bool player) {
|
||||
if(c->mondir == NODIR) return;
|
||||
forCellIdEx(c2, d, c) {
|
||||
bool opposite = angledist(c, d, c->mondir) >= 3;
|
||||
int flags = AF_BULL | AF_ORSTUN;
|
||||
int flags = AF_BULL;
|
||||
if(player) flags |= AF_GETPLAYER;
|
||||
if(!opposite) flags |= AF_ONLY_FBUG;
|
||||
if(canAttack(c, moRagingBull, c2, c2->monst, flags)) {
|
||||
@ -3889,7 +3895,7 @@ cell *moveNormal(cell *c, flagtype mf) {
|
||||
return c2;
|
||||
}
|
||||
else if(m2) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, m);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, m);
|
||||
if(m == moFlailer && m2 == moIllusion)
|
||||
attackMonster(c, 0, m2);
|
||||
return c2;
|
||||
@ -3912,7 +3918,7 @@ cell *moveNormal(cell *c, flagtype mf) {
|
||||
else {
|
||||
eMonster m2 = c2->monst;
|
||||
if(m2) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, m);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, m);
|
||||
if(m == moFlailer && m2 == moIllusion)
|
||||
attackMonster(c, 0, m2);
|
||||
attacking = true;
|
||||
@ -4007,7 +4013,7 @@ void killThePlayer(eMonster m, int id, flagtype flags) {
|
||||
}
|
||||
else if(items[itOrbDomination] && playerpos(id)->monst) {
|
||||
addMessage(XLAT("%The1 tries to dismount you!", m));
|
||||
attackMonster(playerpos(id), AF_ORSTUN, m);
|
||||
attackMonster(playerpos(id), AF_NORMAL, m);
|
||||
useupOrb(itOrbDomination, items[itOrbDomination]/2);
|
||||
}
|
||||
else if(items[itOrbShell] && !(flags & AF_EAT)) {
|
||||
@ -4080,7 +4086,7 @@ void moveWorm(cell *c) {
|
||||
// explodeAround(c);
|
||||
forCellEx(c2, c)
|
||||
if(canAttack(c, c->monst, c2, c2->monst, mounted ? AF_ONLY_ENEMY : (AF_GETPLAYER | AF_ONLY_FBUG))) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
}
|
||||
cell *c2 = c;
|
||||
vector<cell*> allcells;
|
||||
@ -4277,13 +4283,13 @@ void moveivy() {
|
||||
if(isPlayerOn(c->mov[j]))
|
||||
killThePlayerAt(c->monst, c->mov[j], 0);
|
||||
else {
|
||||
if(attackJustStuns(c->mov[j]))
|
||||
if(attackJustStuns(c->mov[j], 0))
|
||||
addMessage(XLAT("The ivy attacks %the1!", c->mov[j]->monst));
|
||||
else if(isNonliving(c->mov[j]->monst))
|
||||
addMessage(XLAT("The ivy destroys %the1!", c->mov[j]->monst));
|
||||
else
|
||||
addMessage(XLAT("The ivy kills %the1!", c->mov[j]->monst));
|
||||
attackMonster(c->mov[j], AF_ORSTUN, c->monst);
|
||||
attackMonster(c->mov[j], AF_NORMAL, c->monst);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -4413,7 +4419,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) {
|
||||
// note: move from 'c' to 'from'!
|
||||
if(!(mf & MF_NOATTACKS)) for(int j=0; j<c->type; j++)
|
||||
if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, af)) {
|
||||
attackMonster(c->mov[j], AF_ORSTUN | AF_GETPLAYER | AF_MSG, c->monst);
|
||||
attackMonster(c->mov[j], AF_NORMAL | AF_GETPLAYER | AF_MSG, c->monst);
|
||||
c->aitmp = sval;
|
||||
// XLATC eagle
|
||||
return;
|
||||
@ -4521,7 +4527,7 @@ void snakeAttack(cell *c, bool mounted) {
|
||||
if(c->mov[j] && canAttack(c, moHexSnake, c->mov[j], c->mov[j]->monst,
|
||||
mounted ? AF_ONLY_ENEMY : (AF_ONLY_FBUG | AF_GETPLAYER))) {
|
||||
eMonster m2 = c->mov[j]->monst;
|
||||
attackMonster(c->mov[j], AF_ORSTUN | AF_GETPLAYER | AF_MSG, moHexSnake);
|
||||
attackMonster(c->mov[j], AF_NORMAL | AF_GETPLAYER | AF_MSG, moHexSnake);
|
||||
produceGhost(c->mov[j], moHexSnake, m2);
|
||||
}
|
||||
}
|
||||
@ -4653,7 +4659,7 @@ void movemutant() {
|
||||
if(!c2) continue;
|
||||
|
||||
if(c2->monst != moMutant && canAttack(c, moMutant, c2, c2->monst, AF_ONLY_FBUG | AF_GETPLAYER)) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG | AF_GETPLAYER, moMutant);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG | AF_GETPLAYER, moMutant);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -4687,7 +4693,7 @@ void moveshadow() {
|
||||
if(c && c->monst == moShadow) {
|
||||
for(int j=0; j<c->type; j++)
|
||||
if(c->mov[j] && canAttack(c, moShadow, c->mov[j], c->mov[j]->monst, AF_ONLY_FBUG | AF_GETPLAYER))
|
||||
attackMonster(c->mov[j], AF_ORSTUN | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
attackMonster(c->mov[j], AF_NORMAL | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
c->monst = moNone;
|
||||
shfrom = c;
|
||||
}
|
||||
@ -4741,7 +4747,7 @@ void moveghosts() {
|
||||
if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, AF_GETPLAYER | AF_ONLY_FBUG)) {
|
||||
// XLATC ghost/greater shark
|
||||
|
||||
attackMonster(c->mov[j], AF_ORSTUN | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
attackMonster(c->mov[j], AF_NORMAL | AF_MSG | AF_GETPLAYER, c->monst);
|
||||
goto nextghost;
|
||||
}
|
||||
|
||||
@ -4800,7 +4806,7 @@ bool swordAttack(cell *mt, eMonster who, cell *c, int bb) {
|
||||
if(!peace::on && canAttack(mt, who, c, m, AF_SWORD)) {
|
||||
markOrb(bb ? itOrbSword2: itOrbSword);
|
||||
int k = tkills();
|
||||
attackMonster(c, AF_ORSTUN | AF_MSG | AF_SWORD, who);
|
||||
attackMonster(c, AF_NORMAL | AF_MSG | AF_SWORD, who);
|
||||
if(c->monst == moShadow) c->monst = moNone;
|
||||
produceGhost(c, m, who);
|
||||
if(tkills() > k) return true;
|
||||
@ -4827,7 +4833,7 @@ void sideAttack(cell *mf, int dir, eMonster who, int bonus, eItem orb) {
|
||||
if(canAttack(mf, who, mt, m, AF_SIDE)) {
|
||||
markOrb(orb);
|
||||
if(who != moPlayer) markOrb(itOrbEmpathy);
|
||||
if(attackMonster(mt, AF_ORSTUN | AF_SIDE | AF_MSG, who))
|
||||
if(attackMonster(mt, AF_NORMAL | AF_SIDE | AF_MSG, who))
|
||||
produceGhost(mt, m, who);
|
||||
}
|
||||
else if(mt->wall == waBigTree)
|
||||
@ -4890,7 +4896,7 @@ void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) {
|
||||
}
|
||||
eMonster m = c->monst;
|
||||
int k = tkills();
|
||||
if(attackMonster(c, AF_ORSTUN | AF_STAB | AF_MSG, who))
|
||||
if(attackMonster(c, AF_STAB | AF_MSG, who))
|
||||
produceGhost(c, m, who);
|
||||
if(tkills() > k) numsh++;
|
||||
}
|
||||
@ -5064,6 +5070,8 @@ int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
|
||||
#define STRONGWIND 99
|
||||
|
||||
void movegolems(flagtype flags) {
|
||||
if(items[itOrbEmpathy] && items[itOrbSlaying])
|
||||
flags |= AF_CRUSH;
|
||||
computePathdist(moMouse);
|
||||
int qg = 0;
|
||||
for(int i=0; i<size(golems); i++) {
|
||||
@ -5115,7 +5123,10 @@ void movegolems(flagtype flags) {
|
||||
playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince");
|
||||
addMessage(XLAT("%The1 takes %his1 revenge on %the2!", m, c2->monst));
|
||||
}
|
||||
attackMonster(c2, ((revenge||jealous)?0:AF_ORSTUN) | AF_MSG, m);
|
||||
if(revenge || jealous) flags |= AF_CRUSH;
|
||||
else if((flags & AF_CRUSH) && !canAttack(c, m, c2, c2->monst, flags ^ AF_CRUSH ^ AF_MUSTKILL))
|
||||
markOrb(itOrbEmpathy), markOrb(itOrbSlaying);
|
||||
attackMonster(c2, flags | AF_MSG, m);
|
||||
produceGhost(c2, m2, m);
|
||||
sideAttack(c, dir, m, 0);
|
||||
if(revenge) c->monst = m = moPrincessArmed;
|
||||
@ -5365,8 +5376,8 @@ void moverefresh(bool turn = true) {
|
||||
if(c2->monst != moPair) continue;
|
||||
if(!c2->stuntime) {
|
||||
cell *c3 = c->mov[(c->mondir + 1) % c->type];
|
||||
if(c3->wall == waColumn) {
|
||||
drawParticles(c3, 0xC00000, 30);
|
||||
if(among(c3->wall, waRuinWall, waColumn, waStone, waVinePlant)) {
|
||||
drawParticles(c3, winf[c3->wall].color, 30);
|
||||
c3->wall = waNone;
|
||||
}
|
||||
}
|
||||
@ -7020,7 +7031,7 @@ void monstersTurn() {
|
||||
|
||||
for(cell *c: crush_now)
|
||||
if(canAttack(c, moCrusher, c, c->monst, AF_GETPLAYER | AF_CRUSH))
|
||||
attackMonster(c, AF_ORSTUN | AF_MSG | AF_GETPLAYER | AF_CRUSH, moCrusher);
|
||||
attackMonster(c, AF_MSG | AF_GETPLAYER | AF_CRUSH, moCrusher);
|
||||
|
||||
crush_now = move(crush_next);
|
||||
crush_next.clear();
|
||||
@ -7144,7 +7155,7 @@ void killFriendlyIvy() {
|
||||
}
|
||||
|
||||
bool monsterPushable(cell *c2) {
|
||||
return (c2->monst != moFatGuard && !(isMetalBeast(c2->monst) && c2->stuntime < 2) && c2->monst != moTortoise && c2->monst != moTerraWarrior);
|
||||
return (c2->monst != moFatGuard && !(isMetalBeast(c2->monst) && c2->stuntime < 2) && c2->monst != moTortoise && c2->monst != moTerraWarrior && c2->monst != moVizier);
|
||||
}
|
||||
|
||||
bool movepcto(int d, int subdir, bool checkonly) {
|
||||
@ -7387,9 +7398,11 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst))
|
||||
&& !(peace::on && !isMultitile(c2->monst) && !goodTortoise)) {
|
||||
|
||||
bool fast = !((!items[itOrbSpeed]) || (items[itOrbSpeed]&1));
|
||||
flagtype attackflags = AF_NORMAL;
|
||||
if(items[itOrbSpeed]&1) attackflags |= AF_FAST;
|
||||
if(items[itOrbSlaying]) attackflags |= AF_CRUSH;
|
||||
|
||||
if(!canAttack(cwt.c, moPlayer, c2, c2->monst, fast ? AF_FAST : 0)) {
|
||||
if(!canAttack(cwt.c, moPlayer, c2, c2->monst, attackflags)) {
|
||||
if(checkonly) return false;
|
||||
if(c2->monst == moWorm || c2->monst == moWormtail || c2->monst == moWormwait)
|
||||
addMessage(XLAT("You cannot attack Sandworms directly!"));
|
||||
@ -7411,7 +7424,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
addMessage(XLAT("You cannot attack %the1 directly!", c2->monst));
|
||||
addMessage(XLAT("Make him hit himself by walking away from him."));
|
||||
}
|
||||
else if(c2->monst == moVizier && c2->hitpoints > 1 && !fast) {
|
||||
else if(c2->monst == moVizier && c2->hitpoints > 1 && !(attackflags & AF_FAST)) {
|
||||
addMessage(XLAT("You cannot attack %the1 directly!", c2->monst));
|
||||
addMessage(XLAT("Hit him by walking away from him."));
|
||||
}
|
||||
@ -7476,24 +7489,16 @@ bool movepcto(int d, int subdir, bool checkonly) {
|
||||
c2->stuntime = 2;
|
||||
achievement_collection(itBabyTortoise, 0, 0);
|
||||
}
|
||||
else if(isStunnable(c2->monst) && c2->hitpoints > 1) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, moPlayer);
|
||||
// salamanders are stunned for longer time when pushed into a wall
|
||||
if(c2->monst == moSalamander && (pushto == c2 || !pushto)) c2->stuntime = 10;
|
||||
if(pushto && pushto != c2) pushMonster(pushto, c2);
|
||||
}
|
||||
else if(c2->monst == moVizier && c2->hitpoints > 1) {
|
||||
fightmessage(c2->monst, moPlayer, true, 0);
|
||||
c2->hitpoints--;
|
||||
}
|
||||
else if(isDragon(c2->monst) || isKraken(c2->monst)) {
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, moPlayer);
|
||||
}
|
||||
else {
|
||||
eMonster m = c2->monst;
|
||||
if(m) {
|
||||
attackMonster(c2, AF_MSG, moPlayer);
|
||||
produceGhost(c2, m, moPlayer);
|
||||
if((attackflags & AF_CRUSH) && !canAttack(cwt.c, moPlayer, c2, c2->monst, attackflags ^ AF_CRUSH ^ AF_MUSTKILL))
|
||||
markOrb(itOrbSlaying);
|
||||
attackMonster(c2, attackflags | AF_MSG, moPlayer);
|
||||
// salamanders are stunned for longer time when pushed into a wall
|
||||
if(c2->monst == moSalamander && (pushto == c2 || !pushto)) c2->stuntime = 10;
|
||||
if(!c2->monst) produceGhost(c2, m, moPlayer);
|
||||
if(pushto && pushto != c2) pushMonster(pushto, c2);
|
||||
}
|
||||
}
|
||||
|
||||
|
59
graph.cpp
59
graph.cpp
@ -695,8 +695,9 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
|
||||
if(it == itOrbAir) icol = 0xFFFFFF;
|
||||
if(it == itOrbUndeath) icol = minf[moFriendlyGhost].color;
|
||||
if(it == itOrbRecall) icol = 0x101010;
|
||||
if(it == itOrbSlaying) icol = 0xFF0000;
|
||||
int col = darkena(icol, 0, int(0x80 + 0x70 * sin(ticks / 300.)));
|
||||
|
||||
|
||||
if(it == itOrbFish)
|
||||
queuepolyat(V * spin(ticks / 1500.), shFishTail, col, PPR_ITEM_BELOW);
|
||||
|
||||
@ -1219,12 +1220,52 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
|
||||
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF);
|
||||
queuepoly(VHEAD, shHood, darkena(col, 0, 0xFF));
|
||||
}
|
||||
else if(m == moPair || m == moAltDemon || m == moHexDemon || m == moMonk || m == moCrusher) {
|
||||
else if(m == moMonk) {
|
||||
otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
|
||||
ShadowV(V, shPBody);
|
||||
queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0));
|
||||
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF);
|
||||
queuepoly(VHEAD, shHood, darkena(col, 0, 0xFF));
|
||||
if(!peace::on) queuepoly(VBODY, shPKnife, 0xFFC0C0C0);
|
||||
queuepoly(VBODY, shTerraArmor1, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor2, darkena(col, 0, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor3, darkena(col, 1, 0xFF));
|
||||
queuepolyat(VBODY, shRatCape2, darkena(col, 2, 0xFF), PPR_MONSTER_ARMOR0);
|
||||
queuepoly(VHEAD, shRaiderHelmet, darkena(col, 0, 0XFF));
|
||||
queuepoly(VHEAD, shPFace, darkena(0xC0C0A0, 0, 0XFF));
|
||||
}
|
||||
else if(m == moCrusher) {
|
||||
otherbodyparts(V, darkena(col, 1, 0xFF), m, footphase);
|
||||
ShadowV(V, shPBody);
|
||||
queuepoly(VBODY, shPBody, darkena(col, 0, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor1, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor2, darkena(col, 0, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor3, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shFlailBall, darkena(col, 0, 0XFF));
|
||||
queuepoly(VBODY, shFlailChain, darkena(col, 1, 0XFF));
|
||||
queuepoly(VBODY, shFlailTrunk, darkena(col, 0, 0XFF));
|
||||
queuepoly(VHEAD, shRaiderHelmet, darkena(col, 0, 0XFF));
|
||||
queuepoly(VHEAD, shPFace, darkena(0xC0C0A0, 0, 0XFF));
|
||||
}
|
||||
else if(m == moPair) {
|
||||
otherbodyparts(V, darkena(col, 1, 0xFF), m, footphase);
|
||||
ShadowV(V, shPBody);
|
||||
queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0));
|
||||
queuepoly(VBODY, shTerraArmor1, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor2, darkena(col, 0, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor3, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shPickAxe, darkena(0xA0A0A0, 0, 0XFF));
|
||||
queuepoly(VHEAD, shRaiderHelmet, darkena(col, 0, 0XFF));
|
||||
queuepoly(VHEAD, shPFace, darkena(0xC0C0A0, 0, 0XFF));
|
||||
}
|
||||
else if(m == moAltDemon || m == moHexDemon) {
|
||||
otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
|
||||
ShadowV(V, shPBody);
|
||||
queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0));
|
||||
queuepoly(VBODY, shTerraArmor1, darkena(col, 1, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor2, darkena(col, 0, 0xFF));
|
||||
queuepoly(VBODY, shTerraArmor3, darkena(col, 1, 0xFF));
|
||||
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFD0D0D0);
|
||||
queuepoly(VHEAD, shRaiderHelmet, darkena(col, 0, 0XFF));
|
||||
queuepoly(VHEAD, shPFace, darkena(0xC0C0A0, 0, 0XFF));
|
||||
}
|
||||
else if(m == moPalace || m == moFatGuard || m == moVizier || m == moSkeleton) {
|
||||
queuepoly(VBODY, shSabre, 0xFFFFFFFF);
|
||||
@ -1412,8 +1453,8 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
|
||||
queuepoly(VHEAD, shWolf3, darkena(0x202020, 0, 0xFF));
|
||||
|
||||
if(m == moRatlingAvenger) {
|
||||
queuepoly(VBODY, shRatCape1, 0x303030FF);
|
||||
queuepoly(VHEAD, shRatCape2, 0x484848FF);
|
||||
queuepoly(VBODY, shRatCape2, 0x484848FF);
|
||||
queuepoly(VHEAD, shRatCape1, 0x303030FF);
|
||||
}
|
||||
}
|
||||
else if(m == moViking) {
|
||||
@ -1936,7 +1977,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) {
|
||||
// also whatever in the lineview mode
|
||||
|
||||
else if(isFriendly(c) || isBug(c) || (c->monst && conformal::on) || c->monst == moKrakenH || (isBull(c->monst) && c->mondir != NODIR) || c->monst == moButterfly || isMagneticPole(c->monst) ||
|
||||
isSwitch(c->monst) || c->monst == moPair) {
|
||||
isSwitch(c->monst)) {
|
||||
if(c->monst == moKrakenH) Vs = Vb, nospins = nospinb;
|
||||
if(!nospins) Vs = Vs * ddspin(c, c->mondir, S42);
|
||||
if(isFriendly(c)) drawPlayerEffects(Vs, c, false);
|
||||
@ -2486,6 +2527,10 @@ void setcolors(cell *c, int& wcol, int &fcol) {
|
||||
case laDragon: case laStorms: case laTerracotta: case laMercuryRiver:
|
||||
fcol = linf[c->land].color; break;
|
||||
|
||||
case laInvincible:
|
||||
fcol = pseudohept(c) ? 0xC0C0C0 : 0x40A040;
|
||||
break;
|
||||
|
||||
case laDual:
|
||||
fcol = linf[c->land].color;
|
||||
if(c->landparam == 2) fcol = 0x40FF00;
|
||||
|
6
hyper.h
6
hyper.h
@ -975,6 +975,8 @@ bool withRose(cell *cfrom, cell *cto);
|
||||
|
||||
// canAttack/moveval flags
|
||||
|
||||
#define AF_NORMAL 0 // nothing special about this attack
|
||||
|
||||
#define AF_TOUGH Flag(0) // tough attacks: Hyperbugs
|
||||
#define AF_MAGIC Flag(1) // magical attacks: Flash
|
||||
#define AF_STAB Flag(2) // stabbing attacks (usually ignored except Hedgehogs)
|
||||
@ -1000,7 +1002,7 @@ bool withRose(cell *cfrom, cell *cto);
|
||||
#define AF_SWORD Flag(20) // big sword
|
||||
#define AF_SWORD_INTO Flag(21) // moving into big sword
|
||||
#define AF_MSG Flag(22) // produce a message
|
||||
#define AF_ORSTUN Flag(23) // attackMonster: allow stunning
|
||||
#define AF_MUSTKILL Flag(23) // when TRUE, stunning attacks are not accepted by canAttack
|
||||
#define AF_NEXTTURN Flag(24) // next turn -- don't count shield at power 1
|
||||
#define AF_FALL Flag(25) // death by falling
|
||||
#define MF_STUNNED Flag(26) // edgeunstable: ignore ladders (as stunned monsters do)
|
||||
@ -1108,7 +1110,7 @@ namespace sword {
|
||||
}
|
||||
|
||||
void killThePlayer(eMonster m, int id, flagtype flags);
|
||||
bool attackJustStuns(cell *c2);
|
||||
bool attackJustStuns(cell *c2, flagtype flags);
|
||||
|
||||
bool isTargetOrAdjacent(cell *c);
|
||||
bool warningprotection();
|
||||
|
@ -331,7 +331,7 @@ namespace inv {
|
||||
gainOrbs(itGlowCrystal, itOrbSide2);
|
||||
gainOrbs(itSwitch, itOrbPhasing);
|
||||
gainOrbs(itMagnet, itOrbMagnetism);
|
||||
gainOrbs(itInvix, itOrbDestruction);
|
||||
gainOrbs(itInvix, itOrbSlaying);
|
||||
|
||||
if(items[itOrbLove] && !items[itSavedPrincess]) items[itSavedPrincess] = 1;
|
||||
|
||||
|
@ -114,7 +114,7 @@ const orbinfo orbinfos[ORBLINES] = {
|
||||
{orbgenflags::S_GUEST, laSwitch, 2000, 0, itOrbSpace},
|
||||
{orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing},
|
||||
{orbgenflags::S_NATIVE, laMagnetic, 2000, 3000, itOrbMagnetism},
|
||||
{orbgenflags::S_NATIVE, laInvincible, 2000, 3000, itOrbDestruction},
|
||||
{orbgenflags::S_NATIVE, laInvincible, 2000, 3000, itOrbSlaying},
|
||||
{orbgenflags::S_NATIVE, laWhirlpool, 0, 2000, itOrbWater}, // needs to be last
|
||||
};
|
||||
|
||||
|
6
orbs.cpp
6
orbs.cpp
@ -140,6 +140,7 @@ void reduceOrbPowers() {
|
||||
reduceOrbPower(itOrbHorns, 77);
|
||||
reduceOrbPower(itOrbLava, 80);
|
||||
reduceOrbPower(itOrbMorph, 80);
|
||||
reduceOrbPower(itOrbSlaying, 120);
|
||||
|
||||
reduceOrbPower(itOrbSide1, 120);
|
||||
reduceOrbPower(itOrbSide2, 120);
|
||||
@ -615,7 +616,7 @@ void jumpTo(cell *dest, eItem byWhat, int bonuskill = 0, eMonster dashmon = moNo
|
||||
|
||||
void growIvyTo(cell *dest, cell *src) {
|
||||
if(dest->monst)
|
||||
attackMonster(dest, AF_MSG | AF_ORSTUN, moFriendlyIvy);
|
||||
attackMonster(dest, AF_NORMAL | AF_MSG, moFriendlyIvy);
|
||||
else {
|
||||
dest->monst = moFriendlyIvy;
|
||||
dest->mondir = neighborId(dest, src);
|
||||
@ -1075,7 +1076,7 @@ eItem targetRangedOrb(cell *c, orbAction a) {
|
||||
if(!isCheck(a)) {
|
||||
int k = tkills();
|
||||
eMonster m = c2->monst;
|
||||
attackMonster(c2, AF_ORSTUN | AF_MSG, moPlayer);
|
||||
attackMonster(c2, AF_NORMAL | AF_MSG, moPlayer);
|
||||
k = tkills() - k;
|
||||
jumpTo(c, itOrbDash, k, m);
|
||||
}
|
||||
@ -1317,6 +1318,7 @@ int orbcharges(eItem it) {
|
||||
case itOrbBull:
|
||||
case itOrbShell:
|
||||
case itOrbAir:
|
||||
case itOrbSlaying:
|
||||
return 66;
|
||||
case itOrbTime:
|
||||
case itOrbSpace:
|
||||
|
@ -1008,7 +1008,7 @@ hpcshape
|
||||
shArrow,
|
||||
shPHead, shPFace, shGolemhead, shHood, shArmor,
|
||||
shAztecHead, shAztecCap,
|
||||
shSabre, shTurban1, shTurban2, shVikingHelmet,
|
||||
shSabre, shTurban1, shTurban2, shVikingHelmet, shRaiderHelmet,
|
||||
shWestHat1, shWestHat2, shGunInHand,
|
||||
shKnightArmor, shKnightCloak, shWightCloak,
|
||||
shGhost, shEyes, shSlime, shJoint, shWormHead, shTentHead, shShark,
|
||||
@ -2122,6 +2122,7 @@ void buildpolys() {
|
||||
bshape(shWestHat2, PPR_MONSTER_HAT1, scalef, 120);
|
||||
bshape(shGunInHand, PPR_MONSTER_WPN, scalef, 121);
|
||||
bshape(shVikingHelmet, PPR_MONSTER_HAT0, scalef, 122);
|
||||
bshape(shRaiderHelmet, PPR_MONSTER_HAT0, scalef, 375);
|
||||
bshape(shHood, PPR_MONSTER_HAT0, scalef, 123);
|
||||
bshape(shPirateHood, PPR_MONSTER_HAT0, scalef, 125);
|
||||
bshape(shEyepatch, PPR_MONSTER_HAT1, scalef, 126);
|
||||
@ -3425,6 +3426,9 @@ NEWSHAPE, 373, 1, 1, -0.019312,0.304743, -0.289045,0.177117, -0.127176,-0.240665
|
||||
|
||||
NEWSHAPE, 374, 1, 1, -0.229502,-0.051000, 0.320183,0.006447, 0.148302,0.144065, 0.173317,0.054954, -0.253447,0.021298,
|
||||
|
||||
NEWSHAPE, 375, 1, 2, -0.090497,-0.016548, -0.072731,-0.044408, -0.058869,-0.063422, -0.031762,-0.071442, -0.001140,-0.143435, 0.032854,-0.162181, 0.080022,-0.161459, 0.108605,-0.129676, 0.112564,-0.096396, 0.102658,-0.077590, 0.088332,-0.113771, 0.046216,-0.129074, 0.017935,-0.063369, 0.049033,-0.046641, 0.032200,-0.027430,
|
||||
|
||||
|
||||
NEWSHAPE
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user