1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2025-07-24 11:42:50 +00:00

Theming Ruins. Implemented Orb of Slaying (also cleaning up some kill/stun/Vizier code).

This commit is contained in:
Zeno Rogue 2018-01-03 21:49:14 +01:00
parent 86e760a562
commit a8460b1ac7
11 changed files with 151 additions and 87 deletions

View File

@ -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."}, "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', 0xC00000, "North Pole", NODESCYET},
{ 'B', 0x0000C0, "South Pole", NODESCYET}, { 'B', 0x0000C0, "South Pole", NODESCYET},
{ 'P', 0xC0D000, "Pair Demon", NODESCYET}, { 'P', 0xC03000, "Red Raider", NODESCYET},
{ 'H', 0x00C0D0, "Hex Demon", NODESCYET}, { 'H', 0xC0C0C0, "Gray Raider", NODESCYET},
{ 'A', 0xD000C0, "Alt Demon", NODESCYET}, { 'A', 0x80B080, "Green Raider", NODESCYET},
{ 'M', 0x904000, "Monk", NODESCYET}, { 'M', 0x904000, "Brown Raider", NODESCYET},
{ 'C', 0x004070, "Crusher", NODESCYET}, { 'C', 0x0060E0, "Blue Raider", NODESCYET},
{ '@', 0xC00000, "Switcher A", NODESCYET}, { '@', 0xC00000, "Switcher A", NODESCYET},
{ '@', 0x0000C0, "Switcher B", NODESCYET}, { '@', 0x0000C0, "Switcher B", NODESCYET},
@ -1213,12 +1213,13 @@ itemtype iinf[ittypes] = {
{ '!', 0x80FF00, "Glowing Crystal", crystaldesc}, { '!', 0x80FF00, "Glowing Crystal", crystaldesc},
{ '!', 0x80FF80, "Snake Oil", NODESCYET}, { '!', 0x80FF80, "Snake Oil", NODESCYET},
{ '*', 0x80FF80, "Sea Glass", NODESCYET}, { '*', 0x80FF80, "Sea Glass", NODESCYET},
{ '*', 0xFFFFFF, "Invix Treasure", NODESCYET}, { '*', 0xD0D8ED, "Chalcedony", NODESCYET},
{ '*', 0x80FF80, "Monopole", NODESCYET}, { '*', 0x80FF80, "Monopole", NODESCYET},
{ '*', 0xFFFF80, "Junk", NODESCYET}, { '*', 0xBBCC99, "Chrysoberyl", NODESCYET},
{ 'o', 0x80FF80, "Orb of Phasing", NODESCYET}, { 'o', 0x80FF80, "Orb of Phasing", NODESCYET},
{ 'o', 0xFFFF80, "Orb of Magnetism", 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 --- // --- wall types ---
@ -1398,6 +1399,7 @@ walltype winf[walltypes] = {
{ '&', 0xD00000, "lava", lavadesc}, { '&', 0xD00000, "lava", lavadesc},
{ '=', 0x804000, "dock", "A dock."}, { '=', 0x804000, "dock", "A dock."},
{ '^', 0xFF8000, "burning dock", "A burning dock."}, { '^', 0xFF8000, "burning dock", "A burning dock."},
{ '#', 0xE07070, "ruin wall", "A ruin wall."},
}; };
// --- land types --- // --- land types ---
@ -1585,7 +1587,7 @@ const landtype linf[landtypes] = {
{ 0x80FF00, "Crystal World", crystaldesc}, { 0x80FF00, "Crystal World", crystaldesc},
{ 0x306030, "Snake Nest", NODESCYET}, { 0x306030, "Snake Nest", NODESCYET},
{ 0x80FF00, "Docks", NODESCYET}, { 0x80FF00, "Docks", NODESCYET},
{ 0x306030, "Invincible", NODESCYET}, { 0x306030, "Ruined City", NODESCYET},
{ 0x306030, "Magnetosphere", NODESCYET}, { 0x306030, "Magnetosphere", NODESCYET},
{ 0x306030, "Switch", NODESCYET}, { 0x306030, "Switch", NODESCYET},
}; };

