1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 17:10:36 +00:00

new lands for 10.1 -- initial commit

This commit is contained in:
Zeno Rogue 2017-09-30 11:46:41 +02:00
parent 14e4fe9a60
commit fe34a4a555
10 changed files with 793 additions and 193 deletions

View File

@ -346,7 +346,7 @@ const char *mirroreddesc =
"Mirror walls reflect Mimics, lightning bolts, and " "Mirror walls reflect Mimics, lightning bolts, and "
"missiles perfectly."; "missiles perfectly.";
const int motypes = 141; const int motypes = 150;
struct monstertype { struct monstertype {
char glyph; char glyph;
@ -696,6 +696,14 @@ monstertype minf[motypes] = {
"If you attack a Mirror Spirit physically, it is delayed, but not destroyed -- " "If you attack a Mirror Spirit physically, it is delayed, but not destroyed -- "
"more reflections will come out of the mirror. Use Mimics to destroy them." "more reflections will come out of the mirror. Use Mimics to destroy them."
}, },
{ 'W', 0x202020, "Hunting Dog", NODESC},
{ 'T', 0xA0A0A0, "Terracotta Warrior", NODESC},
{ 'H', 0xA0A0A0, "Mercury Warrior", NODESC},
{ 'B', 0xA00000, "Void Beast", NODESC},
{ 'L', 0xA00000, "Lemur", NODESC},
{ 'W', 0x202020, "Hunting Dog (guarding)", NODESC},
{ 'G', 0xC0C0FF, "Ice Golem", NODESC},
{ 'B', 0xC0C0FF, "Sand Bird", NODESC},
// shmup specials // shmup specials
{ '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."}, { '@', 0xC0C0C0, "Rogue", "In the Shoot'em Up mode, you are armed with thrown Knives."},
@ -706,10 +714,11 @@ monstertype minf[motypes] = {
{ '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."}, { '*', 0xFFFFFF, "Airball", "This magical missile pushes back whatever it hits."},
// technical // technical
{ '?', 0x00C000, "dead bug", NODESC}, { '?', 0x00C000, "dead bug", NODESC},
{ '?', 0xFFFF00, "electric discharge", NODESC}, // appears as 'killed by electrocution' { '?', 0xFFFF00, "electric discharge", NODESC}, // appears as 'killed by electric discharge'
{ '?', 0xE06000, "dead bird", NODESC}, { '?', 0xE06000, "dead bird", NODESC},
{ '?', 0xE06000, "Energy Sword", NODESC}, { '?', 0xE06000, "Energy Sword", NODESC},
{ '!', 0xFF0000, "Warning", warningdesc}, { '!', 0xFF0000, "Warning", warningdesc},
{ '!', 0xFF0000, "arrow trap", NODESC},
{ '*', 0, "vertex", "A vertex from rogueviz."} { '*', 0, "vertex", "A vertex from rogueviz."}
}; };
@ -756,10 +765,12 @@ enum eMonster {
moVampire, moBat, moReptile, moVampire, moBat, moReptile,
moHerdBull, moRagingBull, moSleepBull, moHerdBull, moRagingBull, moSleepBull,
moButterfly, moNarciss, moMirrorSpirit, moButterfly, moNarciss, moMirrorSpirit,
moHunterDog, moTerraWarrior, moMercuryGuy, moVoidBeast, moLemur, moHunterGuard,
moIceGolem, moSandBird,
// shmup specials // shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball, moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary // temporary
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning, moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning, moArrowTrap,
moRogueviz moRogueviz
}; };
@ -790,7 +801,7 @@ genderswitch_t genderswitch[NUM_GS] = {
// --- items --- // --- items ---
const int ittypes = 112; const int ittypes = 119;
struct itemtype { struct itemtype {
char glyph; char glyph;
@ -1183,6 +1194,13 @@ itemtype iinf[ittypes] = {
}, },
{ 'O', 0xF0F0F0, "your orbs", { 'O', 0xF0F0F0, "your orbs",
"Click this to see your orbs."}, "Click this to see your orbs."},
{ '$', 0xD0D000, "Sage's Stone", NODESCYET},
{ '*', 0x40E0D0, "Turquoise", NODESCYET},
{ '*', 0x009090, "Forgotten Relic", NODESCYET},
{ '*', 0x009090, "Warstone", NODESCYET},
{ 'o', 0x307080, "Orb of the Side I", NODESCYET},
{ 'o', 0x30A080, "Orb of the Side II", NODESCYET},
{ 'o', 0x30D080, "Orb of the Side III", NODESCYET},
}; };
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue, enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
@ -1216,12 +1234,14 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
itTrollEgg, itWarning, itOrbStone, itOrbNature, itTreat, itTrollEgg, itWarning, itOrbStone, itOrbNature, itTreat,
itSlime, itAmethyst, itOrbRecall, itDodeca, itOrbDash, itGreenGrass, itOrbHorns, itSlime, itAmethyst, itOrbRecall, itDodeca, itOrbDash, itGreenGrass, itOrbHorns,
itOrbBull, itBull, itOrbMirror, itOrbBull, itBull, itOrbMirror,
itInventory itInventory,
itAlchemy2, itDogPlains, itBlizzard, itTerra,
itOrbSide1, itOrbSide2, itOrbSide3
}; };
// --- wall types --- // --- wall types ---
const int walltypes = 100; const int walltypes = 103;
struct walltype { struct walltype {
char glyph; char glyph;
@ -1372,8 +1392,8 @@ walltype winf[walltypes] = {
{ '?', 0xFF00FF, "<earth d", NODESC}, { '?', 0xFF00FF, "<earth d", NODESC},
{ '?', 0xFF00FF, "<elemental tmp>", NODESC}, { '?', 0xFF00FF, "<elemental tmp>", NODESC},
{ '?', 0xFF00FF, "<elemental d>", NODESC}, { '?', 0xFF00FF, "<elemental d>", NODESC},
{ '+', 0x607030, "unnamed floor C", NODESC}, { '+', 0x00F000, "green slime", NODESC},
{ '+', 0xC0C0FF, "unnamed floor D", NODESC}, { '+', 0xF0F000, "yellow slime", NODESC},
{ '#', 0x764e7c, "rosebush", roselanddesc}, { '#', 0x764e7c, "rosebush", roselanddesc},
{ '#', 0xC0C000, "warp gate", { '#', 0xC0C000, "warp gate",
"This gate separates the warped area from the normal land."}, "This gate separates the warped area from the normal land."},
@ -1404,6 +1424,9 @@ walltype winf[walltypes] = {
{ '#', 0xC0C0FF, "mirror wall", mirroreddesc}, { '#', 0xC0C0FF, "mirror wall", mirroreddesc},
{ '.', 0xE0E0E0, "stepping stones", "A petrified creature."}, { '.', 0xE0E0E0, "stepping stones", "A petrified creature."},
{ '#', 0x309060, "temporary wall", twdesc}, { '#', 0x309060, "temporary wall", twdesc},
{ 'S', 0xB0B0B0, "warrior statue", NODESCYET},
{ '=', 0xB0B0B0, "bubbling slime", NODESCYET},
{ '^', 0xD00000, "arrow trap", NODESCYET},
}; };
enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune, enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune,
@ -1426,7 +1449,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waCharged, waGrounded, waSandstone, waSaloon, waMetal, waCharged, waGrounded, waSandstone, waSaloon, waMetal,
waDeadTroll2, waFan, waDeadTroll2, waFan,
waTemporary, waEarthD, waElementalTmp, waElementalD, waTemporary, waEarthD, waElementalTmp, waElementalD,
waFloorC, waFloorD, waRose, waWarpGate, waSlime1, waSlime2, waRose, waWarpGate,
waTrunk, waSolidBranch, waWeakBranch, waCanopy, waTrunk, waSolidBranch, waWeakBranch, waCanopy,
waBarrowWall, waBarrowDig, waBarrowWall, waBarrowDig,
waPetrified, waTower, waPetrified, waTower,
@ -1435,12 +1458,14 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waInvisibleFloor, waInvisibleFloor,
waMirrorWall, waMirrorWall,
waPetrifiedBridge, waPetrifiedBridge,
waTempBridgeBlocked waTempBridgeBlocked,
waTerraWarrior, waBubble,
waArrowTrap
}; };
// --- land types --- // --- land types ---
const int landtypes = 73; const int landtypes = 76;
struct landtype { struct landtype {
int color; int color;
@ -1623,7 +1648,10 @@ const landtype linf[landtypes] = {
{ 0xC8C8FF, "Reflection", mirroreddesc}, { 0xC8C8FF, "Reflection", mirroreddesc},
{ 0xC8C8FF, "Mirror Land", { 0xC8C8FF, "Mirror Land",
"A strange land which contains mirrors and mirages, protected by Mirror Rangers."}, "A strange land which contains mirrors and mirages, protected by Mirror Rangers."},
{ 0xFFFFFF, "Alchemy II", NODESCYET} { 0xA06000, "Alchemy II", NODESCYET},
{ 0x8080FF, "Blizzard", NODESCYET},
{ 0x207068, "Hunting Ground", NODESCYET},
{ 0x888888, "Terracotta Army", NODESCYET}
}; };
enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard, enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard,
@ -1643,7 +1671,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laPrairie, laBull, laCrossroads5, laCA, laPrairie, laBull, laCrossroads5, laCA,
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2, laMirrorWall, laMirrored, laMirrorWall2, laMirrored2,
laMirrorOld, laMirrorOld,
laAlchemy2 laAlchemy2, laBlizzard, laDogPlains, laTerracotta
}; };
// cell information for the game // cell information for the game

View File

@ -1195,8 +1195,12 @@ namespace mirror {
cell *c2 = cw2.c; cell *c2 = cw2.c;
if(c2->monst) { if(c2->monst) {
c->monst = moMimic; c->monst = moMimic;
if(!peace::on && canAttack(c,moMimic,c2,c2->monst, 0)) eMonster m2 = c2->monst;
if(!peace::on && canAttack(c,moMimic,c2,m2, 0)) {
attackMonster(c2, AF_MSG | AF_ORSTUN, moMimic); attackMonster(c2, AF_MSG | AF_ORSTUN, moMimic);
if(!fwd) produceGhost(c2, m2, moMimic);
sideAttack(c, m.second.spin, m2, 0);
}
c->monst = moNone; c->monst = moNone;
} }
if(c2->wall == waBigTree) if(c2->wall == waBigTree)
@ -1758,9 +1762,13 @@ inline float& HEAT(cell *c) { return c->LHU.heat; }
namespace heat { namespace heat {
void affect(cell *c, double delta) {
if(isIcyLand(c)) HEAT(c) += delta;
}
double absheat(cell *c) { double absheat(cell *c) {
if(c->land == laCocytus) return HEAT(c) -.6; if(c->land == laCocytus) return HEAT(c) -.6;
if(c->land == laIce) return HEAT(c) -.4; if(c->land == laIce || c->land == laBlizzard) return HEAT(c) -.4;
return 0; return 0;
} }
@ -1850,21 +1858,30 @@ namespace heat {
forCellEx(ct, c) if(!isIcyLand(ct) && isFire(ct)) forCellEx(ct, c) if(!isIcyLand(ct) && isFire(ct))
hmod += xrate*.1; hmod += xrate*.1;
for(int j=0; j<c->type; j++) if(c->mov[j]) { forCellEx(ct, c) {
if(!isIcyLand(c->mov[j])) { if(!isIcyLand(ct)) {
// make sure that we can still enter Cocytus, // make sure that we can still enter Cocytus,
// it won't heat up right away even without Orb of Winter or Orb of Speed // it won't heat up right away even without Orb of Winter or Orb of Speed
if(isPlayerOn(c->mov[j]) && (c->land == laIce || markOrb(itOrbWinter))) if(isPlayerOn(ct) && (c->land == laIce || markOrb(itOrbWinter)))
hmod += (markOrb(itOrbWinter) ? -1.2 : 1.2) / 4 * xrate; hmod += (markOrb(itOrbWinter) ? -1.2 : 1.2) / 4 * xrate;
continue; continue;
} }
ld hdiff = absheat(c->mov[j]) - absheat(c); ld hdiff = absheat(ct) - absheat(c);
hdiff /= 10; hdiff /= 10;
if(shmup::on && (c->land == laCocytus || c->mov[j]->land == laCocytus))
if(ct->land == laBlizzard) {
int v = (windmap::at(ct) - windmap::at(c)) & 255;
if(v > 128) v -= 256;
if(v < windmap::NOWINDFROM && v > -windmap::NOWINDFROM)
hdiff = hdiff * (1 - v * 5. / windmap::NOWINDFROM);
}
if(shmup::on && (c->land == laCocytus || ct->land == laCocytus))
hdiff /= 3; hdiff /= 3;
// if(c->mov[j]->cpdist > 7 && !quotient) hdiff += -HEAT(c) / 30; // if(c->mov[j]->cpdist > 7 && !quotient) hdiff += -HEAT(c) / 30;
hmod += hdiff; hmod += hdiff;
} }
// printf("%d ", vsum);
hmods[i] = hmod; hmods[i] = hmod;
} }
@ -1971,7 +1988,16 @@ namespace heat {
useup(c); useup(c);
offscreen2.push_back(c); offscreen2.push_back(c);
} }
} }
if(c->wall == waArrowTrap && c->wparam) {
c->wparam++;
if(c->wparam == 3) {
if(canAttack(c, moArrowTrap, c, c->monst, AF_GETPLAYER))
attackMonster(c, AF_ORSTUN | AF_MSG | AF_GETPLAYER, moArrowTrap);
}
if(c->wparam == 4) c->wparam = 0;
}
} }
for(int i=0; i<size(newfires); i++) { for(int i=0; i<size(newfires); i++) {
@ -3044,5 +3070,10 @@ namespace windmap {
printf(" return;\n"); printf(" return;\n");
printf(" }\n"); printf(" }\n");
} }
int at(cell *c) {
return windmap::windcodes[windmap::getId(c)];
}
}; };

