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 "
"missiles perfectly.";
const int motypes = 141;
const int motypes = 150;
struct monstertype {
char glyph;
@ -696,6 +696,14 @@ monstertype minf[motypes] = {
"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."
},
{ '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
{ '@', 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."},
// technical
{ '?', 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, "Energy Sword", NODESC},
{ '!', 0xFF0000, "Warning", warningdesc},
{ '!', 0xFF0000, "arrow trap", NODESC},
{ '*', 0, "vertex", "A vertex from rogueviz."}
};
@ -756,10 +765,12 @@ enum eMonster {
moVampire, moBat, moReptile,
moHerdBull, moRagingBull, moSleepBull,
moButterfly, moNarciss, moMirrorSpirit,
moHunterDog, moTerraWarrior, moMercuryGuy, moVoidBeast, moLemur, moHunterGuard,
moIceGolem, moSandBird,
// shmup specials
moPlayer, moBullet, moFlailBullet, moFireball, moTongue, moAirball,
// temporary
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning,
moDeadBug, moLightningBolt, moDeadBird, moEnergySword, moWarning, moArrowTrap,
moRogueviz
};
@ -790,7 +801,7 @@ genderswitch_t genderswitch[NUM_GS] = {
// --- items ---
const int ittypes = 112;
const int ittypes = 119;
struct itemtype {
char glyph;
@ -1183,6 +1194,13 @@ itemtype iinf[ittypes] = {
},
{ 'O', 0xF0F0F0, "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,
@ -1216,12 +1234,14 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
itTrollEgg, itWarning, itOrbStone, itOrbNature, itTreat,
itSlime, itAmethyst, itOrbRecall, itDodeca, itOrbDash, itGreenGrass, itOrbHorns,
itOrbBull, itBull, itOrbMirror,
itInventory
itInventory,
itAlchemy2, itDogPlains, itBlizzard, itTerra,
itOrbSide1, itOrbSide2, itOrbSide3
};
// --- wall types ---
const int walltypes = 100;
const int walltypes = 103;
struct walltype {
char glyph;
@ -1372,8 +1392,8 @@ walltype winf[walltypes] = {
{ '?', 0xFF00FF, "<earth d", NODESC},
{ '?', 0xFF00FF, "<elemental tmp>", NODESC},
{ '?', 0xFF00FF, "<elemental d>", NODESC},
{ '+', 0x607030, "unnamed floor C", NODESC},
{ '+', 0xC0C0FF, "unnamed floor D", NODESC},
{ '+', 0x00F000, "green slime", NODESC},
{ '+', 0xF0F000, "yellow slime", NODESC},
{ '#', 0x764e7c, "rosebush", roselanddesc},
{ '#', 0xC0C000, "warp gate",
"This gate separates the warped area from the normal land."},
@ -1404,6 +1424,9 @@ walltype winf[walltypes] = {
{ '#', 0xC0C0FF, "mirror wall", mirroreddesc},
{ '.', 0xE0E0E0, "stepping stones", "A petrified creature."},
{ '#', 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,
@ -1426,7 +1449,7 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waCharged, waGrounded, waSandstone, waSaloon, waMetal,
waDeadTroll2, waFan,
waTemporary, waEarthD, waElementalTmp, waElementalD,
waFloorC, waFloorD, waRose, waWarpGate,
waSlime1, waSlime2, waRose, waWarpGate,
waTrunk, waSolidBranch, waWeakBranch, waCanopy,
waBarrowWall, waBarrowDig,
waPetrified, waTower,
@ -1435,12 +1458,14 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav
waInvisibleFloor,
waMirrorWall,
waPetrifiedBridge,
waTempBridgeBlocked
waTempBridgeBlocked,
waTerraWarrior, waBubble,
waArrowTrap
};
// --- land types ---
const int landtypes = 73;
const int landtypes = 76;
struct landtype {
int color;
@ -1623,7 +1648,10 @@ const landtype linf[landtypes] = {
{ 0xC8C8FF, "Reflection", mirroreddesc},
{ 0xC8C8FF, "Mirror Land",
"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,
@ -1643,7 +1671,7 @@ enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle
laPrairie, laBull, laCrossroads5, laCA,
laMirrorWall, laMirrored, laMirrorWall2, laMirrored2,
laMirrorOld,
laAlchemy2
laAlchemy2, laBlizzard, laDogPlains, laTerracotta
};
// cell information for the game

View File

@ -1195,8 +1195,12 @@ namespace mirror {
cell *c2 = cw2.c;
if(c2->monst) {
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);
if(!fwd) produceGhost(c2, m2, moMimic);
sideAttack(c, m.second.spin, m2, 0);
}
c->monst = moNone;
}
if(c2->wall == waBigTree)
@ -1758,9 +1762,13 @@ inline float& HEAT(cell *c) { return c->LHU.heat; }
namespace heat {
void affect(cell *c, double delta) {
if(isIcyLand(c)) HEAT(c) += delta;
}
double absheat(cell *c) {
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;
}
@ -1850,21 +1858,30 @@ namespace heat {
forCellEx(ct, c) if(!isIcyLand(ct) && isFire(ct))
hmod += xrate*.1;
for(int j=0; j<c->type; j++) if(c->mov[j]) {
if(!isIcyLand(c->mov[j])) {
forCellEx(ct, c) {
if(!isIcyLand(ct)) {
// make sure that we can still enter Cocytus,
// 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;
continue;
}
ld hdiff = absheat(c->mov[j]) - absheat(c);
ld hdiff = absheat(ct) - absheat(c);
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;
// if(c->mov[j]->cpdist > 7 && !quotient) hdiff += -HEAT(c) / 30;
hmod += hdiff;
}
// printf("%d ", vsum);
hmods[i] = hmod;
}
@ -1971,7 +1988,16 @@ namespace heat {
useup(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++) {
@ -3044,5 +3070,10 @@ namespace windmap {
printf(" return;\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;
mirror::act(1, mirror::SPINSINGLE);
cwspin(cwt, 1);
wavephase = (1+wavephase) & 7;
return true;
}
if(u == 'J') {

View File

@ -4,7 +4,7 @@
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
bool isIcyLand(eLand l) {
return l == laIce || l == laCocytus;
return l == laIce || l == laCocytus || l == laBlizzard;
}
bool isIcyLand(cell *c) {
@ -24,7 +24,7 @@ bool isWatery(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) {
@ -267,7 +267,10 @@ int itemclass(eItem i) {
i == itBabyTortoise || i == itDragon || i == itApple ||
i == itKraken || i == itBarrow || i == itTrollEgg || i == itTreat ||
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;
if(i == itSavedPrincess || i == itStrongWind || i == itWarning)
return IC_NAI;
@ -281,10 +284,18 @@ bool isAlch(eWall w) {
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 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); }
@ -320,7 +331,8 @@ bool isWall(cell *w) {
w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch ||
w->wall == waWeakBranch || w->wall == waCanopy || w->wall == waTower ||
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;
if(isWatery(w) || isChasmy(w) || isFire(w)) return false;
return true;
@ -362,7 +374,8 @@ bool normalMover(eMonster m) {
m == moRoseBeauty || m == moWolf ||
m == moResearcher || m == moRagingBull ||
m == moNarciss || m == moMirrorSpirit ||
slowMover(m);
m == moHunterDog || m == moTerraWarrior || m == moMercuryGuy || m == moLemur || m == moHunterGuard ||
m == moIceGolem || slowMover(m);
}
// from-to

402
game.cpp
View File

@ -23,30 +23,31 @@ int hardcoreAt;
flagtype havewhat, hadwhat;
#define HF_BUG (1<<0)
#define HF_EARTH (1<<1)
#define HF_BIRD (1<<2)
#define HF_LEADER (1<<3)
#define HF_HEX (1<<4)
#define HF_WHIRLPOOL (1<<5)
#define HF_WATER (1<<6)
#define HF_AIR (1<<7)
#define HF_MUTANT (1<<8)
#define HF_OUTLAW (1<<9)
#define HF_WHIRLWIND (1<<10)
#define HF_ROSE (1<<11)
#define HF_DRAGON (1<<12)
#define HF_KRAKEN (1<<13)
#define HF_SHARK (1<<14)
#define HF_BATS (1<<15)
#define HF_REPTILE (1<<16)
#define HF_EAGLES (1<<17)
#define HF_SLOW (1<<18)
#define HF_FAST (1<<19)
#define HF_WARP (1<<20)
#define HF_MOUSE (1<<21)
#define HF_RIVER (1<<22)
#define HF_MIRROR (1<<23)
#define HF_BUG Flag(0)
#define HF_EARTH Flag(1)
#define HF_BIRD Flag(2)
#define HF_LEADER Flag(3)
#define HF_HEX Flag(4)
#define HF_WHIRLPOOL Flag(5)
#define HF_WATER Flag(6)
#define HF_AIR Flag(7)
#define HF_MUTANT Flag(8)
#define HF_OUTLAW Flag(9)
#define HF_WHIRLWIND Flag(10)
#define HF_ROSE Flag(11)
#define HF_DRAGON Flag(12)
#define HF_KRAKEN Flag(13)
#define HF_SHARK Flag(14)
#define HF_BATS Flag(15)
#define HF_REPTILE Flag(16)
#define HF_EAGLES Flag(17)
#define HF_SLOW Flag(18)
#define HF_FAST Flag(19)
#define HF_WARP Flag(20)
#define HF_MOUSE Flag(21)
#define HF_RIVER Flag(22)
#define HF_MIRROR Flag(23)
#define HF_VOID Flag(24)
bool seenSevenMines = false;
@ -332,6 +333,7 @@ int* killtable[] = {
&kills[moHerdBull], &kills[moSleepBull], &kills[moRagingBull],
&kills[moGadfly], &kills[moButterfly],
&kills[moNarciss], &kills[moMirrorSpirit],
&kills[moHunterDog], &kills[moIceGolem], &kills[moVoidBeast],
NULL
};
@ -459,6 +461,7 @@ bool strictlyAgainstGravity(cell *w, cell *from, bool revdir, flagtype flags) {
bool passable(cell *w, cell *from, flagtype flags) {
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;
@ -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 && !((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_JUMP1 | P_JUMP2 | P_BULLET | P_FLYING | P_BLOW | P_CLIMBUP | P_AETHER | P_REPTILE))
return false;
@ -483,11 +486,11 @@ bool passable(cell *w, cell *from, flagtype flags) {
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)
) 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)))
return true;
@ -621,7 +624,15 @@ void calcAirdir(cell *c) {
bool againstWind(cell *cto, cell *cfrom) {
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);
int d = neighborId(cfrom, cto);
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);
if(isWorm(m))
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;
}
@ -805,6 +818,7 @@ eMonster movegroup(eMonster m) {
if(m == moWaterElemental) return moWaterElemental;
if(m == moAirElemental) return moAirElemental;
if(isBull(m)) return moRagingBull;
if(m == moVoidBeast) return moVoidBeast;
return moNone;
}
@ -959,6 +973,14 @@ bool stalemate1::isKilled(cell *w) {
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(canAttack(moveto, who, w, w->monst, AF_STAB))
return true;
@ -1279,13 +1301,16 @@ int monstersnear(cell *c, cell *nocount, eMonster who, cell *pushto, cell *comef
return b;
}
void petrify(cell *c, eWall walltype, eMonster m) {
bool petrify(cell *c, eWall walltype, eMonster m) {
destroyHalfvine(c);
playSound(c, "die-troll");
if(walltype == waIcewall && !isIcyLand(c->land))
return false;
if(isWateryOrBoat(c) && c->land == laWhirlpool) {
c->wall = waSea;
return;
return false;
}
if(walltype == waGargoyle && cellUnstableOrChasm(c))
@ -1296,11 +1321,11 @@ void petrify(cell *c, eWall walltype, eMonster m) {
walltype = waPetrifiedBridge;
else if((c->wall == waTempBridge || c->wall == waTempBridgeBlocked) && c->land == laWhirlpool) {
c->wall = waTempBridgeBlocked;
return;
return true;
}
else if(!doesnotFall(c)) {
fallingFloorAnimation(c, walltype, m);
return;
return true;
}
if(isReptile(c->wall)) kills[moReptile]++;
@ -1308,6 +1333,7 @@ void petrify(cell *c, eWall walltype, eMonster m) {
c->wall = walltype;
c->wparam = m;
c->item = itNone;
return true;
}
void killIvy(cell *c, eMonster who) {
@ -1755,6 +1781,7 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
if(isPrincess(m)) m = moPrincess;
if(m == moTentacleGhost) m = moGhost;
if(!isBulletType(m)) kills[m]++;
if(m == moHunterGuard) m = moHunterDog;
if(!c->item) if(m == moButterfly && (deathflags & AF_BULL))
c->item = itBull;
@ -1816,6 +1843,12 @@ void killMonster(cell *c, eMonster who, flagtype deathflags) {
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) {
petrify(c, waDeadTroll, m); pcount = 0;
@ -2359,6 +2392,10 @@ bool recalcTide;
#define LANDDIST LHU.bytes[1]
#define CHAOSPARAM LHU.bytes[2]
int alchemyval(cell *c, int t) {
return (windmap::at(c) + (turncount+t)*4) & 255;
}
void checkTide(cell *c) {
if(c->land == laOcean) {
int t = c->landparam;
@ -2390,6 +2427,11 @@ void checkTide(cell *c) {
if(isFire(c) && t >= tidalphase)
c->wall = waSea;
}
if(isAlch2(c, true)) {
int id = alchemyval(c, 0);
if(id < 96) c->wall = waBubble;
else c->wall = waSlime1;
}
}
void buildAirmap() {
@ -2746,6 +2788,7 @@ void bfs() {
else if(isLeader(c2->monst)) havewhat |= HF_LEADER;
else if(c2->monst == moEarthElemental) havewhat |= HF_EARTH;
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 == moAirElemental)
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
// this is called from moveMonster, or separately from moveIvy/moveWorm,
// 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))
toggleGates(ct, ct->wall);
if(ct->wall == waArrowTrap && !ignoresPlates(m))
activateArrowTrap(ct);
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))
toggleGates(c2, c2->wall);
if(c2->wall == waArrowTrap && !markOrb(itOrbAether))
activateArrowTrap(c2);
princess::playernear(c2);
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(c->monst == moRagingBull) return -1690; // worse than to stay in place
if(c->monst == moBat && batsAfraid(c)) return 575;
if(c->monst == moHunterGuard) return 1600; // prefers to stay in place
return 1000;
}
@ -3423,8 +3481,11 @@ int determinizeBullPush(cellwalker bull) {
return 1;
}
int posdir[10], nc;
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);
for(int d=0; d<c->type; d++) {
@ -3439,8 +3500,7 @@ int pickMoveDirection(cell *c, flagtype mf) {
determinizeBull(c, posdir, nc);
if(!nc) return -1;
nc = hrand(nc);
return posdir[nc];
return posdir[hrand(nc)];
}
int pickDownDirection(cell *c, flagtype mf) {
@ -3523,13 +3583,15 @@ void beastAttack(cell *c, bool player) {
}
}
bool quantum;
cell *moveNormal(cell *c, flagtype mf) {
eMonster m = c->monst;
int d;
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 {
@ -3541,24 +3603,55 @@ cell *moveNormal(cell *c, flagtype mf) {
stayEffect(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(m == moRagingBull) beastAttack(c2, false);
return c2;
if(!quantum) {
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(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) {
@ -4136,8 +4229,9 @@ void snakeAttack(cell *c, bool mounted) {
for(int j=0; j<c->type; j++)
if(c->mov[j] && canAttack(c, moHexSnake, c->mov[j], c->mov[j]->monst,
mounted ? AF_ONLY_ENEMY : (AF_ONLY_FBUG | AF_GETPLAYER))) {
eMonster m2 = c->mov[j]->monst;
attackMonster(c->mov[j], AF_ORSTUN | AF_GETPLAYER | AF_MSG, moHexSnake);
produceGhost(c->mov[j], moHexSnake, m2);
}
}
@ -4425,6 +4519,36 @@ void swordAttackStatic() {
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) {
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);
produceGhost(c2, m2, m);
sideAttack(c, dir, m, 0);
if(revenge) c->monst = m = moPrincessArmed;
if(jealous) {
playSound(c2, princessgender() ? "dzia-princess" : "dzia-prince");
@ -4960,7 +5085,7 @@ void moverefresh(bool turn = true) {
if(c->monst == moTortoise && c->item == itBabyTortoise &&
!((tortoise::getb(c) ^ tortoise::babymap[c]) & tortoise::mask))
c->stuntime = 2;
if(c->monst == moReptile) {
if(c->wall == waChasm || cellUnstable(c)) {
c->monst = moNone;
@ -5166,6 +5291,8 @@ void movemonsters() {
if(havewhat & HF_EARTH) groupmove(moEarthElemental, 0);
DEBT("water");
if(havewhat & HF_WATER) groupmove(moWaterElemental, 0);
DEBT("void");
if(havewhat & HF_VOID) groupmove(moVoidBeast, 0);
DEBT("leader");
if(havewhat & HF_LEADER) groupmove(moPirate, 0);
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) {
int pg = gold();
@ -5739,6 +6000,11 @@ bool collectItem(cell *c2, bool telekinesis) {
if(!cantGetGrimoire(c2, false)) collectMessage(c2, c2->item);
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()) {
multiRevival(cwt.c, c2);
@ -5874,7 +6140,7 @@ bool collectItem(cell *c2, bool telekinesis) {
gainItem(itElemental);
gainItem(itElemental);
addMessage(XLAT("You construct some Elemental Gems!", c2->item) + itemcounter(items[itElemental]));
}
}
if(c2->item == itBounty)
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() {
mirror::breakAll();
DEBT("bfs");
@ -6239,7 +6518,8 @@ void monstersTurn() {
orbbull::check();
terracotta();
DEBT("check");
checkmove();
if(canmove) elec::checklightningfast();
@ -6559,16 +6839,19 @@ bool movepcto(int d, int subdir, bool checkonly) {
addMessage(XLAT("You start chopping down the tree."));
playSound(c2, "hit-axe" + pick123());
c2->wall = waNone;
sideAttack(cwt.c, d, moPlayer, 0);
}
else if(c2->wall == waBigTree) {
drawParticles(c2, winf[c2->wall].color, 8);
addMessage(XLAT("You chop down the tree."));
playSound(c2, "hit-axe" + pick123());
c2->wall = waSmallTree;
sideAttack(cwt.c, d, moPlayer, 0);
}
else {
if(!peace::on)
if(!peace::on) {
addMessage(XLAT("You swing your sword at the mirror."));
sideAttack(cwt.c, d, moPlayer, 0);
}
}
if(survivalist && isHaunted(c2->land))
survivalist = false;
@ -6692,6 +6975,7 @@ bool movepcto(int d, int subdir, bool checkonly) {
}
}
sideAttack(cwt.c, d, moPlayer, 0);
lastmovetype = lmAttack; lastmove = c2;
swordAttackStatic();
}

166
graph.cpp
View File

@ -403,9 +403,8 @@ void ShadowV(const transmatrix& V, const hpcshape& bp, int prio) {
if(mmspatial) {
if(pmodel == mdHyperboloid || pmodel == mdBall)
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);
poly_outline = p;
}
}
@ -503,6 +502,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
it == itHolyGrail ? &shGrail :
isElementalShard(it) ? &shElementalShard :
(it == itBombEgg || it == itTrollEgg) ? &shEgg :
it == itDogPlains ? &shTriangle :
it == itDodeca ? &shDodeca :
xch == '*' ? &shGem[ct6] :
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)
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)
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;
}
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) {
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));
}
else if(m == moRunDog) {
else if(m == moRunDog || m == moHunterDog || m == moHunterGuard) {
if(!mmspatial && !footphase)
queuepoly(VABODY, shDogBody, darkena(col, 0, 0xFF));
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);
}
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) {
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)
queuepoly(VFISH, shShark, darkena(col, 0, 0xFF));
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);
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);
queuepoly(VBODY, shPBody, c);
}
else if(m == moTerraWarrior)
drawTerraWarrior(V, 7, footphase);
else if(m == moDesertman) {
otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase);
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, 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) {
if(m == moFriendlyGhost) col = fghostcolor(ticks, where);
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;
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) {
otherbodyparts(V, darkena(col, 0, 0xFF), m, footphase);
ShadowV(V, shYeti);
@ -1386,7 +1428,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
int acol = col;
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);
ShadowV(V, shPBody);
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(c->land == laOcean)
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));
else if(c->land == laOceanWall)
@ -2366,11 +2408,6 @@ void setcolors(cell *c, int& wcol, int &fcol) {
case laCanvas:
fcol = c->landparam;
break;
case laAlchemy2:
fcol = (windmap::windcodes[windmap::getId(c)] - SDL_GetTicks()/10) & 255;
if(fcol > 128) fcol = 256 - fcol;
fcol += 96;
break;
case laPalace:
fcol = 0x806020;
if(c->wall == waClosedGate || c->wall == waOpenGate)
@ -2422,6 +2459,17 @@ void setcolors(cell *c, int& wcol, int &fcol) {
fcol = wcol[whirlwind::fzebra3(c)];
}
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:
fcol = 0x10101 * (32 + (c->landparam&1) * 32) - 0x000010;
@ -2492,24 +2540,34 @@ void setcolors(cell *c, int& wcol, int &fcol) {
break;
}
case laIce: case laCocytus:
case laIce: case laCocytus: case laBlizzard:
if(isIcyWall(c)) {
float h = HEAT(c);
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)
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)
wcol = gradient(showcoc ? 0x80C0FF : 0x8080FF, 0xFFFFFF, 0, h, 0.2);
wcol = gradient(color0, color02, 0, h, 0.2);
// else if(h < 0.4)
// wcol = gradient(0xFFFFFF, 0xFFFF00, 0.2, h, 0.4);
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)
wcol = gradient(0xFF0000, 0xFFFF00, 0.6, h, 0.8);
wcol = gradient(color06, color08, 0.6, h, 0.8);
else
wcol = 0xFFFF00;
wcol = color08;
if(c->wall == waFrozenLake)
fcol = wcol;
else
@ -2563,6 +2621,15 @@ void setcolors(cell *c, int& wcol, int &fcol) {
else
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) {
eMonster m = eMonster(c->wparam);
@ -2884,6 +2951,8 @@ bool allemptynear(cell *c) {
return true;
}
#include "blizzard.cpp"
void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
qfi.shape = NULL; qfi.special = false;
@ -3160,7 +3229,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
int fd =
c->land == laRedRock ? 0 :
(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 == laDeadCaves || c->land == laPalace || c->land == laCA ? 1 :
c->land == laCanvas ? 0 :
@ -3179,7 +3248,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
c->land == laHalloween ? 1 :
c->land == laTrollheim ? 2 :
c->land == laReptile ? 0 :
c->land == laDogPlains ? 1 :
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;
@ -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(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) {
qfloor(c, Vf, shBFloor[ct6], darkena(fcol, 0, 0xFF));
int rd = rosedist(c);
@ -3505,7 +3586,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
else if(c->land == laHell)
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));
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));
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;
bool magical = items[itOrbWater] && (isPlayerOn(c) || (isFriendly(c) && items[itOrbEmpathy]));
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 ||
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) {
@ -3837,32 +3921,35 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) {
}
else {
transmatrix Vdepth = mscale(V, geom3::WALL);
int alpha = 0xFF;
if(c->wall == waIcewall)
alpha = 0xC0;
bool warp = isWarped(c);
if(starcol && !(wmescher && c->wall == waPlatform))
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);
if(c->wall == waCamelot) {
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) {
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) {
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) {
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) {
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));
}
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 == '%') {
if(doHighlight())
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 != ',')
error = true;
}
else if(!(it || c->monst || c->cpdist == 0)) error = true;
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) {
whirlwind::calcdirs(c);
@ -4472,6 +4568,7 @@ void drawFlashes() {
bool allowIncreasedSight() {
if(cheater) return true;
if(inHighQual) return true;
if(peace::on) return true;
#if CAP_TOUR
if(tour::on) return true;
@ -4487,7 +4584,7 @@ void drawthemap() {
frameid++;
wavephase = (-(SDL_GetTicks() / 100)) & 7;
wavephase = (-(ticks / 100)) & 7;
if(!allowIncreasedSight()) {
if(sightrange > 7) sightrange = 7;
@ -4562,6 +4659,7 @@ void drawthemap() {
maxreclevel,
hsOrigin, ypush(vid.yshift) * sphereflip * View);
}
drawBlizzards();
ivoryz = false;
linepatterns::drawAll();

View File

@ -150,6 +150,12 @@ int arg::readCommon() {
shift(); int q = argi();
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")) {
PHASE(3) cheater++; timerghost = false;
shift(); eMonster m = readMonster(args());
@ -272,6 +278,10 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { showstartmenu
fieldpattern::info();
exit(0);
}
else if(argis("-quantum")) {
quantum = true;
autocheat = true;
}
else if(argis("-P")) {
PHASE(2); shift();
vid.scfg.players = argi();

141
hyper.h
View File

@ -53,7 +53,8 @@ void achievement_pump();
vector<string> achievementsReceived;
// game forward declarations
typedef int flagtype;
typedef unsigned long long flagtype;
#define Flag(i) (flagtype(1ull<<i))
bool mirrorkill(cell *c);
bool isNeighbor(cell *c1, cell *c2);
@ -461,38 +462,39 @@ void setGLProjection();
// passable flags
#define P_MONSTER (1<<0) // can move through monsters
#define P_MIRROR (1<<1) // can move through mirrors
#define P_REVDIR (1<<2) // reverse direction movement
#define P_WIND (1<<3) // can move against the wind
#define P_GRAVITY (1<<4) // can move against the gravity
#define P_ISPLAYER (1<<5) // player-only moves (like the Round Table jump)
#define P_ONPLAYER (1<<6) // always can step on the player
#define P_FLYING (1<<7) // is flying
#define P_BULLET (1<<8) // bullet can fly through more things
#define P_MIRRORWALL (1<<9) // mirror images go through mirror walls
#define P_JUMP1 (1<<10) // first part of a jump
#define P_JUMP2 (1<<11) // second part of a jump
#define P_TELE (1<<12) // teleport onto
#define P_BLOW (1<<13) // Orb of Air -- blow, or push
#define P_AETHER (1<<14) // aethereal
#define P_FISH (1<<15) // swimming
#define P_WINTER (1<<16) // fire resistant
#define P_USEBOAT (1<<17) // can use boat
#define P_NOAETHER (1<<18) // disable AETHER
#define P_FRIENDSWAP (1<<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_LEADER (1<<21) // can push statues and use boats
#define P_MARKWATER (1<<22) // mark Orb of Water as used
#define P_EARTHELEM (1<<23) // Earth Elemental
#define P_WATERELEM (1<<24) // Water Elemental
#define P_IGNORE37 (1<<25) // ignore the triheptagonal board
#define P_CHAIN (1<<26) // for chaining moves with boats
#define P_DEADLY (1<<27) // suicide moves allowed
#define P_ROSE (1<<28) // rose smell
#define P_CLIMBUP (1<<29) // allow climbing up
#define P_CLIMBDOWN (1<<30) // allow climbing down
#define P_REPTILE (1<<31) // is reptile
#define P_MONSTER Flag(0) // can move through monsters
#define P_MIRROR Flag(1) // can move through mirrors
#define P_REVDIR Flag(2) // reverse direction movement
#define P_WIND Flag(3) // can move against the wind
#define P_GRAVITY Flag(4) // can move against the gravity
#define P_ISPLAYER Flag(5) // player-only moves (like the Round Table jump)
#define P_ONPLAYER Flag(6) // always can step on the player
#define P_FLYING Flag(7) // is flying
#define P_BULLET Flag(8) // bullet can fly through more things
#define P_MIRRORWALL Flag(9) // mirror images go through mirror walls
#define P_JUMP1 Flag(10) // first part of a jump
#define P_JUMP2 Flag(11) // second part of a jump
#define P_TELE Flag(12) // teleport onto
#define P_BLOW Flag(13) // Orb of Air -- blow, or push
#define P_AETHER Flag(14) // aethereal
#define P_FISH Flag(15) // swimming
#define P_WINTER Flag(16) // fire resistant
#define P_USEBOAT Flag(17) // can use boat
#define P_NOAETHER Flag(18) // disable AETHER
#define P_FRIENDSWAP Flag(19) // can move on friends (to swap with tem)
#define P_ISFRIEND Flag(20) // is a friend (can use Empathy + Winter/Aether/Fish combo)
#define P_LEADER Flag(21) // can push statues and use boats
#define P_MARKWATER Flag(22) // mark Orb of Water as used
#define P_EARTHELEM Flag(23) // Earth Elemental
#define P_WATERELEM Flag(24) // Water Elemental
#define P_IGNORE37 Flag(25) // ignore the triheptagonal board
#define P_CHAIN Flag(26) // for chaining moves with boats
#define P_DEADLY Flag(27) // suicide moves allowed
#define P_ROSE Flag(28) // rose smell
#define P_CLIMBUP Flag(29) // allow climbing up
#define P_CLIMBDOWN Flag(30) // allow climbing down
#define P_REPTILE Flag(31) // is reptile
#define P_VOID Flag(32) // void beast
bool passable(cell *w, cell *from, flagtype flags);
@ -646,38 +648,39 @@ bool withRose(cell *cfrom, cell *cto);
// canAttack/moveval flags
#define AF_TOUGH (1<<0) // tough attacks: Hyperbugs
#define AF_MAGIC (1<<1) // magical attacks: Flash
#define AF_STAB (1<<2) // stabbing attacks (usually ignored except Hedgehogs)
#define AF_LANCE (1<<3) // lance attacks (used by Lancers)
#define AF_ONLY_ENEMY (1<<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_FBUG (1<<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_APPROACH (1<<8) // approach attacks (ignored except Lancers)
#define AF_IGNORE_UNARMED (1<<9) // ignore the UNARMED flag
#define AF_NOSHIELD (1<<10) // ignore the shielded status
#define AF_GETPLAYER (1<<11) // check for player (replace m2 with moPlayer for player position)
#define AF_GUN (1<<12) // revolver attack
#define AF_FAST (1<<13) // fast attack
#define AF_EAT (1<<17) // eating attacks from Worm-likes
#define AF_TOUGH Flag(0) // tough attacks: Hyperbugs
#define AF_MAGIC Flag(1) // magical attacks: Flash
#define AF_STAB Flag(2) // stabbing attacks (usually ignored except Hedgehogs)
#define AF_LANCE Flag(3) // lance attacks (used by Lancers)
#define AF_ONLY_ENEMY Flag(4) // only say YES if it is an enemy
#define AF_ONLY_FRIEND Flag(5) // only say YES if it is a friend
#define AF_ONLY_FBUG Flag(6) // only say YES if it is a bug_or friend
#define AF_BACK Flag(7) // backward attacks (ignored except Viziers and Flailers)
#define AF_APPROACH Flag(8) // approach attacks (ignored except Lancers)
#define AF_IGNORE_UNARMED Flag(9) // ignore the UNARMED flag
#define AF_NOSHIELD Flag(10) // ignore the shielded status
#define AF_GETPLAYER Flag(11) // check for player (replace m2 with moPlayer for player position)
#define AF_GUN Flag(12) // revolver attack
#define AF_FAST Flag(13) // fast attack
#define AF_EAT Flag(17) // eating attacks from Worm-likes
#define MF_NOATTACKS (1<<14) // don't do any attacks
#define MF_PATHDIST (1<<15) // consider pathdist for moveval
#define MF_ONLYEAGLE (1<<16) // do this only for Eagles
#define MF_MOUNT (1<<18) // don't do
#define MF_NOFRIEND (1<<19) // don't do it for friends
#define MF_NOATTACKS Flag(14) // don't do any attacks
#define MF_PATHDIST Flag(15) // consider pathdist for moveval
#define MF_ONLYEAGLE Flag(16) // do this only for Eagles
#define MF_MOUNT Flag(18) // don't do
#define MF_NOFRIEND Flag(19) // don't do it for friends
#define AF_SWORD (1<<20) // big sword
#define AF_SWORD_INTO (1<<21) // moving into big sword
#define AF_MSG (1<<22) // produce a message
#define AF_ORSTUN (1<<23) // attackMonster: allow stunning
#define AF_NEXTTURN (1<<24) // next turn -- don't count shield at power 1
#define AF_FALL (1<<25) // death by falling
#define MF_STUNNED (1<<26) // edgeunstable: ignore ladders (as stunned monsters do)
#define MF_IVY (1<<27) // edgeunstable: ignore ivy (ivy cannot climb ivy)
#define AF_HORNS (1<<28) // spear attack (always has APPROACH too)
#define AF_BULL (1<<29) // bull attack
#define AF_SWORD Flag(20) // big sword
#define AF_SWORD_INTO Flag(21) // moving into big sword
#define AF_MSG Flag(22) // produce a message
#define AF_ORSTUN Flag(23) // attackMonster: allow stunning
#define AF_NEXTTURN Flag(24) // next turn -- don't count shield at power 1
#define AF_FALL Flag(25) // death by falling
#define MF_STUNNED Flag(26) // edgeunstable: ignore ladders (as stunned monsters do)
#define MF_IVY Flag(27) // edgeunstable: ignore ivy (ivy cannot climb ivy)
#define AF_HORNS Flag(28) // spear attack (always has APPROACH too)
#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);
@ -857,7 +860,7 @@ void resetGeometry();
namespace svg {
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);
extern bool in;
extern string *info;
@ -1533,6 +1536,16 @@ static bool orbProtection(eItem it) { return false; } // not implemented
namespace windmap {
void create();
static const int NOWINDBELOW = 8;
static const int NOWINDFROM = 120;
int at(cell *c);
}
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;
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;
}
@ -311,7 +320,11 @@ eItem treasureType(eLand l) {
case laBull: return itBull;
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;
}
return itNone;
@ -767,6 +780,15 @@ bool landUnlocked(eLand l) {
case laAlchemy2:
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:
return gold() >= R300;
}
@ -3512,6 +3534,15 @@ int reptilemax() {
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!
void setdist(cell *c, int d, cell *from) {
@ -3611,7 +3642,7 @@ void setdist(cell *c, int d, cell *from) {
else buildPrizeMirror(c, 1000);
}
}
if(d == 7)
prairie::generateTreasure(c);
@ -3986,7 +4017,55 @@ void setdist(cell *c, int d, cell *from) {
if(c->land == laAlchemist)
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(randomPatternsMode)
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)
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(items[itFjord] >= 5 && hrand(100) < 20 && !peace::on)
@ -4821,7 +4917,7 @@ void setdist(cell *c, int d, cell *from) {
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;
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))
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(hrand(8000) < items[itTrollEgg] + hardness_empty())
@ -5482,7 +5599,7 @@ void setdist(cell *c, int d, cell *from) {
#endif
}
bool wchance(int a, int of) {
bool wchance(int a, int of, int reduction = 0) {
of *= 10;
a += yendor::hardness() + 1;
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)
a = max(a, (items[i]-R10) / 10);
a -= reduction;
if(a < 0) return false;
return hrand(a+of) < a;
}
@ -5721,6 +5842,9 @@ void wandering() {
else if(c->land == laIce && wchance(items[itDiamond], 10))
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))
c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm;

View File

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