View File

@ -117,10 +117,10 @@ enum eItem {
itOrbSide1, itOrbSide2, itOrbSide3, itOrbSide1, itOrbSide2, itOrbSide3,
itOrbLava, itOrbMorph, itGlowCrystal, itSnake, itOrbLava, itOrbMorph, itGlowCrystal, itSnake,
itDock, itInvix, itMagnet, itSwitch, itDock, itInvix, itMagnet, itSwitch,
itOrbPhasing, itOrbMagnetism, itOrbDestruction itOrbPhasing, itOrbMagnetism, itOrbSlaying
}; };
static const int walltypes = 107; static const int walltypes = 108;
struct walltype { struct walltype {
char glyph; char glyph;
@ -161,7 +161,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waTempBridgeBlocked, waTempBridgeBlocked,
waTerraWarrior, waBubble, waTerraWarrior, waBubble,
waArrowTrap, waMercury, waMagma, waArrowTrap, waMercury, waMagma,
waDock, waBurningDock waDock, waBurningDock, waRuinWall
}; };
static const int landtypes = 83; static const int landtypes = 83;

View File

@ -1199,7 +1199,7 @@ namespace mirror {
c->monst = moMimic; c->monst = moMimic;
eMonster m2 = c2->monst; eMonster m2 = c2->monst;
if(!peace::on && canAttack(c,moMimic,c2,m2, 0)) { 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); if(!fwd) produceGhost(c2, m2, moMimic);
sideAttack(c, m.second.spin, m2, 0); sideAttack(c, m.second.spin, m2, 0);
} }
@ -1642,7 +1642,7 @@ namespace hive {
if(isBug(killed)) battlecount++; if(isBug(killed)) battlecount++;
else if(killed != moPlayer && !fightspam(c2)) else if(killed != moPlayer && !fightspam(c2))
addMessage(XLAT("%The1 fights with %the2!", c->monst, killed)); 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); // killMonster(c);
if(isBug(killed)) { if(isBug(killed)) {
c2->monst = moDeadBug, deadbug.push_back(c2); c2->monst = moDeadBug, deadbug.push_back(c2);
@ -2020,7 +2020,7 @@ namespace heat {
c->wparam++; c->wparam++;
if(c->wparam == 3) { if(c->wparam == 3) {
if(canAttack(c, moArrowTrap, c, c->monst, AF_GETPLAYER)) 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; if(c->wparam == 4) c->wparam = 0;
} }
@ -2589,7 +2589,7 @@ namespace kraken {
if(c->monst == moKrakenT && !c->stuntime) forCellEx(c2, c) { if(c->monst == moKrakenT && !c->stuntime) forCellEx(c2, c) {
bool dboat = false; bool dboat = false;
if(c2->monst && canAttack(c, moKrakenT, c2, c2->monst, AF_ONLY_FBUG)) { 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); sleep(c);
} }
else for(int i=0; i<numplayers(); i++) if(playerpos(i) == c2) { else for(int i=0; i<numplayers(); i++) if(playerpos(i) == c2) {
@ -2869,7 +2869,7 @@ namespace prairie {
cell *cn = whirlline[q+1]; cell *cn = whirlline[q+1];
if(cp->monst == moHerdBull && !cp->stuntime) { if(cp->monst == moHerdBull && !cp->stuntime) {
forCellEx(c2, cp) { 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(c2 != cn) flags |= AF_ONLY_FBUG;
if(canAttack(c, moHerdBull, c2, c2->monst, flags)) if(canAttack(c, moHerdBull, c2, c2->monst, flags))
attackMonster(c2, flags | AF_MSG, moHerdBull); attackMonster(c2, flags | AF_MSG, moHerdBull);

View File

@ -117,7 +117,8 @@ bool isMetalBeast(eMonster m) {
bool isStunnable(eMonster m) { bool isStunnable(eMonster m) {
return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) || return m == moPalace || m == moFatGuard || m == moSkeleton || isPrincess(m) ||
isMetalBeast(m) || m == moTortoise || isDragon(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) { bool hasHitpoints(eMonster m) {
@ -555,7 +556,8 @@ bool isOffensiveOrb(eItem it) {
return it == itOrbLightning || it == itOrbFlash || it == itOrbThorns || return it == itOrbLightning || it == itOrbFlash || it == itOrbThorns ||
it == itOrbDragon || it == itOrbStunning || it == itOrbDragon || it == itOrbStunning ||
it == itOrbFreedom || it == itOrbPsi || it == itOrbFreedom || it == itOrbPsi ||
it == itOrbSide1 || it == itOrbSide2 || it == itOrbSide3; it == itOrbSide1 || it == itOrbSide2 || it == itOrbSide3 ||
it == itOrbSlaying;
} }
bool isRangedOrb(eItem i) { bool isRangedOrb(eItem i) {
@ -575,7 +577,8 @@ bool isEmpathyOrb(eItem i) {
i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield || i == itOrbUndeath || i == itOrbSpeed || i == itOrbShield ||
i == itOrbAether || i == itOrbInvis || i == itOrbThorns || i == itOrbAether || i == itOrbInvis || i == itOrbThorns ||
i == itOrbWater || i == itOrbStone || i == itOrbWater || i == itOrbStone ||
i == itOrbSide1 || i == itOrbSide2 || i == itOrbSide3; i == itOrbSide1 || i == itOrbSide2 || i == itOrbSide3 ||
i == itOrbSlaying;
} }
bool isUtilityOrb(eItem i) { bool isUtilityOrb(eItem i) {
@ -720,8 +723,9 @@ bool hornStuns(cell *c) {
return return
m == moRagingBull || m == moSleepBull || m == moHerdBull || m == moRagingBull || m == moSleepBull || m == moHerdBull ||
m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr || m == moButterfly || m == moGreater || m == moGreaterM || m == moDraugr ||
m == moHedge || m == moFlailer || m == moVizier || m == moHedge || m == moFlailer || m == moVizier || m == moReptile || m == moSalamander ||
attackJustStuns(c); m == moPair || m == moAltDemon || m == moHexDemon || m == moMonk || m == moCrusher ||
attackJustStuns(c, AF_NORMAL);
} }
// generate all the world first in the quotient geometry // generate all the world first in the quotient geometry

105
game.cpp
View File

@ -928,6 +928,9 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) {
if(m2 == moPlayer && peace::on) return false; 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_FRIEND) && m2 != moPlayer && !isFriendly(c2)) return false;
if((flags & AF_ONLY_FBUG) && m2 != moPlayer && !isFriendlyOrBug(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; 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)) (m2 == moKrakenT || m2 == moKrakenH))
return false; 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(m2 == moHerdBull && !(flags & AF_MAGIC)) return false;
if(isBull(m2) && !(flags & (AF_MAGIC | AF_HORNS | AF_SWORD_INTO | AF_CRUSH))) 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 == moTortoise && !(flags & AF_MAGIC)) return false;
if(m2 == moRoseBeauty) 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(!isMimic(m1))
if(!checkOrb(m1, itOrbBeauty) && !checkOrb(m1, itOrbAether) && !checkOrb(m1, itOrbShield)) if(!checkOrb(m1, itOrbBeauty) && !checkOrb(m1, itOrbAether) && !checkOrb(m1, itOrbShield))
if(!c1 || !c2 || !withRose(c1,c2)) 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(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(!(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; if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_FAST | AF_BULL | AF_CRUSH))) return false;
return true; return true;
@ -1800,7 +1803,7 @@ void stunMonster(cell *c2) {
(c2->monst == moGreater || c2->monst == moGreaterM) ? 5 : (c2->monst == moGreater || c2->monst == moGreaterM) ? 5 :
c2->monst == moButterfly ? 2 : c2->monst == moButterfly ? 2 :
c2->monst == moDraugr ? 1 : c2->monst == moDraugr ? 1 :
c2->monst == moVizier ? 1 : c2->monst == moVizier ? 0 :
c2->monst == moHedge ? 1 : c2->monst == moHedge ? 1 :
c2->monst == moFlailer ? 1 : c2->monst == moFlailer ? 1 :
c2->monst == moSalamander ? 6 : c2->monst == moSalamander ? 6 :
@ -1816,7 +1819,14 @@ void stunMonster(cell *c2) {
checkStunKill(c2); checkStunKill(c2);
} }
bool attackJustStuns(cell *c2) { 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; return isStunnable(c2->monst) && c2->hitpoints > 1;
} }
@ -2306,17 +2316,13 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) {
int tkt = killtypes(); 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) { if((flags & AF_BULL) && c->monst == moVizier && c->hitpoints > 1) {
dostun = true; dostun = true;
c->stuntime = 2; c->stuntime = 2;
} }
if(c->monst == moSkeleton && (flags & AF_SWORD)) dostun = false;
if(c->monst == moSkeleton && killer == moCrusher) dostun = false;
bool eu = elementalUnlocked(); bool eu = elementalUnlocked();
bool tu = trollUnlocked(); bool tu = trollUnlocked();
@ -3400,7 +3406,7 @@ void moveMonster(cell *ct, cell *cf) {
for(int u=2; u<=ct->type-2; u++) { for(int u=2; u<=ct->type-2; u++) {
cell *c3 = ct->mov[(ct->mondir+u)%ct->type]; cell *c3 = ct->mov[(ct->mondir+u)%ct->type];
if(canAttack(ct, moLancer, c3, c3->monst, AF_LANCE | AF_GETPLAYER)) { 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); fallMonster(ct);
} }
if(sword::at(ct) && canAttack(NULL, moPlayer, ct, m, AF_SWORD_INTO)) { 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"); achievement_gain("GOSWORD");
} }
} }
@ -3819,7 +3825,7 @@ void beastAttack(cell *c, bool player) {
if(c->mondir == NODIR) return; if(c->mondir == NODIR) return;
forCellIdEx(c2, d, c) { forCellIdEx(c2, d, c) {
bool opposite = angledist(c, d, c->mondir) >= 3; bool opposite = angledist(c, d, c->mondir) >= 3;
int flags = AF_BULL | AF_ORSTUN; int flags = AF_BULL;
if(player) flags |= AF_GETPLAYER; if(player) flags |= AF_GETPLAYER;
if(!opposite) flags |= AF_ONLY_FBUG; if(!opposite) flags |= AF_ONLY_FBUG;
if(canAttack(c, moRagingBull, c2, c2->monst, flags)) { if(canAttack(c, moRagingBull, c2, c2->monst, flags)) {
@ -3889,7 +3895,7 @@ cell *moveNormal(cell *c, flagtype mf) {
return c2; return c2;
} }
else if(m2) { else if(m2) {
attackMonster(c2, AF_ORSTUN | AF_MSG, m); attackMonster(c2, AF_NORMAL | AF_MSG, m);
if(m == moFlailer && m2 == moIllusion) if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2); attackMonster(c, 0, m2);
return c2; return c2;
@ -3912,7 +3918,7 @@ cell *moveNormal(cell *c, flagtype mf) {
else { else {
eMonster m2 = c2->monst; eMonster m2 = c2->monst;
if(m2) { if(m2) {
attackMonster(c2, AF_ORSTUN | AF_MSG, m); attackMonster(c2, AF_NORMAL | AF_MSG, m);
if(m == moFlailer && m2 == moIllusion) if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2); attackMonster(c, 0, m2);
attacking = true; attacking = true;
@ -4007,7 +4013,7 @@ void killThePlayer(eMonster m, int id, flagtype flags) {
} }
else if(items[itOrbDomination] && playerpos(id)->monst) { else if(items[itOrbDomination] && playerpos(id)->monst) {
addMessage(XLAT("%The1 tries to dismount you!", m)); 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); useupOrb(itOrbDomination, items[itOrbDomination]/2);
} }
else if(items[itOrbShell] && !(flags & AF_EAT)) { else if(items[itOrbShell] && !(flags & AF_EAT)) {
@ -4080,7 +4086,7 @@ void moveWorm(cell *c) {
// explodeAround(c); // explodeAround(c);
forCellEx(c2, c) forCellEx(c2, c)
if(canAttack(c, c->monst, c2, c2->monst, mounted ? AF_ONLY_ENEMY : (AF_GETPLAYER | AF_ONLY_FBUG))) { 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; cell *c2 = c;
vector<cell*> allcells; vector<cell*> allcells;
@ -4277,13 +4283,13 @@ void moveivy() {
if(isPlayerOn(c->mov[j])) if(isPlayerOn(c->mov[j]))
killThePlayerAt(c->monst, c->mov[j], 0); killThePlayerAt(c->monst, c->mov[j], 0);
else { else {
if(attackJustStuns(c->mov[j])) if(attackJustStuns(c->mov[j], 0))
addMessage(XLAT("The ivy attacks %the1!", c->mov[j]->monst)); addMessage(XLAT("The ivy attacks %the1!", c->mov[j]->monst));
else if(isNonliving(c->mov[j]->monst)) else if(isNonliving(c->mov[j]->monst))
addMessage(XLAT("The ivy destroys %the1!", c->mov[j]->monst)); addMessage(XLAT("The ivy destroys %the1!", c->mov[j]->monst));
else else
addMessage(XLAT("The ivy kills %the1!", c->mov[j]->monst)); 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; continue;
} }
@ -4413,7 +4419,7 @@ void groupmove2(cell *c, cell *from, int d, eMonster movtype, flagtype mf) {
// note: move from 'c' to 'from'! // note: move from 'c' to 'from'!
if(!(mf & MF_NOATTACKS)) for(int j=0; j<c->type; j++) 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)) { 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; c->aitmp = sval;
// XLATC eagle // XLATC eagle
return; 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, if(c->mov[j] && canAttack(c, moHexSnake, c->mov[j], c->mov[j]->monst,
mounted ? AF_ONLY_ENEMY : (AF_ONLY_FBUG | AF_GETPLAYER))) { mounted ? AF_ONLY_ENEMY : (AF_ONLY_FBUG | AF_GETPLAYER))) {
eMonster m2 = c->mov[j]->monst; 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); produceGhost(c->mov[j], moHexSnake, m2);
} }
} }
@ -4653,7 +4659,7 @@ void movemutant() {
if(!c2) continue; if(!c2) continue;
if(c2->monst != moMutant && canAttack(c, moMutant, c2, c2->monst, AF_ONLY_FBUG | AF_GETPLAYER)) { 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; continue;
} }
@ -4687,7 +4693,7 @@ void moveshadow() {
if(c && c->monst == moShadow) { if(c && c->monst == moShadow) {
for(int j=0; j<c->type; j++) 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)) 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; c->monst = moNone;
shfrom = c; 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)) { if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, AF_GETPLAYER | AF_ONLY_FBUG)) {
// XLATC ghost/greater shark // 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; 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)) { if(!peace::on && canAttack(mt, who, c, m, AF_SWORD)) {
markOrb(bb ? itOrbSword2: itOrbSword); markOrb(bb ? itOrbSword2: itOrbSword);
int k = tkills(); 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; if(c->monst == moShadow) c->monst = moNone;
produceGhost(c, m, who); produceGhost(c, m, who);
if(tkills() > k) return true; 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)) { if(canAttack(mf, who, mt, m, AF_SIDE)) {
markOrb(orb); markOrb(orb);
if(who != moPlayer) markOrb(itOrbEmpathy); 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); produceGhost(mt, m, who);
} }
else if(mt->wall == waBigTree) else if(mt->wall == waBigTree)
@ -4890,7 +4896,7 @@ void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) {
} }
eMonster m = c->monst; eMonster m = c->monst;
int k = tkills(); 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); produceGhost(c, m, who);
if(tkills() > k) numsh++; if(tkills() > k) numsh++;
} }
@ -5064,6 +5070,8 @@ int movevalue(eMonster m, cell *c, cell *c2, flagtype flags) {
#define STRONGWIND 99 #define STRONGWIND 99
void movegolems(flagtype flags) { void movegolems(flagtype flags) {
if(items[itOrbEmpathy] && items[itOrbSlaying])
flags |= AF_CRUSH;
computePathdist(moMouse); computePathdist(moMouse);
int qg = 0; int qg = 0;
for(int i=0; i<size(golems); i++) { for(int i=0; i<size(golems); i++) {
@ -5115,7 +5123,10 @@ void movegolems(flagtype flags) {
playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince"); playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince");
addMessage(XLAT("%The1 takes %his1 revenge on %the2!", m, c2->monst)); 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); produceGhost(c2, m2, m);
sideAttack(c, dir, m, 0); sideAttack(c, dir, m, 0);
if(revenge) c->monst = m = moPrincessArmed; if(revenge) c->monst = m = moPrincessArmed;
@ -5365,8 +5376,8 @@ void moverefresh(bool turn = true) {
if(c2->monst != moPair) continue; if(c2->monst != moPair) continue;
if(!c2->stuntime) { if(!c2->stuntime) {
cell *c3 = c->mov[(c->mondir + 1) % c->type]; cell *c3 = c->mov[(c->mondir + 1) % c->type];
if(c3->wall == waColumn) { if(among(c3->wall, waRuinWall, waColumn, waStone, waVinePlant)) {
drawParticles(c3, 0xC00000, 30); drawParticles(c3, winf[c3->wall].color, 30);
c3->wall = waNone; c3->wall = waNone;
} }
} }
@ -7020,7 +7031,7 @@ void monstersTurn() {
for(cell *c: crush_now) for(cell *c: crush_now)
if(canAttack(c, moCrusher, c, c->monst, AF_GETPLAYER | AF_CRUSH)) 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_now = move(crush_next);
crush_next.clear(); crush_next.clear();
@ -7144,7 +7155,7 @@ void killFriendlyIvy() {
} }
bool monsterPushable(cell *c2) { 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) { 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)) else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst))
&& !(peace::on && !isMultitile(c2->monst) && !goodTortoise)) { && !(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(checkonly) return false;
if(c2->monst == moWorm || c2->monst == moWormtail || c2->monst == moWormwait) if(c2->monst == moWorm || c2->monst == moWormtail || c2->monst == moWormwait)
addMessage(XLAT("You cannot attack Sandworms directly!")); 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("You cannot attack %the1 directly!", c2->monst));
addMessage(XLAT("Make him hit himself by walking away from him.")); 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("You cannot attack %the1 directly!", c2->monst));
addMessage(XLAT("Hit him by walking away from him.")); addMessage(XLAT("Hit him by walking away from him."));
} }
@ -7476,24 +7489,16 @@ bool movepcto(int d, int subdir, bool checkonly) {
c2->stuntime = 2; c2->stuntime = 2;
achievement_collection(itBabyTortoise, 0, 0); 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 { else {
eMonster m = c2->monst; eMonster m = c2->monst;
if(m) { if(m) {
attackMonster(c2, AF_MSG, moPlayer); if((attackflags & AF_CRUSH) && !canAttack(cwt.c, moPlayer, c2, c2->monst, attackflags ^ AF_CRUSH ^ AF_MUSTKILL))
produceGhost(c2, m, moPlayer); 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);
} }
} }

View File

@ -695,6 +695,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
if(it == itOrbAir) icol = 0xFFFFFF; if(it == itOrbAir) icol = 0xFFFFFF;
if(it == itOrbUndeath) icol = minf[moFriendlyGhost].color; if(it == itOrbUndeath) icol = minf[moFriendlyGhost].color;
if(it == itOrbRecall) icol = 0x101010; if(it == itOrbRecall) icol = 0x101010;
if(it == itOrbSlaying) icol = 0xFF0000;
int col = darkena(icol, 0, int(0x80 + 0x70 * sin(ticks / 300.))); int col = darkena(icol, 0, int(0x80 + 0x70 * sin(ticks / 300.)));
if(it == itOrbFish) if(it == itOrbFish)
@ -1219,12 +1220,52 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF); if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF);
queuepoly(VHEAD, shHood, darkena(col, 0, 0xFF)); 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); otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
ShadowV(V, shPBody); ShadowV(V, shPBody);
queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0)); queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0));
if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF); if(!peace::on) queuepoly(VBODY, shPKnife, 0xFFC0C0C0);
queuepoly(VHEAD, shHood, 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));
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) { else if(m == moPalace || m == moFatGuard || m == moVizier || m == moSkeleton) {
queuepoly(VBODY, shSabre, 0xFFFFFFFF); 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)); queuepoly(VHEAD, shWolf3, darkena(0x202020, 0, 0xFF));
if(m == moRatlingAvenger) { if(m == moRatlingAvenger) {
queuepoly(VBODY, shRatCape1, 0x303030FF); queuepoly(VBODY, shRatCape2, 0x484848FF);
queuepoly(VHEAD, shRatCape2, 0x484848FF); queuepoly(VHEAD, shRatCape1, 0x303030FF);
} }
} }
else if(m == moViking) { 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 // 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) || 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(c->monst == moKrakenH) Vs = Vb, nospins = nospinb;
if(!nospins) Vs = Vs * ddspin(c, c->mondir, S42); if(!nospins) Vs = Vs * ddspin(c, c->mondir, S42);
if(isFriendly(c)) drawPlayerEffects(Vs, c, false); 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: case laDragon: case laStorms: case laTerracotta: case laMercuryRiver:
fcol = linf[c->land].color; break; fcol = linf[c->land].color; break;
case laInvincible:
fcol = pseudohept(c) ? 0xC0C0C0 : 0x40A040;
break;
case laDual: case laDual:
fcol = linf[c->land].color; fcol = linf[c->land].color;
if(c->landparam == 2) fcol = 0x40FF00; if(c->landparam == 2) fcol = 0x40FF00;

View File

@ -975,6 +975,8 @@ bool withRose(cell *cfrom, cell *cto);
// canAttack/moveval flags // canAttack/moveval flags
#define AF_NORMAL 0 // nothing special about this attack
#define AF_TOUGH Flag(0) // tough attacks: Hyperbugs #define AF_TOUGH Flag(0) // tough attacks: Hyperbugs
#define AF_MAGIC Flag(1) // magical attacks: Flash #define AF_MAGIC Flag(1) // magical attacks: Flash
#define AF_STAB Flag(2) // stabbing attacks (usually ignored except Hedgehogs) #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 Flag(20) // big sword
#define AF_SWORD_INTO Flag(21) // moving into big sword #define AF_SWORD_INTO Flag(21) // moving into big sword
#define AF_MSG Flag(22) // produce a message #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_NEXTTURN Flag(24) // next turn -- don't count shield at power 1
#define AF_FALL Flag(25) // death by falling #define AF_FALL Flag(25) // death by falling
#define MF_STUNNED Flag(26) // edgeunstable: ignore ladders (as stunned monsters do) #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); void killThePlayer(eMonster m, int id, flagtype flags);
bool attackJustStuns(cell *c2); bool attackJustStuns(cell *c2, flagtype flags);
bool isTargetOrAdjacent(cell *c); bool isTargetOrAdjacent(cell *c);
bool warningprotection(); bool warningprotection();

View File

@ -331,7 +331,7 @@ namespace inv {
gainOrbs(itGlowCrystal, itOrbSide2); gainOrbs(itGlowCrystal, itOrbSide2);
gainOrbs(itSwitch, itOrbPhasing); gainOrbs(itSwitch, itOrbPhasing);
gainOrbs(itMagnet, itOrbMagnetism); gainOrbs(itMagnet, itOrbMagnetism);
gainOrbs(itInvix, itOrbDestruction); gainOrbs(itInvix, itOrbSlaying);
if(items[itOrbLove] && !items[itSavedPrincess]) items[itSavedPrincess] = 1; if(items[itOrbLove] && !items[itSavedPrincess]) items[itSavedPrincess] = 1;

View File

@ -114,7 +114,7 @@ const orbinfo orbinfos[ORBLINES] = {
{orbgenflags::S_GUEST, laSwitch, 2000, 0, itOrbSpace}, {orbgenflags::S_GUEST, laSwitch, 2000, 0, itOrbSpace},
{orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing}, {orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing},
{orbgenflags::S_NATIVE, laMagnetic, 2000, 3000, itOrbMagnetism}, {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 {orbgenflags::S_NATIVE, laWhirlpool, 0, 2000, itOrbWater}, // needs to be last
}; };

View File

@ -140,6 +140,7 @@ void reduceOrbPowers() {
reduceOrbPower(itOrbHorns, 77); reduceOrbPower(itOrbHorns, 77);
reduceOrbPower(itOrbLava, 80); reduceOrbPower(itOrbLava, 80);
reduceOrbPower(itOrbMorph, 80); reduceOrbPower(itOrbMorph, 80);
reduceOrbPower(itOrbSlaying, 120);
reduceOrbPower(itOrbSide1, 120); reduceOrbPower(itOrbSide1, 120);
reduceOrbPower(itOrbSide2, 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) { void growIvyTo(cell *dest, cell *src) {
if(dest->monst) if(dest->monst)
attackMonster(dest, AF_MSG | AF_ORSTUN, moFriendlyIvy); attackMonster(dest, AF_NORMAL | AF_MSG, moFriendlyIvy);
else { else {
dest->monst = moFriendlyIvy; dest->monst = moFriendlyIvy;
dest->mondir = neighborId(dest, src); dest->mondir = neighborId(dest, src);
@ -1075,7 +1076,7 @@ eItem targetRangedOrb(cell *c, orbAction a) {
if(!isCheck(a)) { if(!isCheck(a)) {
int k = tkills(); int k = tkills();
eMonster m = c2->monst; eMonster m = c2->monst;
attackMonster(c2, AF_ORSTUN | AF_MSG, moPlayer); attackMonster(c2, AF_NORMAL | AF_MSG, moPlayer);
k = tkills() - k; k = tkills() - k;
jumpTo(c, itOrbDash, k, m); jumpTo(c, itOrbDash, k, m);
} }
@ -1317,6 +1318,7 @@ int orbcharges(eItem it) {
case itOrbBull: case itOrbBull:
case itOrbShell: case itOrbShell:
case itOrbAir: case itOrbAir:
case itOrbSlaying:
return 66; return 66;
case itOrbTime: case itOrbTime:
case itOrbSpace: case itOrbSpace:

View File

@ -1008,7 +1008,7 @@ hpcshape
shArrow, shArrow,
shPHead, shPFace, shGolemhead, shHood, shArmor, shPHead, shPFace, shGolemhead, shHood, shArmor,
shAztecHead, shAztecCap, shAztecHead, shAztecCap,
shSabre, shTurban1, shTurban2, shVikingHelmet, shSabre, shTurban1, shTurban2, shVikingHelmet, shRaiderHelmet,
shWestHat1, shWestHat2, shGunInHand, shWestHat1, shWestHat2, shGunInHand,
shKnightArmor, shKnightCloak, shWightCloak, shKnightArmor, shKnightCloak, shWightCloak,
shGhost, shEyes, shSlime, shJoint, shWormHead, shTentHead, shShark, shGhost, shEyes, shSlime, shJoint, shWormHead, shTentHead, shShark,
@ -2122,6 +2122,7 @@ void buildpolys() {
bshape(shWestHat2, PPR_MONSTER_HAT1, scalef, 120); bshape(shWestHat2, PPR_MONSTER_HAT1, scalef, 120);
bshape(shGunInHand, PPR_MONSTER_WPN, scalef, 121); bshape(shGunInHand, PPR_MONSTER_WPN, scalef, 121);
bshape(shVikingHelmet, PPR_MONSTER_HAT0, scalef, 122); bshape(shVikingHelmet, PPR_MONSTER_HAT0, scalef, 122);
bshape(shRaiderHelmet, PPR_MONSTER_HAT0, scalef, 375);
bshape(shHood, PPR_MONSTER_HAT0, scalef, 123); bshape(shHood, PPR_MONSTER_HAT0, scalef, 123);
bshape(shPirateHood, PPR_MONSTER_HAT0, scalef, 125); bshape(shPirateHood, PPR_MONSTER_HAT0, scalef, 125);
bshape(shEyepatch, PPR_MONSTER_HAT1, scalef, 126); 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, 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 NEWSHAPE
}; };