View File

@ -159,6 +159,7 @@ bool applyCheat(char u, cell *c = NULL) {
flipplayer = false; flipplayer = false;
mirror::act(1, mirror::SPINSINGLE); mirror::act(1, mirror::SPINSINGLE);
cwspin(cwt, 1); cwspin(cwt, 1);
wavephase = (1+wavephase) & 7;
return true; return true;
} }
if(u == 'J') { if(u == 'J') {

View File

@ -4,7 +4,7 @@
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
bool isIcyLand(eLand l) { bool isIcyLand(eLand l) {
return l == laIce || l == laCocytus; return l == laIce || l == laCocytus || l == laBlizzard;
} }
bool isIcyLand(cell *c) { bool isIcyLand(cell *c) {
@ -24,7 +24,7 @@ bool isWatery(cell *c) {
} }
bool isChasmy(cell *c) { bool isChasmy(cell *c) {
return c->wall == waChasm || c->wall == waSulphur || c->wall == waSulphurC; return c->wall == waChasm || c->wall == waSulphur || c->wall == waSulphurC || c->wall == waBubble;
} }
bool isWateryOrBoat(cell *c) { bool isWateryOrBoat(cell *c) {
@ -267,7 +267,10 @@ int itemclass(eItem i) {
i == itBabyTortoise || i == itDragon || i == itApple || i == itBabyTortoise || i == itDragon || i == itApple ||
i == itKraken || i == itBarrow || i == itTrollEgg || i == itTreat || i == itKraken || i == itBarrow || i == itTrollEgg || i == itTreat ||
i == itSlime || i == itAmethyst || i == itDodeca || i == itSlime || i == itAmethyst || i == itDodeca ||
i == itGreenGrass || i == itBull) i == itGreenGrass || i == itBull ||
i == itAlchemy2 || i == itDogPlains ||
i == itBlizzard || i == itTerra
)
return IC_TREASURE; return IC_TREASURE;
if(i == itSavedPrincess || i == itStrongWind || i == itWarning) if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
return IC_NAI; return IC_NAI;
@ -281,10 +284,18 @@ bool isAlch(eWall w) {
return w == waFloorA || w == waFloorB; return w == waFloorA || w == waFloorB;
} }
bool isAlch2(eWall w, bool bubbletoo) {
return w == waSlime1 || w == waSlime2 || (bubbletoo && w == waBubble);
}
bool isAlch2(cell *c, bool bubbletoo) {
return isAlch2(c->wall, bubbletoo);
}
bool isAlch(cell *c) { return isAlch(c->wall); } bool isAlch(cell *c) { return isAlch(c->wall); }
bool isAlchAny(eWall w) { bool isAlchAny(eWall w) {
return w == waFloorA || w == waFloorB || w == waFloorC || w == waFloorD; return w == waFloorA || w == waFloorB;
} }
bool isAlchAny(cell *c) { return isAlchAny(c->wall); } bool isAlchAny(cell *c) { return isAlchAny(c->wall); }
@ -320,7 +331,8 @@ bool isWall(cell *w) {
w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch || w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch ||
w->wall == waWeakBranch || w->wall == waCanopy || w->wall == waTower || w->wall == waWeakBranch || w->wall == waCanopy || w->wall == waTower ||
w->wall == waSmallBush || w->wall == waBigBush || w->wall == waSmallBush || w->wall == waBigBush ||
w->wall == waReptile || w->wall == waReptileBridge || w->wall == waInvisibleFloor) w->wall == waReptile || w->wall == waReptileBridge || w->wall == waInvisibleFloor ||
w->wall == waSlime1 || w->wall == waSlime2 || w->wall == waArrowTrap)
return false; return false;
if(isWatery(w) || isChasmy(w) || isFire(w)) return false; if(isWatery(w) || isChasmy(w) || isFire(w)) return false;
return true; return true;
@ -362,7 +374,8 @@ bool normalMover(eMonster m) {
m == moRoseBeauty || m == moWolf || m == moRoseBeauty || m == moWolf ||
m == moResearcher || m == moRagingBull || m == moResearcher || m == moRagingBull ||
m == moNarciss || m == moMirrorSpirit || m == moNarciss || m == moMirrorSpirit ||
slowMover(m); m == moHunterDog || m == moTerraWarrior || m == moMercuryGuy || m == moLemur || m == moHunterGuard ||
m == moIceGolem || slowMover(m);
} }
// from-to // from-to

402
game.cpp
View File

@ -23,30 +23,31 @@ int hardcoreAt;
flagtype havewhat, hadwhat; flagtype havewhat, hadwhat;
#define HF_BUG (1<<0) #define HF_BUG Flag(0)
#define HF_EARTH (1<<1) #define HF_EARTH Flag(1)
#define HF_BIRD (1<<2) #define HF_BIRD Flag(2)
#define HF_LEADER (1<<3) #define HF_LEADER Flag(3)
#define HF_HEX (1<<4) #define HF_HEX Flag(4)
#define HF_WHIRLPOOL (1<<5) #define HF_WHIRLPOOL Flag(5)
#define HF_WATER (1<<6) #define HF_WATER Flag(6)
#define HF_AIR (1<<7) #define HF_AIR Flag(7)
#define HF_MUTANT (1<<8) #define HF_MUTANT Flag(8)
#define HF_OUTLAW (1<<9) #define HF_OUTLAW Flag(9)
#define HF_WHIRLWIND (1<<10) #define HF_WHIRLWIND Flag(10)
#define HF_ROSE (1<<11) #define HF_ROSE Flag(11)
#define HF_DRAGON (1<<12) #define HF_DRAGON Flag(12)
#define HF_KRAKEN (1<<13) #define HF_KRAKEN Flag(13)
#define HF_SHARK (1<<14) #define HF_SHARK Flag(14)
#define HF_BATS (1<<15) #define HF_BATS Flag(15)
#define HF_REPTILE (1<<16) #define HF_REPTILE Flag(16)
#define HF_EAGLES (1<<17) #define HF_EAGLES Flag(17)
#define HF_SLOW (1<<18) #define HF_SLOW Flag(18)
#define HF_FAST (1<<19) #define HF_FAST Flag(19)
#define HF_WARP (1<<20) #define HF_WARP Flag(20)
#define HF_MOUSE (1<<21) #define HF_MOUSE Flag(21)
#define HF_RIVER (1<<22) #define HF_RIVER Flag(22)
#define HF_MIRROR (1<<23) #define HF_MIRROR Flag(23)
#define HF_VOID Flag(24)
bool seenSevenMines = false; bool seenSevenMines = false;
@ -332,6 +333,7 @@ int* killtable[] = {
&kills[moHerdBull], &kills[moSleepBull], &kills[moRagingBull], &kills[moHerdBull], &kills[moSleepBull], &kills[moRagingBull],
&kills[moGadfly], &kills[moButterfly], &kills[moGadfly], &kills[moButterfly],
&kills[moNarciss], &kills[moMirrorSpirit], &kills[moNarciss], &kills[moMirrorSpirit],
&kills[moHunterDog], &kills[moIceGolem], &kills[moVoidBeast],
NULL NULL
}; };
@ -459,6 +461,7 @@ bool strictlyAgainstGravity(cell *w, cell *from, bool revdir, flagtype flags) {
bool passable(cell *w, cell *from, flagtype flags) { bool passable(cell *w, cell *from, flagtype flags) {
bool revdir = (flags&P_REVDIR); bool revdir = (flags&P_REVDIR);
bool vrevdir = revdir ^ bool(flags&P_VOID);
if(from && from != w && nonAdjacent(from, w) && !F(P_IGNORE37 | P_BULLET)) return false; if(from && from != w && nonAdjacent(from, w) && !F(P_IGNORE37 | P_BULLET)) return false;
@ -469,7 +472,7 @@ bool passable(cell *w, cell *from, flagtype flags) {
if(from == pp && F(P_ONPLAYER) && F(P_REVDIR)) return true; if(from == pp && F(P_ONPLAYER) && F(P_REVDIR)) return true;
if(from && !((flags & P_ISPLAYER) && getMount(i))) { if(from && !((flags & P_ISPLAYER) && getMount(i))) {
int i = revdir ? incline(w, from) : incline(from, w); int i = vrevdir ? incline(w, from) : incline(from, w);
if(i < -1 && F(P_ROSE)) return false; if(i < -1 && F(P_ROSE)) return false;
if((i > 1) && !F(P_JUMP1 | P_JUMP2 | P_BULLET | P_FLYING | P_BLOW | P_CLIMBUP | P_AETHER | P_REPTILE)) if((i > 1) && !F(P_JUMP1 | P_JUMP2 | P_BULLET | P_FLYING | P_BLOW | P_CLIMBUP | P_AETHER | P_REPTILE))
return false; return false;
@ -483,11 +486,11 @@ bool passable(cell *w, cell *from, flagtype flags) {
if(againstWind(w,from)) return false; if(againstWind(w,from)) return false;
} }
if(from && strictlyAgainstGravity(w, from, revdir, flags) if(from && strictlyAgainstGravity(w, from, vrevdir, flags)
&& !F(P_GRAVITY | P_BLOW | P_JUMP1 | P_JUMP2 | P_FLYING | P_BULLET | P_AETHER) && !F(P_GRAVITY | P_BLOW | P_JUMP1 | P_JUMP2 | P_FLYING | P_BULLET | P_AETHER)
) return false; ) return false;
if(from && (revdir ? againstWind(from,w) : againstWind(w, from)) && !F(P_WIND | P_BLOW | P_JUMP1 | P_JUMP2 | P_BULLET | P_AETHER)) return false; if(from && (vrevdir ? againstWind(from,w) : againstWind(w, from)) && !F(P_WIND | P_BLOW | P_JUMP1 | P_JUMP2 | P_BULLET | P_AETHER)) return false;
if(revdir && from && w->monst && passable(from, w, flags &~ (P_REVDIR|P_MONSTER))) if(revdir && from && w->monst && passable(from, w, flags &~ (P_REVDIR|P_MONSTER)))
return true; return true;
@ -621,7 +624,15 @@ void calcAirdir(cell *c) {
bool againstWind(cell *cto, cell *cfrom) { bool againstWind(cell *cto, cell *cfrom) {
if(!cfrom || !cto) return false; if(!cfrom || !cto) return false;
if(airdist(cto) < airdist(cfrom)) return true; int dcto = airdist(cto), dcfrom = airdist(cfrom);
if(dcto < dcfrom) return true;
if(cfrom->land == laBlizzard && cto->land == laBlizzard && dcto == 3 && dcfrom == 3) {
char vfrom = windmap::at(cfrom);
char vto = windmap::at(cto);
int z = (vfrom-vto) & 255;
if(z >= windmap::NOWINDBELOW && z < windmap::NOWINDFROM)
return true;
}
whirlwind::calcdirs(cfrom); whirlwind::calcdirs(cfrom);
int d = neighborId(cfrom, cto); int d = neighborId(cfrom, cto);
if(whirlwind::winddir(d) == -1) return true; if(whirlwind::winddir(d) == -1) return true;
@ -777,6 +788,8 @@ bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
return passable(w, from, extra | P_ISFRIEND); return passable(w, from, extra | P_ISFRIEND);
if(isWorm(m)) if(isWorm(m))
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)
return passable(w, from, extra | P_VOID);
return false; return false;
} }
@ -805,6 +818,7 @@ eMonster movegroup(eMonster m) {
if(m == moWaterElemental) return moWaterElemental; if(m == moWaterElemental) return moWaterElemental;
if(m == moAirElemental) return moAirElemental; if(m == moAirElemental) return moAirElemental;
if(isBull(m)) return moRagingBull; if(isBull(m)) return moRagingBull;
if(m == moVoidBeast) return moVoidBeast;
return moNone; return moNone;
} }
@ -959,6 +973,14 @@ bool stalemate1::isKilled(cell *w) {
if(canAttack(moveto, who, w, w->monst, flag)) return true; if(canAttack(moveto, who, w, w->monst, flag)) return true;
} }
if(isNeighbor(w, comefrom) && comefrom == moveto && killed) {
int d1 = neighborId(comefrom, w);
int d2 = neighborId(comefrom, killed);
int di = angledist(comefrom->type, d1, d2);
if(di && items[itOrbSide1-1+di] && canAttack(moveto, who, w, w->monst, AF_SIDE))
return true;
}
if(isNeighbor(w, comefrom) && isNeighbor(w, moveto) && moveto != comefrom) if(isNeighbor(w, comefrom) && isNeighbor(w, moveto) && moveto != comefrom)
if(canAttack(moveto, who, w, w->monst, AF_STAB)) if(canAttack(moveto, who, w, w->monst, AF_STAB))
return true; return true;
@ -1279,13 +1301,16 @@ int monstersnear(cell *c, cell *nocount, eMonster who, cell *pushto, cell *comef
return b; return b;
} }
void petrify(cell *c, eWall walltype, eMonster m) { bool petrify(cell *c, eWall walltype, eMonster m) {
destroyHalfvine(c); destroyHalfvine(c);
playSound(c, "die-troll"); playSound(c, "die-troll");
if(walltype == waIcewall && !isIcyLand(c->land))
return false;
if(isWateryOrBoat(c) && c->land == laWhirlpool) { if(isWateryOrBoat(c) && c->land == laWhirlpool) {
c->wall = waSea; c->wall = waSea;
return; return false;
} }
if(walltype == waGargoyle && cellUnstableOrChasm(c)) if(walltype == waGargoyle && cellUnstableOrChasm(c))
@ -1296,11 +1321,11 @@ void petrify(cell *c, eWall walltype, eMonster m) {
walltype = waPetrifiedBridge; walltype = waPetrifiedBridge;
else if((c->wall == waTempBridge || c->wall == waTempBridgeBlocked) && c->land == laWhirlpool) { else if((c->wall == waTempBridge || c->wall == waTempBridgeBlocked) && c->land == laWhirlpool) {
c->wall = waTempBridgeBlocked; c->wall = waTempBridgeBlocked;
return; return true;
} }
else if(!doesnotFall(c)) { else if(!doesnotFall(c)) {
fallingFloorAnimation(c, walltype, m); fallingFloorAnimation(c, walltype, m);
return; return true;
} }
if(isReptile(c->wall)) kills[moReptile]++; if(isReptile(c->wall)) kills[moReptile]++;
@ -1308,6 +1333,7 @@ void petrify(cell *c, eWall walltype, eMonster m) {
c->wall = walltype; c->wall = walltype;
c->wparam = m; c->wparam = m;
c->item = itNone; c->item = itNone;
return true;
} }
void killIvy(cell *c, eMonster who) { void killIvy(cell *c, eMonster who) {
@ -1755,6 +1781,7 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
if(isPrincess(m)) m = moPrincess; if(isPrincess(m)) m = moPrincess;
if(m == moTentacleGhost) m = moGhost; if(m == moTentacleGhost) m = moGhost;
if(!isBulletType(m)) kills[m]++; if(!isBulletType(m)) kills[m]++;
if(m == moHunterGuard) m = moHunterDog;
if(!c->item) if(m == moButterfly && (deathflags & AF_BULL)) if(!c->item) if(m == moButterfly && (deathflags & AF_BULL))
c->item = itBull; c->item = itBull;
@ -1816,6 +1843,12 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
if(connected) petrify(c, waGargoyle, m), pcount = 0; if(connected) petrify(c, waGargoyle, m), pcount = 0;
} }
if(m == moIceGolem) {
if(petrify(c, waIcewall, m)) pcount = 0;
heat::affect(c, -1);
forCellEx(c2, c) heat::affect(c2, -.5);
}
if(m == moTroll) { if(m == moTroll) {
petrify(c, waDeadTroll, m); pcount = 0; petrify(c, waDeadTroll, m); pcount = 0;
@ -2359,6 +2392,10 @@ bool recalcTide;
#define LANDDIST LHU.bytes[1] #define LANDDIST LHU.bytes[1]
#define CHAOSPARAM LHU.bytes[2] #define CHAOSPARAM LHU.bytes[2]
int alchemyval(cell *c, int t) {
return (windmap::at(c) + (turncount+t)*4) & 255;
}
void checkTide(cell *c) { void checkTide(cell *c) {
if(c->land == laOcean) { if(c->land == laOcean) {
int t = c->landparam; int t = c->landparam;
@ -2390,6 +2427,11 @@ void checkTide(cell *c) {
if(isFire(c) && t >= tidalphase) if(isFire(c) && t >= tidalphase)
c->wall = waSea; c->wall = waSea;
} }
if(isAlch2(c, true)) {
int id = alchemyval(c, 0);
if(id < 96) c->wall = waBubble;
else c->wall = waSlime1;
}
} }
void buildAirmap() { void buildAirmap() {
@ -2746,6 +2788,7 @@ void bfs() {
else if(isLeader(c2->monst)) havewhat |= HF_LEADER; else if(isLeader(c2->monst)) havewhat |= HF_LEADER;
else if(c2->monst == moEarthElemental) havewhat |= HF_EARTH; else if(c2->monst == moEarthElemental) havewhat |= HF_EARTH;
else if(c2->monst == moWaterElemental) havewhat |= HF_WATER; else if(c2->monst == moWaterElemental) havewhat |= HF_WATER;
else if(c2->monst == moVoidBeast) havewhat |= HF_VOID;
else if(c2->monst == moShark || c2->monst == moCShark) havewhat |= HF_SHARK; else if(c2->monst == moShark || c2->monst == moCShark) havewhat |= HF_SHARK;
else if(c2->monst == moAirElemental) else if(c2->monst == moAirElemental)
havewhat |= HF_AIR, airmap.push_back(make_pair(c2,0)); havewhat |= HF_AIR, airmap.push_back(make_pair(c2,0));
@ -2878,6 +2921,14 @@ void destroyWeakBranch(cell *cf, cell *ct, eMonster who) {
} }
} }
void activateArrowTrap(cell *c) {
if(c->wall == waArrowTrap && c->wparam == 0) {
c->wparam = 1;
forCellEx(c2, c) activateArrowTrap(c2);
}
}
// effect of moving monster m from cf to ct // effect of moving monster m from cf to ct
// this is called from moveMonster, or separately from moveIvy/moveWorm, // this is called from moveMonster, or separately from moveIvy/moveWorm,
// or when a dead bird falls (then m == moDeadBird) // or when a dead bird falls (then m == moDeadBird)
@ -2893,6 +2944,9 @@ void moveEffect(cell *ct, cell *cf, eMonster m) {
if((ct->wall == waClosePlate || ct->wall == waOpenPlate) && !ignoresPlates(m)) if((ct->wall == waClosePlate || ct->wall == waOpenPlate) && !ignoresPlates(m))
toggleGates(ct, ct->wall); toggleGates(ct, ct->wall);
if(ct->wall == waArrowTrap && !ignoresPlates(m))
activateArrowTrap(ct);
if(cf && isPrincess(m)) princess::move(ct, cf); if(cf && isPrincess(m)) princess::move(ct, cf);
@ -2961,6 +3015,9 @@ void playerMoveEffects(cell *c1, cell *c2) {
if((c2->wall == waClosePlate || c2->wall == waOpenPlate) && !markOrb(itOrbAether)) if((c2->wall == waClosePlate || c2->wall == waOpenPlate) && !markOrb(itOrbAether))
toggleGates(c2, c2->wall); toggleGates(c2, c2->wall);
if(c2->wall == waArrowTrap && !markOrb(itOrbAether))
activateArrowTrap(c2);
princess::playernear(c2); princess::playernear(c2);
if(c2->wall == waGlass && items[itOrbAether] > ORBBASE+1) { if(c2->wall == waGlass && items[itOrbAether] > ORBBASE+1) {
@ -3383,6 +3440,7 @@ int stayval(cell *c, flagtype mf) {
if(isWorm(c->monst)) return 550; if(isWorm(c->monst)) return 550;
if(c->monst == moRagingBull) return -1690; // worse than to stay in place if(c->monst == moRagingBull) return -1690; // worse than to stay in place
if(c->monst == moBat && batsAfraid(c)) return 575; if(c->monst == moBat && batsAfraid(c)) return 575;
if(c->monst == moHunterGuard) return 1600; // prefers to stay in place
return 1000; return 1000;
} }
@ -3423,8 +3481,11 @@ int determinizeBullPush(cellwalker bull) {
return 1; return 1;
} }
int posdir[10], nc;
int pickMoveDirection(cell *c, flagtype mf) { int pickMoveDirection(cell *c, flagtype mf) {
int posdir[10], nc = 0, bestval = stayval(c, mf); int bestval = stayval(c, mf);
nc = 1; posdir[0] = -1;
// printf("stayval [%p, %s]: %d\n", c, dnameof(c->monst), bestval); // printf("stayval [%p, %s]: %d\n", c, dnameof(c->monst), bestval);
for(int d=0; d<c->type; d++) { for(int d=0; d<c->type; d++) {
@ -3439,8 +3500,7 @@ int pickMoveDirection(cell *c, flagtype mf) {
determinizeBull(c, posdir, nc); determinizeBull(c, posdir, nc);
if(!nc) return -1; if(!nc) return -1;
nc = hrand(nc); return posdir[hrand(nc)];
return posdir[nc];
} }
int pickDownDirection(cell *c, flagtype mf) { int pickDownDirection(cell *c, flagtype mf) {
@ -3523,13 +3583,15 @@ void beastAttack(cell *c, bool player) {
} }
} }
bool quantum;
cell *moveNormal(cell *c, flagtype mf) { cell *moveNormal(cell *c, flagtype mf) {
eMonster m = c->monst; eMonster m = c->monst;
int d; int d;
if(c->stuntime) { if(c->stuntime) {
if(cellEdgeUnstable(c, MF_STUNNED)) d = pickDownDirection(c, mf); if(cellEdgeUnstable(c, MF_STUNNED)) d = pickDownDirection(c, mf), nc = 1, posdir[0] = d;
else return NULL; else return NULL;
} }
else { else {
@ -3541,24 +3603,55 @@ cell *moveNormal(cell *c, flagtype mf) {
stayEffect(c); stayEffect(c);
return c; return c;
} }
cell *c2 = c->mov[d];
if(isPlayerOn(c2)) {
killThePlayerAt(m, c2, 0);
return c2;
}
eMonster m2 = c2->monst;
if(m2) {
attackMonster(c2, AF_ORSTUN | AF_MSG, m);
if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2);
return c2;
}
moveMonster(c2, c); if(!quantum) {
if(m == moRagingBull) beastAttack(c2, false); cell *c2 = c->mov[d];
return c2; if(isPlayerOn(c2)) {
killThePlayerAt(m, c2, 0);
return c2;
}
eMonster m2 = c2->monst;
if(m2) {
attackMonster(c2, AF_ORSTUN | AF_MSG, m);
if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2);
return c2;
}
moveMonster(c2, c);
if(m == moRagingBull) beastAttack(c2, false);
return c2;
}
else {
bool attacking = false;
for(int i=0; i<nc; i++) {
cell *c2 = c->mov[posdir[i]];
if(isPlayerOn(c2)) {
killThePlayerAt(m, c2, 0);
attacking = true;
}
else {
eMonster m2 = c2->monst;
if(m2) {
attackMonster(c2, AF_ORSTUN | AF_MSG, m);
if(m == moFlailer && m2 == moIllusion)
attackMonster(c, 0, m2);
attacking = true;
}
}
}
if(!attacking) for(int i=0; i<nc; i++) {
cell *c2 = c->mov[posdir[i]];
if(!c->monst) c->monst = m;
moveMonster(c2, c);
if(m == moRagingBull) beastAttack(c2, false);
}
return c->mov[d];
}
} }
void explodeAround(cell *c) { void explodeAround(cell *c) {
@ -4136,8 +4229,9 @@ void snakeAttack(cell *c, bool mounted) {
for(int j=0; j<c->type; j++) for(int j=0; j<c->type; j++)
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;
attackMonster(c->mov[j], AF_ORSTUN | AF_GETPLAYER | AF_MSG, moHexSnake); attackMonster(c->mov[j], AF_ORSTUN | AF_GETPLAYER | AF_MSG, moHexSnake);
produceGhost(c->mov[j], moHexSnake, m2);
} }
} }
@ -4425,6 +4519,36 @@ void swordAttackStatic() {
swordAttackStatic(bb); swordAttackStatic(bb);
} }
void sideAttack(cell *mf, int dir, eMonster who, int bonus, eItem orb) {
if(!items[orb]) return;
if(who != moPlayer && !items[itOrbEmpathy]) return;
for(int k: {-1, 1}) {
cell *mt = getMovR(mf, dir + k*bonus);
eMonster m = mt->monst;
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))
produceGhost(mt, m, who);
}
else if(mt->wall == waBigTree)
mt->wall = waSmallTree;
else if(mt->wall == waSmallTree)
mt->wall = waNone;
}
}
void sideAttack(cell *mf, int dir, eMonster who, int bonuskill) {
int k = tkills();
sideAttack(mf, dir, who, 1, itOrbSide1);
sideAttack(mf, dir, who, 2, itOrbSide2);
sideAttack(mf, dir, who, 3, itOrbSide3);
int kills = tkills() - k + bonuskill;
if(kills >= 5) achievement_gain("MELEE5");
}
void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) { void stabbingAttack(cell *mf, cell *mt, eMonster who, int bonuskill) {
int numsh = 0, numflail = 0, numlance = 0, numslash = 0; int numsh = 0, numflail = 0, numlance = 0, numslash = 0;
@ -4685,6 +4809,7 @@ void movegolems(flagtype flags) {
} }
attackMonster(c2, ((revenge||jealous)?0:AF_ORSTUN) | AF_MSG, m); attackMonster(c2, ((revenge||jealous)?0:AF_ORSTUN) | AF_MSG, m);
produceGhost(c2, m2, m); produceGhost(c2, m2, m);
sideAttack(c, dir, m, 0);
if(revenge) c->monst = m = moPrincessArmed; if(revenge) c->monst = m = moPrincessArmed;
if(jealous) { if(jealous) {
playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince"); playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince");
@ -4960,7 +5085,7 @@ void moverefresh(bool turn = true) {
if(c->monst == moTortoise && c->item == itBabyTortoise && if(c->monst == moTortoise && c->item == itBabyTortoise &&
!((tortoise::getb(c) ^ tortoise::babymap[c]) & tortoise::mask)) !((tortoise::getb(c) ^ tortoise::babymap[c]) & tortoise::mask))
c->stuntime = 2; c->stuntime = 2;
if(c->monst == moReptile) { if(c->monst == moReptile) {
if(c->wall == waChasm || cellUnstable(c)) { if(c->wall == waChasm || cellUnstable(c)) {
c->monst = moNone; c->monst = moNone;
@ -5166,6 +5291,8 @@ void movemonsters() {
if(havewhat & HF_EARTH) groupmove(moEarthElemental, 0); if(havewhat & HF_EARTH) groupmove(moEarthElemental, 0);
DEBT("water"); DEBT("water");
if(havewhat & HF_WATER) groupmove(moWaterElemental, 0); if(havewhat & HF_WATER) groupmove(moWaterElemental, 0);
DEBT("void");
if(havewhat & HF_VOID) groupmove(moVoidBeast, 0);
DEBT("leader"); DEBT("leader");
if(havewhat & HF_LEADER) groupmove(moPirate, 0); if(havewhat & HF_LEADER) groupmove(moPirate, 0);
DEBT("mutant"); DEBT("mutant");
@ -5717,6 +5844,140 @@ void collectMessage(cell *c2, eItem which) {
} }
} }
int ambushval;
void ambush(cell *c, eItem what) {
int maxdist = purehepta ? 5 : 7;
celllister cl(c, maxdist, 1000000, NULL);
cell *c0 = c;
int d = 0;
cl.prepare();
bool restricted = false;
for(cell *cx: cl.lst) {
int dh = cl.getdist(cx);
if(dh <= 2 && cx->monst == moHunterGuard)
cx->monst = moHunterDog;
if(dh <= 3 && cx->monst) restricted = true;
if(dh > d) c0 = cx, d = dh;
}
vector<cell*> around;
cell *clast = NULL;
cell *ccur = c0;
while(true) {
cell *c2 = NULL;
forCellEx(c1, ccur)
if(c1 != clast && cl.listed(c1) && cl.getdist(c1) == d)
c2 = c1;
if(!c2) break;
if(c2->land == laDogPlains && c2->wall == waNone && c2->monst == moNone)
around.push_back(c2);
clast = ccur; ccur = c2;
if(c2 == c0) break;
}
int N = size(around);
int dogs;
int qty = items[itDogPlains];
if(ambushval) dogs = ambushval;
else
switch(what) {
case itDogPlains:
if(qty <= 16)
dogs = qty;
else
dogs = max(33-qty, 6);
break;
case itOrbSide3:
dogs = restricted ? 10 : 20;
break;
case itOrbFreedom:
dogs = restricted ? 10 : 60;
break;
case itOrbThorns:
case itOrb37:
dogs = 20;
return;
case itOrbBeauty:
dogs = 35;
return;
case itOrbShell:
dogs = 35;
break;
case itOrbPsi:
// dogs = 40; -> no benefits
dogs = 20;
break;
case itOrbDash:
case itOrbFrog:
dogs = 40;
break;
case itOrbAir:
case itOrbDragon:
dogs = 50;
break;
case itOrbStunning:
// dogs = restricted ? 50 : 60; -> no benefits
dogs = 30;
break;
case itOrbBull:
case itOrbSpeed:
case itOrbShield:
dogs = 60;
break;
case itOrbInvis:
dogs = 80;
break;
case itOrbTeleport:
dogs = 300;
break;
case itGreenStone:
case itOrbSafety:
case itOrbYendor:
return;
case itKey:
dogs = 16;
break;
case itWarning:
dogs = qty;
break;
default:
dogs = restricted ? 6 : 10;
break;
// Flash can survive about 70, but this gives no benefits
}
int gaps = dogs;
if(!N) return;
int shift = hrand(N);
dogs = min(dogs, N);
gaps = min(gaps, N);
for(int i=0; i<dogs; i++) {
int pos = (shift + (N * i) / gaps) % N;
cell *nextdog = around[pos];
nextdog->monst = moHunterDog;
nextdog->stuntime = 1;
drawFlash(nextdog);
}
}
bool collectItem(cell *c2, bool telekinesis) { bool collectItem(cell *c2, bool telekinesis) {
int pg = gold(); int pg = gold();
@ -5739,6 +6000,11 @@ bool collectItem(cell *c2, bool telekinesis) {
if(!cantGetGrimoire(c2, false)) collectMessage(c2, c2->item); if(!cantGetGrimoire(c2, false)) collectMessage(c2, c2->item);
if(c2->item == itDodeca && peace::on) peace::simon::extend(); if(c2->item == itDodeca && peace::on) peace::simon::extend();
} }
if(c2->land == laDogPlains && c2->item) {
addMessage(XLAT("You are ambushed!"));
ambush(c2, c2->item);
}
if(isRevivalOrb(c2->item) && multi::revive_queue.size()) { if(isRevivalOrb(c2->item) && multi::revive_queue.size()) {
multiRevival(cwt.c, c2); multiRevival(cwt.c, c2);
@ -5874,7 +6140,7 @@ bool collectItem(cell *c2, bool telekinesis) {
gainItem(itElemental); gainItem(itElemental);
gainItem(itElemental); gainItem(itElemental);
addMessage(XLAT("You construct some Elemental Gems!", c2->item) + itemcounter(items[itElemental])); addMessage(XLAT("You construct some Elemental Gems!", c2->item) + itemcounter(items[itElemental]));
} }
if(c2->item == itBounty) if(c2->item == itBounty)
items[itRevolver] = 6; items[itRevolver] = 6;
@ -6199,6 +6465,19 @@ namespace orbbull {
} }
} }
void terracotta() {
for(int i=0; i<numplayers(); i++)
forCellEx(c2, playerpos(i))
if(c2->wall == waTerraWarrior) {
c2->landparam++;
if((c2->landparam == 3 && hrand(3) == 0) ||
(c2->landparam == 4 && hrand(2) == 0) ||
c2->landparam == 5)
c2->monst = moTerraWarrior,
c2->wall = waNone;
}
}
void monstersTurn() { void monstersTurn() {
mirror::breakAll(); mirror::breakAll();
DEBT("bfs"); DEBT("bfs");
@ -6239,7 +6518,8 @@ void monstersTurn() {
orbbull::check(); orbbull::check();
terracotta();
DEBT("check"); DEBT("check");
checkmove(); checkmove();
if(canmove) elec::checklightningfast(); if(canmove) elec::checklightningfast();
@ -6559,16 +6839,19 @@ bool movepcto(int d, int subdir, bool checkonly) {
addMessage(XLAT("You start chopping down the tree.")); addMessage(XLAT("You start chopping down the tree."));
playSound(c2, "hit-axe" + pick123()); playSound(c2, "hit-axe" + pick123());
c2->wall = waNone; c2->wall = waNone;
sideAttack(cwt.c, d, moPlayer, 0);
} }
else if(c2->wall == waBigTree) { else if(c2->wall == waBigTree) {
drawParticles(c2, winf[c2->wall].color, 8); drawParticles(c2, winf[c2->wall].color, 8);
addMessage(XLAT("You chop down the tree.")); addMessage(XLAT("You chop down the tree."));
playSound(c2, "hit-axe" + pick123()); playSound(c2, "hit-axe" + pick123());
c2->wall = waSmallTree; sideAttack(cwt.c, d, moPlayer, 0);
} }
else { else {
if(!peace::on) if(!peace::on) {
addMessage(XLAT("You swing your sword at the mirror.")); addMessage(XLAT("You swing your sword at the mirror."));
sideAttack(cwt.c, d, moPlayer, 0);
}
} }
if(survivalist && isHaunted(c2->land)) if(survivalist && isHaunted(c2->land))
survivalist = false; survivalist = false;
@ -6692,6 +6975,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
} }
} }
sideAttack(cwt.c, d, moPlayer, 0);
lastmovetype = lmAttack; lastmove = c2; lastmovetype = lmAttack; lastmove = c2;
swordAttackStatic(); swordAttackStatic();
} }

166
graph.cpp
View File

@ -403,9 +403,8 @@ void ShadowV(const transmatrix& V, const hpcshape& bp, int prio) {
if(mmspatial) { if(mmspatial) {
if(pmodel == mdHyperboloid || pmodel == mdBall) if(pmodel == mdHyperboloid || pmodel == mdBall)
return; // shadows break the depth testing return; // shadows break the depth testing
int p = poly_outline; poly_outline = OUTLINE_TRANS; dynamicval<int> p(poly_outline, OUTLINE_TRANS);
queuepolyat(V, bp, SHADOW_MON, prio); queuepolyat(V, bp, SHADOW_MON, prio);
poly_outline = p;
} }
} }
@ -503,6 +502,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
it == itHolyGrail ? &shGrail : it == itHolyGrail ? &shGrail :
isElementalShard(it) ? &shElementalShard : isElementalShard(it) ? &shElementalShard :
(it == itBombEgg || it == itTrollEgg) ? &shEgg : (it == itBombEgg || it == itTrollEgg) ? &shEgg :
it == itDogPlains ? &shTriangle :
it == itDodeca ? &shDodeca : it == itDodeca ? &shDodeca :
xch == '*' ? &shGem[ct6] : xch == '*' ? &shGem[ct6] :
it == itShard ? &shMFloor[0] : it == itShard ? &shMFloor[0] :
@ -610,8 +610,12 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
if(xsh == &shBookCover && mmitem) if(xsh == &shBookCover && mmitem)
queuepoly(V2, shBook, 0x805020FF); queuepoly(V2, shBook, 0x805020FF);
int pr = PPR_ITEM;
int alpha = hidden ? (it == itKraken ? 0xC0 : 0x40) : 0xF0;
if(c && c->wall == waIcewall) pr = PPR_HIDDEN, alpha = 0x80;
queuepoly(V2, *xsh, darkena(icol, 0, hidden ? (it == itKraken ? 0xC0 : 0x40) : 0xF0)); queuepolyat(V2, *xsh, darkena(icol, 0, alpha), pr);
if(it == itZebra) if(it == itZebra)
queuepolyat(V * spin(ticks / 1500. + M_PI/(ct6+6)), *xsh, darkena(0x202020, 0, hidden ? 0x40 : 0xF0), PPR_ITEMb); queuepolyat(V * spin(ticks / 1500. + M_PI/(ct6+6)), *xsh, darkena(0x202020, 0, hidden ? 0x40 : 0xF0), PPR_ITEMb);
@ -645,6 +649,17 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
return false; return false;
} }
void drawTerraWarrior(const transmatrix& V, int t, double footphase) {
int col = 0xC0C0C0;
int col2 = t > 6 ? 0x4040C0 : 0x6060A0;
ShadowV(V, shPBody);
otherbodyparts(V, darkena(t > 4 ? col2 : col, 0, 0xF0), moDesertman, footphase);
queuepoly(VBODY, shPBody, darkena(t > 0 ? col2 : col, 0, 0xF0));
queuepoly(VBODY, shPrinceDress, darkena(t > 1 ? col2 : col, 0, 0xF0));
if(!peace::on) queuepoly(VBODY * Mirror, shPSword, darkena(t > 2 ? col2 : col, 0, 0xF0));
queuepoly(VHEAD, shTurban1, darkena(t > 3 ? col2 : col, 0, 0xF0));
}
bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, double footphase) { bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, double footphase) {
char xch = minf[m].glyph; char xch = minf[m].glyph;
@ -984,7 +999,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
} }
queuepoly(VABODY, shBugArmor, darkena(col, 1, 0xFF)); queuepoly(VABODY, shBugArmor, darkena(col, 1, 0xFF));
} }
else if(m == moRunDog) { else if(m == moRunDog || m == moHunterDog || m == moHunterGuard) {
if(!mmspatial && !footphase) if(!mmspatial && !footphase)
queuepoly(VABODY, shDogBody, darkena(col, 0, 0xFF)); queuepoly(VABODY, shDogBody, darkena(col, 0, 0xFF));
else { else {
@ -993,9 +1008,18 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
animallegs(VALEGS, moRunDog, darkena(col, 0, 0xFF), footphase); animallegs(VALEGS, moRunDog, darkena(col, 0, 0xFF), footphase);
} }
queuepoly(VAHEAD, shDogHead, darkena(col, 0, 0xFF)); queuepoly(VAHEAD, shDogHead, darkena(col, 0, 0xFF));
queuepoly(VAHEAD, shWolf1, darkena(0x202020, 0, 0xFF));
queuepoly(VAHEAD, shWolf2, darkena(0x202020, 0, 0xFF)); {
queuepoly(VAHEAD, shWolf3, darkena(0x202020, 0, 0xFF)); dynamicval<int> dp(poly_outline);
dynamicval<double> dw(minwidth_global);
bool redeyes = m != moRunDog;
int eyes = darkena(redeyes ? 0xFF0000 : 0x202020, 0, 0xFF);
if(redeyes) poly_outline = eyes, minwidth_global = 1;
queuepoly(VAHEAD, shWolf1, eyes);
queuepoly(VAHEAD, shWolf2, eyes);
}
queuepoly(VAHEAD, shWolf3, darkena(m == moRunDog ? 0x202020 : 0x000000, 0, 0xFF));
} }
else if(m == moOrangeDog) { else if(m == moOrangeDog) {
if(!mmspatial && !footphase) if(!mmspatial && !footphase)
@ -1014,7 +1038,8 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
else if(m == moShark || m == moGreaterShark || m == moCShark) else if(m == moShark || m == moGreaterShark || m == moCShark)
queuepoly(VFISH, shShark, darkena(col, 0, 0xFF)); queuepoly(VFISH, shShark, darkena(col, 0, 0xFF));
else if(m == moEagle || m == moParrot || m == moBomberbird || m == moAlbatross || else if(m == moEagle || m == moParrot || m == moBomberbird || m == moAlbatross ||
m == moTameBomberbird || m == moWindCrow || m == moTameBomberbirdMoved) { m == moTameBomberbird || m == moWindCrow || m == moTameBomberbirdMoved ||
m == moSandBird) {
ShadowV(V, shEagle); ShadowV(V, shEagle);
queuepoly(VBIRD, shEagle, darkena(col, 0, 0xFF)); queuepoly(VBIRD, shEagle, darkena(col, 0, 0xFF));
} }
@ -1062,6 +1087,8 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
ShadowV(V, shPBody); ShadowV(V, shPBody);
queuepoly(VBODY, shPBody, c); queuepoly(VBODY, shPBody, c);
} }
else if(m == moTerraWarrior)
drawTerraWarrior(V, 7, footphase);
else if(m == moDesertman) { else if(m == moDesertman) {
otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase); otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
ShadowV(V, shPBody); ShadowV(V, shPBody);
@ -1180,6 +1207,15 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
queuepoly(VHEAD, shPFace, darkena(col, 1, 0x90)); queuepoly(VHEAD, shPFace, darkena(col, 1, 0x90));
queuepoly(VHEAD, shArmor, darkena(col, 0, 0xC0)); queuepoly(VHEAD, shArmor, darkena(col, 0, 0xC0));
} }
else if(m == moTerraWarrior || m == moMercuryGuy || m == moLemur) {
ShadowV(V, shPBody);
otherbodyparts(V, darkena(col, 0, 0xF0), m, footphase);
queuepoly(VBODY, shPBody, darkena(col, 0, 0xF0));
if(!peace::on) queuepoly(VBODY * Mirror, shPSword, darkena(col, 0, 0xF0));
queuepoly(VHEAD, shPHead, darkena(col, 1, 0xF0));
queuepoly(VHEAD, shPFace, darkena(col, 1, 0xF0));
queuepoly(VHEAD, shArmor, darkena(col, 0, 0xF0));
}
else if(m == moGhost || m == moSeep || m == moFriendlyGhost) { else if(m == moGhost || m == moSeep || m == moFriendlyGhost) {
if(m == moFriendlyGhost) col = fghostcolor(ticks, where); if(m == moFriendlyGhost) col = fghostcolor(ticks, where);
queuepoly(VGHOST, shGhost, darkena(col, 0, m == moFriendlyGhost ? 0xC0 : 0x80)); queuepoly(VGHOST, shGhost, darkena(col, 0, m == moFriendlyGhost ? 0xC0 : 0x80));
@ -1285,6 +1321,12 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
if(b > 6) b = 6; if(b > 6) b = 6;
queuepoly(VHEAD, shWightCloak, 0x605040A0 + 0x10101000 * b); queuepoly(VHEAD, shWightCloak, 0x605040A0 + 0x10101000 * b);
} }
else if(m == moVoidBeast) {
otherbodyparts(V, 0x080808D0, m, footphase);
queuepoly(VBODY, shPBody, 0x080808D0);
queuepoly(VHEAD, shPHead, 0x080808D0);
queuepoly(VHEAD, shWightCloak, 0xFF0000A0);
}
else if(m == moGoblin) { else if(m == moGoblin) {
otherbodyparts(V, darkena(col, 0, 0xFF), m, footphase); otherbodyparts(V, darkena(col, 0, 0xFF), m, footphase);
ShadowV(V, shYeti); ShadowV(V, shYeti);
@ -1386,7 +1428,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
int acol = col; int acol = col;
queuepoly(VAHEAD, shTrylobiteHead, darkena(acol, 0, 0xFF)); queuepoly(VAHEAD, shTrylobiteHead, darkena(acol, 0, 0xFF));
} }
else if(m == moEvilGolem) { else if(m == moEvilGolem || m == moIceGolem) {
otherbodyparts(V, darkena(col, 2, 0xC0), m, footphase); otherbodyparts(V, darkena(col, 2, 0xC0), m, footphase);
ShadowV(V, shPBody); ShadowV(V, shPBody);
queuepoly(VBODY, shPBody, darkena(col, 0, 0XC0)); queuepoly(VBODY, shPBody, darkena(col, 0, 0XC0));
@ -2271,7 +2313,7 @@ void setcolors(cell *c, int& wcol, int &fcol) {
if(isWateryOrBoat(c) || c->wall == waReptileBridge) { if(isWateryOrBoat(c) || c->wall == waReptileBridge) {
if(c->land == laOcean) if(c->land == laOcean)
fcol = (c->landparam > 25 && !chaosmode) ? ( fcol = (c->landparam > 25 && !chaosmode) ? (
0x90 + 8 * sin(windmap::windcodes[windmap::getId(c)] * M_PI / 128 - SDL_GetTicks()/1000.) 0x90 + 8 * sin(windmap::windcodes[windmap::getId(c)] * M_PI / 128 - ticks/1000.)
) : ) :
0x1010C0 + int(32 * sin(ticks / 500. + (chaosmode ? c->CHAOSPARAM : c->landparam)*1.5)); 0x1010C0 + int(32 * sin(ticks / 500. + (chaosmode ? c->CHAOSPARAM : c->landparam)*1.5));
else if(c->land == laOceanWall) else if(c->land == laOceanWall)
@ -2366,11 +2408,6 @@ void setcolors(cell *c, int& wcol, int &fcol) {
case laCanvas: case laCanvas:
fcol = c->landparam; fcol = c->landparam;
break; break;
case laAlchemy2:
fcol = (windmap::windcodes[windmap::getId(c)] - SDL_GetTicks()/10) & 255;
if(fcol > 128) fcol = 256 - fcol;
fcol += 96;
break;
case laPalace: case laPalace:
fcol = 0x806020; fcol = 0x806020;
if(c->wall == waClosedGate || c->wall == waOpenGate) if(c->wall == waClosedGate || c->wall == waOpenGate)
@ -2422,6 +2459,17 @@ void setcolors(cell *c, int& wcol, int &fcol) {
fcol = wcol[whirlwind::fzebra3(c)]; fcol = wcol[whirlwind::fzebra3(c)];
} }
break; break;
case laDogPlains:
// fcol = pseudohept(c) ? 0x205050 : 0x306060;
fcol = 0x40E0D0;
fcol /= 2;
if(pseudohept(c)) fcol = fcol * 3/4;
break;
case laTerracotta:
fcol = 0x909090;
break;
case laIvoryTower: case laIvoryTower:
fcol = 0x10101 * (32 + (c->landparam&1) * 32) - 0x000010; fcol = 0x10101 * (32 + (c->landparam&1) * 32) - 0x000010;
@ -2492,24 +2540,34 @@ void setcolors(cell *c, int& wcol, int &fcol) {
break; break;
} }
case laIce: case laCocytus: case laIce: case laCocytus: case laBlizzard:
if(isIcyWall(c)) { if(isIcyWall(c)) {
float h = HEAT(c); float h = HEAT(c);
bool showcoc = c->land == laCocytus && chaosmode && !wmescher; bool showcoc = c->land == laCocytus && chaosmode && !wmescher;
if(h < -0.4)
wcol = gradient(showcoc ? 0x4080FF : 0x4040FF, 0x0000FF, -0.4, h, -1); int colorN04 = showcoc ? 0x4080FF : 0x4040FF;
int colorN10 = 0x0000FF;
int color0 = c->land == laBlizzard ? 0x5050C0 : showcoc ? 0x80C0FF : 0x8080FF;
int color02 = 0xFFFFFF;
int color06 = 0xFF0000;
int color08 = 0xFFFF00;
if(h < -1)
wcol = colorN10;
else if(h < -0.4)
wcol = gradient(colorN04, colorN10 , -0.4, h, -1);
else if(h < 0) else if(h < 0)
wcol = gradient(showcoc ? 0x80C0FF : 0x8080FF, showcoc ? 0x4080FF : 0x4040FF, 0, h, -0.4); wcol = gradient(color0, colorN04, 0, h, -0.4);
else if(h < 0.2) else if(h < 0.2)
wcol = gradient(showcoc ? 0x80C0FF : 0x8080FF, 0xFFFFFF, 0, h, 0.2); wcol = gradient(color0, color02, 0, h, 0.2);
// else if(h < 0.4) // else if(h < 0.4)
// wcol = gradient(0xFFFFFF, 0xFFFF00, 0.2, h, 0.4); // wcol = gradient(0xFFFFFF, 0xFFFF00, 0.2, h, 0.4);
else if(h < 0.6) else if(h < 0.6)
wcol = gradient(0xFFFFFF, 0xFF0000, 0.2, h, 0.6); wcol = gradient(color02, color06, 0.2, h, 0.6);
else if(h < 0.8) else if(h < 0.8)
wcol = gradient(0xFF0000, 0xFFFF00, 0.6, h, 0.8); wcol = gradient(color06, color08, 0.6, h, 0.8);
else else
wcol = 0xFFFF00; wcol = color08;
if(c->wall == waFrozenLake) if(c->wall == waFrozenLake)
fcol = wcol; fcol = wcol;
else else
@ -2563,6 +2621,15 @@ void setcolors(cell *c, int& wcol, int &fcol) {
else else
fcol = wcol; fcol = wcol;
} }
if(isAlch2(c, true)) {
int id = alchemyval(c, -1);
if(id < 96)
wcol = gradient(0x800000, 0xFF0000, 0, id, 96);
else
wcol = gradient(0x00FF00, 0xFFFF00, 96, id, 255);
fcol = wcol;
}
if(c->wall == waDeadTroll2 || c->wall == waPetrified || c->wall == waPetrifiedBridge) { if(c->wall == waDeadTroll2 || c->wall == waPetrified || c->wall == waPetrifiedBridge) {
eMonster m = eMonster(c->wparam); eMonster m = eMonster(c->wparam);
@ -2884,6 +2951,8 @@ bool allemptynear(cell *c) {
return true; return true;
} }
#include "blizzard.cpp"
void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
qfi.shape = NULL; qfi.special = false; qfi.shape = NULL; qfi.special = false;
@ -3160,7 +3229,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
int fd = int fd =
c->land == laRedRock ? 0 : c->land == laRedRock ? 0 :
(c->land == laOcean || c->land == laLivefjord || c->land == laWhirlpool) ? 1 : (c->land == laOcean || c->land == laLivefjord || c->land == laWhirlpool) ? 1 :
c->land == laAlchemist || c->land == laIce || c->land == laGraveyard || c->land == laAlchemist || c->land == laIce || c->land == laGraveyard || c->land == laBlizzard ||
c->land == laRlyeh || c->land == laTemple || c->land == laWineyard || c->land == laRlyeh || c->land == laTemple || c->land == laWineyard ||
c->land == laDeadCaves || c->land == laPalace || c->land == laCA ? 1 : c->land == laDeadCaves || c->land == laPalace || c->land == laCA ? 1 :
c->land == laCanvas ? 0 : c->land == laCanvas ? 0 :
@ -3179,7 +3248,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
c->land == laHalloween ? 1 : c->land == laHalloween ? 1 :
c->land == laTrollheim ? 2 : c->land == laTrollheim ? 2 :
c->land == laReptile ? 0 : c->land == laReptile ? 0 :
c->land == laDogPlains ? 1 :
2; 2;
if(c->land == laAlchemy2) {
int id = alchemyval(c, -1);
if(id/4 == 95/4 || id/4 == 255/4) fd = 0;
if(id/4 == 95/4-1 || id/4 == 255/4-1) fd = 1;
}
poly_outline = OUTLINE_DEFAULT; poly_outline = OUTLINE_DEFAULT;
@ -3360,6 +3436,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else if(wmblack == 1 && c->wall == waMineOpen && vid.grid) else if(wmblack == 1 && c->wall == waMineOpen && vid.grid)
; ;
// else if(true)
// qfloor(c, Vf, shWave[wavephase][ct6], darkena(fcol, fd, 0xFF));
// else if(true)
// qfloor(c, Vf, shSeabed[ct6], darkena(fcol, fd, 0xFF));
else if(wmblack) { else if(wmblack) {
qfloor(c, Vf, shBFloor[ct6], darkena(fcol, 0, 0xFF)); qfloor(c, Vf, shBFloor[ct6], darkena(fcol, 0, 0xFF));
int rd = rosedist(c); int rd = rosedist(c);
@ -3505,7 +3586,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else if(c->land == laHell) else if(c->land == laHell)
qfloor(c, Vf, (euclid ? shStarFloor : shDemonFloor)[ct6], darkena(fcol, fd, 0xFF)); qfloor(c, Vf, (euclid ? shStarFloor : shDemonFloor)[ct6], darkena(fcol, fd, 0xFF));
else if(c->land == laIce) else if(c->land == laIce || c->land == laBlizzard)
qfloor(c, Vf, shStarFloor[ct6], darkena(fcol, fd, 0xFF)); qfloor(c, Vf, shStarFloor[ct6], darkena(fcol, fd, 0xFF));
else if(c->land == laCocytus) else if(c->land == laCocytus)
@ -3680,8 +3761,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
placeSidewallX(c, i, SIDE_LAKE, V, isWarped(c), false, darkena(gradient(0, col, 0, .8, 1), fd, 0xFF)); placeSidewallX(c, i, SIDE_LAKE, V, isWarped(c), false, darkena(gradient(0, col, 0, .8, 1), fd, 0xFF));
chasmg = 1; chasmg = 1;
} }
if(c->wall == waTerraWarrior)
drawTerraWarrior(V, c->landparam & 7, 0);
if(c->wall == waBoat || c->wall == waStrandedBoat) { else if(c->wall == waBoat || c->wall == waStrandedBoat) {
double footphase; double footphase;
bool magical = items[itOrbWater] && (isPlayerOn(c) || (isFriendly(c) && items[itOrbEmpathy])); bool magical = items[itOrbWater] && (isPlayerOn(c) || (isFriendly(c) && items[itOrbEmpathy]));
int outcol = magical ? watercolor(0) : 0xC06000FF; int outcol = magical ? watercolor(0) : 0xC06000FF;
@ -3741,7 +3825,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else if(c->wall == waFrozenLake || c->wall == waLake || c->wall == waCamelotMoat || else if(c->wall == waFrozenLake || c->wall == waLake || c->wall == waCamelotMoat ||
c->wall == waSea || c->wall == waClosePlate || c->wall == waOpenPlate || c->wall == waSea || c->wall == waClosePlate || c->wall == waOpenPlate ||
c->wall == waOpenGate || c->wall == waTrapdoor) c->wall == waOpenGate || c->wall == waTrapdoor || c->wall == waBubble)
; ;
else if(c->wall == waRose) { else if(c->wall == waRose) {
@ -3837,32 +3921,35 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
} }
else { else {
transmatrix Vdepth = mscale(V, geom3::WALL); transmatrix Vdepth = mscale(V, geom3::WALL);
int alpha = 0xFF;
if(c->wall == waIcewall)
alpha = 0xC0;
bool warp = isWarped(c); bool warp = isWarped(c);
if(starcol && !(wmescher && c->wall == waPlatform)) if(starcol && !(wmescher && c->wall == waPlatform))
queuepolyat(Vdepth, shThisWall, darkena(starcol, 0, 0xFF), PPR_WALL3A); queuepolyat(Vdepth, shThisWall, darkena(starcol, 0, 0xFF), PPR_WALL3A);
warpfloor(c, Vdepth, darkena(wcol0, fd, 0xFF), PPR_WALL3, warp); warpfloor(c, Vdepth, darkena(wcol0, fd, alpha), PPR_WALL3, warp);
floorShadow(c, V, SHADOW_WALL, warp); floorShadow(c, V, SHADOW_WALL, warp);
if(c->wall == waCamelot) { if(c->wall == waCamelot) {
forCellIdEx(c2, i, c) { forCellIdEx(c2, i, c) {
placeSidewallX(c, i, SIDE_SLEV, V, warp, false, darkena(wcol2, fd, 0xFF)); placeSidewallX(c, i, SIDE_SLEV, V, warp, false, darkena(wcol2, fd, alpha));
} }
forCellIdEx(c2, i, c) { forCellIdEx(c2, i, c) {
placeSidewallX(c, i, SIDE_SLEV+1, V, warp, false, darkena(wcol2, fd, 0xFF)); placeSidewallX(c, i, SIDE_SLEV+1, V, warp, false, darkena(wcol2, fd, alpha));
} }
forCellIdEx(c2, i, c) { forCellIdEx(c2, i, c) {
placeSidewallX(c, i, SIDE_SLEV+2, V, warp, false, darkena(wcol2, fd, 0xFF)); placeSidewallX(c, i, SIDE_SLEV+2, V, warp, false, darkena(wcol2, fd, alpha));
} }
forCellIdEx(c2, i, c) { forCellIdEx(c2, i, c) {
placeSidewallX(c, i, SIDE_WTS3, V, warp, false, darkena(wcol2, fd, 0xFF)); placeSidewallX(c, i, SIDE_WTS3, V, warp, false, darkena(wcol2, fd, alpha));
} }
} }
else forCellIdEx(c2, i, c) { else forCellIdEx(c2, i, c) {
if(!highwall(c2) || conegraph(c2)) if(!highwall(c2) || conegraph(c2))
{ placeSidewallX(c, i, SIDE_WALL, V, warp, false, darkena(wcol2, fd, 0xFF)); } { placeSidewallX(c, i, SIDE_WALL, V, warp, false, darkena(wcol2, fd, alpha)); }
} }
} }
} }
@ -3872,6 +3959,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
queuepoly(V * spin(M_PI/6 - fanframe * M_PI / 3), shFan, darkena(wcol, 0, 0xFF)); queuepoly(V * spin(M_PI/6 - fanframe * M_PI / 3), shFan, darkena(wcol, 0, 0xFF));
} }
else if(c->wall == waArrowTrap) {
int trapcol[4] = {0x904040, 0xA02020, 0xD00000, 0x303030};
queuepoly(V, shDisk, darkena(trapcol[c->wparam&3], 0, 0xFF));
}
else if(xch == '%') { else if(xch == '%') {
if(doHighlight()) if(doHighlight())
poly_outline = (c->land == laMirror) ? OUTLINE_TREASURE : OUTLINE_ORB; poly_outline = (c->land == laMirror) ? OUTLINE_TREASURE : OUTLINE_ORB;
@ -3912,6 +4004,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else if(xch != '.' && xch != '+' && xch != '>' && xch != ':'&& xch != '-' && xch != ';' && c->wall != waSulphur && xch != ',') else if(xch != '.' && xch != '+' && xch != '>' && xch != ':'&& xch != '-' && xch != ';' && c->wall != waSulphur && xch != ',')
error = true; error = true;
} }
else if(!(it || c->monst || c->cpdist == 0)) error = true; else if(!(it || c->monst || c->cpdist == 0)) error = true;
int sha = shallow(c); int sha = shallow(c);
@ -4070,6 +4163,9 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
} }
} }
if(c->land == laBlizzard)
blizzardcells[c].frame = frameid;
if(c->land == laWhirlwind) { if(c->land == laWhirlwind) {
whirlwind::calcdirs(c); whirlwind::calcdirs(c);
@ -4472,6 +4568,7 @@ void drawFlashes() {
bool allowIncreasedSight() { bool allowIncreasedSight() {
if(cheater) return true; if(cheater) return true;
if(inHighQual) return true;
if(peace::on) return true; if(peace::on) return true;
#if CAP_TOUR #if CAP_TOUR
if(tour::on) return true; if(tour::on) return true;
@ -4487,7 +4584,7 @@ void drawthemap() {
frameid++; frameid++;
wavephase = (-(SDL_GetTicks() / 100)) & 7; wavephase = (-(ticks / 100)) & 7;
if(!allowIncreasedSight()) { if(!allowIncreasedSight()) {
if(sightrange > 7) sightrange = 7; if(sightrange > 7) sightrange = 7;
@ -4562,6 +4659,7 @@ void drawthemap() {
maxreclevel, maxreclevel,
hsOrigin, ypush(vid.yshift) * sphereflip * View); hsOrigin, ypush(vid.yshift) * sphereflip * View);
} }
drawBlizzards();
ivoryz = false; ivoryz = false;
linepatterns::drawAll(); linepatterns::drawAll();

View File

@ -150,6 +150,12 @@ int arg::readCommon() {
shift(); int q = argi(); shift(); int q = argi();
placeItems(q, i); placeItems(q, i);
} }
else if(argis("-ambush")) {
// make all ambushes use the given number of dogs
// example: hyper -W Hunt -IP Shield 1 -ambush 60
PHASE(3) cheater++; timerghost = false;
shift(); ambushval = argi();
}
else if(argis("-M")) { else if(argis("-M")) {
PHASE(3) cheater++; timerghost = false; PHASE(3) cheater++; timerghost = false;
shift(); eMonster m = readMonster(args()); shift(); eMonster m = readMonster(args());
@ -272,6 +278,10 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { showstartmenu
fieldpattern::info(); fieldpattern::info();
exit(0); exit(0);
} }
else if(argis("-quantum")) {
quantum = true;
autocheat = true;
}
else if(argis("-P")) { else if(argis("-P")) {
PHASE(2); shift(); PHASE(2); shift();
vid.scfg.players = argi(); vid.scfg.players = argi();

141
hyper.h
View File

@ -53,7 +53,8 @@ void achievement_pump();
vector<string> achievementsReceived; vector<string> achievementsReceived;
// game forward declarations // game forward declarations
typedef int flagtype; typedef unsigned long long flagtype;
#define Flag(i) (flagtype(1ull<<i))
bool mirrorkill(cell *c); bool mirrorkill(cell *c);
bool isNeighbor(cell *c1, cell *c2); bool isNeighbor(cell *c1, cell *c2);
@ -461,38 +462,39 @@ void setGLProjection();
// passable flags // passable flags
#define P_MONSTER (1<<0) // can move through monsters #define P_MONSTER Flag(0) // can move through monsters
#define P_MIRROR (1<<1) // can move through mirrors #define P_MIRROR Flag(1) // can move through mirrors
#define P_REVDIR (1<<2) // reverse direction movement #define P_REVDIR Flag(2) // reverse direction movement
#define P_WIND (1<<3) // can move against the wind #define P_WIND Flag(3) // can move against the wind
#define P_GRAVITY (1<<4) // can move against the gravity #define P_GRAVITY Flag(4) // can move against the gravity
#define P_ISPLAYER (1<<5) // player-only moves (like the Round Table jump) #define P_ISPLAYER Flag(5) // player-only moves (like the Round Table jump)
#define P_ONPLAYER (1<<6) // always can step on the player #define P_ONPLAYER Flag(6) // always can step on the player
#define P_FLYING (1<<7) // is flying #define P_FLYING Flag(7) // is flying
#define P_BULLET (1<<8) // bullet can fly through more things #define P_BULLET Flag(8) // bullet can fly through more things
#define P_MIRRORWALL (1<<9) // mirror images go through mirror walls #define P_MIRRORWALL Flag(9) // mirror images go through mirror walls
#define P_JUMP1 (1<<10) // first part of a jump #define P_JUMP1 Flag(10) // first part of a jump
#define P_JUMP2 (1<<11) // second part of a jump #define P_JUMP2 Flag(11) // second part of a jump
#define P_TELE (1<<12) // teleport onto #define P_TELE Flag(12) // teleport onto
#define P_BLOW (1<<13) // Orb of Air -- blow, or push #define P_BLOW Flag(13) // Orb of Air -- blow, or push
#define P_AETHER (1<<14) // aethereal #define P_AETHER Flag(14) // aethereal
#define P_FISH (1<<15) // swimming #define P_FISH Flag(15) // swimming
#define P_WINTER (1<<16) // fire resistant #define P_WINTER Flag(16) // fire resistant
#define P_USEBOAT (1<<17) // can use boat #define P_USEBOAT Flag(17) // can use boat
#define P_NOAETHER (1<<18) // disable AETHER #define P_NOAETHER Flag(18) // disable AETHER
#define P_FRIENDSWAP (1<<19) // can move on friends (to swap with tem) #define P_FRIENDSWAP Flag(19) // can move on friends (to swap with tem)
#define P_ISFRIEND (1<<20) // is a friend (can use Empathy + Winter/Aether/Fish combo) #define P_ISFRIEND Flag(20) // is a friend (can use Empathy + Winter/Aether/Fish combo)
#define P_LEADER (1<<21) // can push statues and use boats #define P_LEADER Flag(21) // can push statues and use boats
#define P_MARKWATER (1<<22) // mark Orb of Water as used #define P_MARKWATER Flag(22) // mark Orb of Water as used
#define P_EARTHELEM (1<<23) // Earth Elemental #define P_EARTHELEM Flag(23) // Earth Elemental
#define P_WATERELEM (1<<24) // Water Elemental #define P_WATERELEM Flag(24) // Water Elemental
#define P_IGNORE37 (1<<25) // ignore the triheptagonal board #define P_IGNORE37 Flag(25) // ignore the triheptagonal board
#define P_CHAIN (1<<26) // for chaining moves with boats #define P_CHAIN Flag(26) // for chaining moves with boats
#define P_DEADLY (1<<27) // suicide moves allowed #define P_DEADLY Flag(27) // suicide moves allowed
#define P_ROSE (1<<28) // rose smell #define P_ROSE Flag(28) // rose smell
#define P_CLIMBUP (1<<29) // allow climbing up #define P_CLIMBUP Flag(29) // allow climbing up
#define P_CLIMBDOWN (1<<30) // allow climbing down #define P_CLIMBDOWN Flag(30) // allow climbing down
#define P_REPTILE (1<<31) // is reptile #define P_REPTILE Flag(31) // is reptile
#define P_VOID Flag(32) // void beast
bool passable(cell *w, cell *from, flagtype flags); bool passable(cell *w, cell *from, flagtype flags);
@ -646,38 +648,39 @@ bool withRose(cell *cfrom, cell *cto);
// canAttack/moveval flags // canAttack/moveval flags
#define AF_TOUGH (1<<0) // tough attacks: Hyperbugs #define AF_TOUGH Flag(0) // tough attacks: Hyperbugs
#define AF_MAGIC (1<<1) // magical attacks: Flash #define AF_MAGIC Flag(1) // magical attacks: Flash
#define AF_STAB (1<<2) // stabbing attacks (usually ignored except Hedgehogs) #define AF_STAB Flag(2) // stabbing attacks (usually ignored except Hedgehogs)
#define AF_LANCE (1<<3) // lance attacks (used by Lancers) #define AF_LANCE Flag(3) // lance attacks (used by Lancers)
#define AF_ONLY_ENEMY (1<<4) // only say YES if it is an enemy #define AF_ONLY_ENEMY Flag(4) // only say YES if it is an enemy
#define AF_ONLY_FRIEND (1<<5) // only say YES if it is a friend #define AF_ONLY_FRIEND Flag(5) // only say YES if it is a friend
#define AF_ONLY_FBUG (1<<6) // only say YES if it is a bug_or friend #define AF_ONLY_FBUG Flag(6) // only say YES if it is a bug_or friend
#define AF_BACK (1<<7) // backward attacks (ignored except Viziers and Flailers) #define AF_BACK Flag(7) // backward attacks (ignored except Viziers and Flailers)
#define AF_APPROACH (1<<8) // approach attacks (ignored except Lancers) #define AF_APPROACH Flag(8) // approach attacks (ignored except Lancers)
#define AF_IGNORE_UNARMED (1<<9) // ignore the UNARMED flag #define AF_IGNORE_UNARMED Flag(9) // ignore the UNARMED flag
#define AF_NOSHIELD (1<<10) // ignore the shielded status #define AF_NOSHIELD Flag(10) // ignore the shielded status
#define AF_GETPLAYER (1<<11) // check for player (replace m2 with moPlayer for player position) #define AF_GETPLAYER Flag(11) // check for player (replace m2 with moPlayer for player position)
#define AF_GUN (1<<12) // revolver attack #define AF_GUN Flag(12) // revolver attack
#define AF_FAST (1<<13) // fast attack #define AF_FAST Flag(13) // fast attack
#define AF_EAT (1<<17) // eating attacks from Worm-likes #define AF_EAT Flag(17) // eating attacks from Worm-likes
#define MF_NOATTACKS (1<<14) // don't do any attacks #define MF_NOATTACKS Flag(14) // don't do any attacks
#define MF_PATHDIST (1<<15) // consider pathdist for moveval #define MF_PATHDIST Flag(15) // consider pathdist for moveval
#define MF_ONLYEAGLE (1<<16) // do this only for Eagles #define MF_ONLYEAGLE Flag(16) // do this only for Eagles
#define MF_MOUNT (1<<18) // don't do #define MF_MOUNT Flag(18) // don't do
#define MF_NOFRIEND (1<<19) // don't do it for friends #define MF_NOFRIEND Flag(19) // don't do it for friends
#define AF_SWORD (1<<20) // big sword #define AF_SWORD Flag(20) // big sword
#define AF_SWORD_INTO (1<<21) // moving into big sword #define AF_SWORD_INTO Flag(21) // moving into big sword
#define AF_MSG (1<<22) // produce a message #define AF_MSG Flag(22) // produce a message
#define AF_ORSTUN (1<<23) // attackMonster: allow stunning #define AF_ORSTUN Flag(23) // attackMonster: allow stunning
#define AF_NEXTTURN (1<<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 (1<<25) // death by falling #define AF_FALL Flag(25) // death by falling
#define MF_STUNNED (1<<26) // edgeunstable: ignore ladders (as stunned monsters do) #define MF_STUNNED Flag(26) // edgeunstable: ignore ladders (as stunned monsters do)
#define MF_IVY (1<<27) // edgeunstable: ignore ivy (ivy cannot climb ivy) #define MF_IVY Flag(27) // edgeunstable: ignore ivy (ivy cannot climb ivy)
#define AF_HORNS (1<<28) // spear attack (always has APPROACH too) #define AF_HORNS Flag(28) // spear attack (always has APPROACH too)
#define AF_BULL (1<<29) // bull attack #define AF_BULL Flag(29) // bull attack
#define AF_SIDE Flag(30) // side attack
bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags); bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags);
@ -857,7 +860,7 @@ void resetGeometry();
namespace svg { namespace svg {
void circle(int x, int y, int size, int col); void circle(int x, int y, int size, int col);
void polygon(int *polyx, int *polyy, int polyi, int col, int outline); void polygon(int *polyx, int *polyy, int polyi, int col, int outline, double minwidth);
void text(int x, int y, int size, const string& str, bool frame, int col, int align); void text(int x, int y, int size, const string& str, bool frame, int col, int align);
extern bool in; extern bool in;
extern string *info; extern string *info;
@ -1533,6 +1536,16 @@ static bool orbProtection(eItem it) { return false; } // not implemented
namespace windmap { namespace windmap {
void create(); void create();
static const int NOWINDBELOW = 8;
static const int NOWINDFROM = 120;
int at(cell *c);
} }
extern int wavephase; extern int wavephase;
void buildEquidistant(cell *c);
void produceGhost(cell *c, eMonster victim, eMonster who);
void sideAttack(cell *mf, int dir, eMonster who, int bonus, eItem orb);
void sideAttack(cell *mf, int dir, eMonster who, int bonuskill);

View File

@ -221,7 +221,16 @@ int isNative(eLand l, eMonster m) {
return (m == moRagingBull || m == moHerdBull || m == moGadfly) ? 1 : 0; return (m == moRagingBull || m == moHerdBull || m == moGadfly) ? 1 : 0;
case laAlchemy2: case laAlchemy2:
return false; return m == moLemur ? 2 : 0;
case laTerracotta:
return m == moMercuryGuy ? 2 : m == moTerraWarrior ? 1 : 0;
case laBlizzard:
return (m == moVoidBeast || m == moIceGolem) ? 2 : 0;
case laDogPlains:
return m == moHunterDog ? 1 : 0;
case laCA: return false; case laCA: return false;
} }
@ -311,7 +320,11 @@ eItem treasureType(eLand l) {
case laBull: return itBull; case laBull: return itBull;
case laPrairie: return itGreenGrass; case laPrairie: return itGreenGrass;
case laAlchemy2: return itElixir; case laAlchemy2: return itAlchemy2;
case laTerracotta: return itTerra;
case laBlizzard: return itBlizzard;
case laDogPlains: return itDogPlains;
case laCA: return itNone; case laCA: return itNone;
} }
return itNone; return itNone;
@ -767,6 +780,15 @@ bool landUnlocked(eLand l) {
case laAlchemy2: case laAlchemy2:
return gold() >= R30 && items[itElixir] >= U10; return gold() >= R30 && items[itElixir] >= U10;
case laDogPlains:
return true;
case laTerracotta:
return gold() >= 60;
case laBlizzard:
return items[itDiamond] >= 5 && items[itWindstone] >= 5;
case laCrossroads5: case laCrossroads5:
return gold() >= R300; return gold() >= R300;
} }
@ -3512,6 +3534,15 @@ int reptilemax() {
bool is02(int i) { return i == 0 || i == 2; } bool is02(int i) { return i == 0 || i == 2; }
bool openplains(cell *c) {
celllister cl(c, purehepta ? 5 : 7, 1000000, NULL);
for(cell *c: cl.lst) {
while(c->mpdist > 8) setdist(c, c->mpdist-1, NULL);
if(c->land != laDogPlains) return false;
}
return true;
}
// This function generates all lands. Warning: it's very long! // This function generates all lands. Warning: it's very long!
void setdist(cell *c, int d, cell *from) { void setdist(cell *c, int d, cell *from) {
@ -3611,7 +3642,7 @@ void setdist(cell *c, int d, cell *from) {
else buildPrizeMirror(c, 1000); else buildPrizeMirror(c, 1000);
} }
} }
if(d == 7) if(d == 7)
prairie::generateTreasure(c); prairie::generateTreasure(c);
@ -3986,7 +4017,55 @@ void setdist(cell *c, int d, cell *from) {
if(c->land == laAlchemist) if(c->land == laAlchemist)
c->wall = (randomPatternsMode ? RANDPAT : hrand(2)) ? waFloorA : waFloorB; c->wall = (randomPatternsMode ? RANDPAT : hrand(2)) ? waFloorA : waFloorB;
if(c->land == laAlchemy2)
c->wall = waSlime1;
if(c->land == laBlizzard) {
bool windless = true;
int w = windmap::at(c);
forCellCM(c2, c) {
int w2 = windmap::at(c2);
if(((w2-w) & 255) >= windmap::NOWINDBELOW)
if(((w-w2) & 255) >= windmap::NOWINDBELOW)
windless = false;
}
if(windless) {
c->wall = waIcewall;
if(hrand(500) < PT(100 + 2 * kills[moVoidBeast] + 2 * kills[moIceGolem], 200) && notDippingFor(itBlizzard))
c->item = itBlizzard;
}
}
if(c->land == laTerracotta) {
if(hrand(500) < 15) {
cellwalker cw(c, hrand(c->type));
cell* cc[5];
cc[2] = c;
cellwalker cw2 = cw;
cwstep(cw); cc[3] = cw.c; cwrevstep(cw); cc[4] = cw.c;
cwrevstep(cw2); cc[1] = cw2.c; cwrevstep(cw2); cc[0] = cw2.c;
bool ok = true;
for(int i=1; i<4; i++) {
forCellEx(c2, cc[i]) if(c2->wall == waArrowTrap) ok = false;
if(cc[i]->land != laNone && cc[i]->land != laTerracotta) ok = false;
if(cc[i]->bardir != NODIR) ok = false;
cc[i]->bardir = NOBARRIERS;
}
if(ok) {
for(int i=1; i<4; i++)
cc[i]->wall = waArrowTrap,
cc[i]->wparam = 0;
cc[0]->wall = waStone;
cc[4]->wall = waStone;
}
}
if(pseudohept(c) && hrand(100) < 40 && c->wall == waNone) {
c->wall = waTerraWarrior;
c->landparam = 0;
}
}
if(c->land == laDryForest) { if(c->land == laDryForest) {
if(randomPatternsMode) if(randomPatternsMode)
c->wall = RANDPAT ? waNone : RANDPATV(laHell) ? waBigTree : waSmallTree; c->wall = RANDPAT ? waNone : RANDPATV(laHell) ? waBigTree : waSmallTree;
@ -4652,6 +4731,23 @@ void setdist(cell *c, int d, cell *from) {
if(d == 7 && c->land == laCaves && c->wall == waCavewall && hrand(5000) < items[itGold] + hard && !safety) if(d == 7 && c->land == laCaves && c->wall == waCavewall && hrand(5000) < items[itGold] + hard && !safety)
c->monst = moSeep; c->monst = moSeep;
if(d == 7 && c->land == laDogPlains) {
if(hrand(1000) < 10) {
if(openplains(c)) {
c->item = itDogPlains;
vector<cell*> next;
forCellEx(c2, c) if(c2->mpdist > 7) next.push_back(c2);
if(size(next) && items[itDogPlains] < 10) {
cell *c3 = next[hrand(size(next))];
forCellEx(c4, c3) if(c4->mpdist > 7 && !isNeighbor(c4, c))
c4->monst = moHunterGuard;
}
}
}
if(hrand(5000) < items[itDogPlains]- 17 + hard)
c->monst = moHunterDog;
}
if(d == 7 && c->land == laLivefjord && c->wall == waSea && hrand(5000) < 15 + items[itFjord] + hard && !safety) { if(d == 7 && c->land == laLivefjord && c->wall == waSea && hrand(5000) < 15 + items[itFjord] + hard && !safety) {
if(items[itFjord] >= 5 && hrand(100) < 20 && !peace::on) if(items[itFjord] >= 5 && hrand(100) < 20 && !peace::on)
@ -4821,7 +4917,7 @@ void setdist(cell *c, int d, cell *from) {
placePrizeOrb(c); placePrizeOrb(c);
} }
if(d == 7 && c->wall == waIcewall && c->land != laIce && c->land != laCocytus) if(d == 7 && c->wall == waIcewall && c->land != laIce && c->land != laCocytus && c->land != laBlizzard)
c->wall = waNone; c->wall = waNone;
if(d == 7 && c->wall == waRed3 && c->land != laRedRock) if(d == 7 && c->wall == waRed3 && c->land != laRedRock)
@ -4972,6 +5068,27 @@ void setdist(cell *c, int d, cell *from) {
if(hrand(8000) < 2 * (items[itDiamond] + hard)) if(hrand(8000) < 2 * (items[itDiamond] + hard))
c->monst = hrand(2) ? moYeti : moWolf; c->monst = hrand(2) ? moYeti : moWolf;
} }
if(c->land == laBlizzard) {
if(hrand(8000) < 10 + 2 * (items[itBlizzard] + hard))
c->monst = pick(moVoidBeast, moIceGolem);
}
if(c->land == laAlchemy2) {
if(hrand(5000) < PT(100 + 2 * kills[moLemur], 200) && notDippingFor(itAlchemy2))
c->item = itAlchemy2;
if(hrand(8000) < 2 * (items[itAlchemy2] + hard))
c->monst = moLemur;
}
if(c->land == laTerracotta) {
bool nearwarrior = false;
forCellEx(c2, c) if(c2->wall == waTerraWarrior) nearwarrior = true;
if(nearwarrior && hrand(5000) < PT(100 + 2 * kills[moMercuryGuy], 200) && notDippingFor(itTerra))
c->item = itTerra;
if(hrand(8000) < 2 * (items[itTerra] + hard))
c->monst = moMercuryGuy;
}
if(c->land == laTrollheim && !safety) { if(c->land == laTrollheim && !safety) {
if(hrand(8000) < items[itTrollEgg] + hardness_empty()) if(hrand(8000) < items[itTrollEgg] + hardness_empty())
@ -5482,7 +5599,7 @@ void setdist(cell *c, int d, cell *from) {
#endif #endif
} }
bool wchance(int a, int of) { bool wchance(int a, int of, int reduction = 0) {
of *= 10; of *= 10;
a += yendor::hardness() + 1; a += yendor::hardness() + 1;
if(isCrossroads(cwt.c->land)) if(isCrossroads(cwt.c->land))
@ -5492,6 +5609,10 @@ bool wchance(int a, int of) {
for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE) for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE)
a = max(a, (items[i]-R10) / 10); a = max(a, (items[i]-R10) / 10);
a -= reduction;
if(a < 0) return false;
return hrand(a+of) < a; return hrand(a+of) < a;
} }
@ -5721,6 +5842,9 @@ void wandering() {
else if(c->land == laIce && wchance(items[itDiamond], 10)) else if(c->land == laIce && wchance(items[itDiamond], 10))
c->monst = hrand(2) ? moWolf : moYeti; c->monst = hrand(2) ? moWolf : moYeti;
else if(c->land == laDogPlains && wchance(items[itDogPlains], 50, 26))
c->monst = moHunterDog;
else if(c->land == laDesert && wchance(items[itSpice], 10)) else if(c->land == laDesert && wchance(items[itSpice], 10))
c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm; c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm;

View File

@ -440,8 +440,7 @@ void castLightningBolt(cellwalker lig) {
bnc++; if(bnc > 10) break; bnc++; if(bnc > 10) break;
} }
else { else {
cwspin(lig, 3); cwrev(lig);
if(c->type == 7) cwspin(lig, hrand(2));
} }
if(lig.c->wall == waCloud) { if(lig.c->wall == waCloud) {
@ -654,8 +653,6 @@ eMonster summonedAt(cell *dest) {
return dest->land == laPalace ? moPalace : moBat; return dest->land == laPalace ? moPalace : moBat;
if(dest->wall == waFloorA || dest->wall == waFloorB) if(dest->wall == waFloorA || dest->wall == waFloorB)
return moSlime; return moSlime;
if(dest->wall == waFloorC || dest->wall == waFloorD)
return moRatling;
if(dest->wall == waCavefloor) if(dest->wall == waCavefloor)
return moTroll; return moTroll;
if(dest->wall == waDeadfloor) if(dest->wall == waDeadfloor)
@ -698,6 +695,7 @@ eMonster summonedAt(cell *dest) {
if(dest->wall == waGiantRug) if(dest->wall == waGiantRug)
return moVizier; return moVizier;
if(dest->wall == waNone) { if(dest->wall == waNone) {
if(dest->land == laDogPlains) return moAirElemental;
if(dest->land == laBull) return moRagingBull; if(dest->land == laBull) return moRagingBull;
if(dest->land == laPrairie) return moAirElemental; if(dest->land == laPrairie) return moAirElemental;
if(dest->land == laZebra) return moAirElemental; if(dest->land == laZebra) return moAirElemental;