diff --git a/achievement.cpp b/achievement.cpp index db1bc281..9224cb58 100644 --- a/achievement.cpp +++ b/achievement.cpp @@ -10,7 +10,7 @@ #include "hyper.h" namespace hr { -#define NUMLEADER 87 +#define NUMLEADER 90 EX bool test_achievements = false; @@ -80,7 +80,10 @@ EX const char* leadernames[NUMLEADER] = { "Lazurite Figurines", // 83 "Water Lilies", // 84 "Capon Stones", // 85 - "Crystal Dice" // 86 + "Crystal Dice", // 86 + "Crossbow (bull)", // 87 + "Crossbow (geodesic)", // 88 + "Crossbow (geometric)", // 89 }; #define LB_STATISTICS 62 @@ -109,7 +112,6 @@ EX bool wrongMode(char flags) { if(casual) return true; if(flags == rg::global) return false; if(flags == rg::fail) return true; - if(bow::weapon) return true; if(flags != rg::special_geometry && flags != rg::special_geometry_nicewalls) { if(!BITRUNCATED) return true; @@ -630,6 +632,10 @@ EX void achievement_count(const string& s, int current, int prev) { achievement_gain("BUG3"); if(s == "ELEC" && current >= 10) achievement_gain("ELEC3"); + if(s == "BOWVARIETY" && current >= 2) + achievement_gain("BOWVARIETY1"); + if(s == "BOWVARIETY" && current >= 6) + achievement_gain("BOWVARIETY2"); } int specific_improved = 0; @@ -655,7 +661,6 @@ EX void achievement_score(int cat, int number) { #ifdef HAVE_ACHIEVEMENTS if(cheater) return; if(casual) return; - if(bow::weapon) return; LATE( achievement_score(cat, number); ) if(disksize) return; if(cat == LB_HALLOWEEN) { @@ -796,6 +801,9 @@ EX void achievement_final(bool really_final) { if(PURE) specialcode+=4; if(numplayers() > 1) specialcode+=8; if(inv::on) specialcode+=16; + if(bow::crossbow_mode && bow::style == bow::cbBull) specialcode += 32; + if(bow::crossbow_mode && bow::style == bow::cbGeodesic) specialcode += 64; + if(bow::crossbow_mode && bow::style == bow::cbGeometric) specialcode += 96; if(sphere && specialland == laHalloween) { if(specialcode) return; @@ -822,6 +830,9 @@ EX void achievement_final(bool really_final) { case 8: sid = 61; break; case 9: sid = 44; break; case 16: sid = 69; break; + case 32: sid = 87; break; + case 64: sid = 88; break; + case 96: sid = 89; break; default: return; } diff --git a/complex.cpp b/complex.cpp index 467aeb02..b610188f 100644 --- a/complex.cpp +++ b/complex.cpp @@ -2944,6 +2944,8 @@ EX } EX namespace kraken { + EX map half_killed; + EX cell *head(cell *c) { if(c->monst == moKrakenH) return c; if(c->monst == moKrakenT) return c->move(c->mondir); @@ -3045,6 +3047,7 @@ EX namespace kraken { c3->monst = moNone; } c->monst = moKrakenH; + if(half_killed.count(c2)) { half_killed[c] = half_killed[c2]; half_killed.erase(c2); } vector > acells; acells.push_back(make_pair(c2, c)); forCellIdEx(c3, i, c) { @@ -3516,6 +3519,7 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () { clearing::stats.clear(); clearing::score.clear(); tortoise::emap.clear(); + kraken::half_killed.clear(); tortoise::babymap.clear(); dragon::target = NULL; #if CAP_FIELD @@ -3548,6 +3552,7 @@ auto ccm = addHook(hooks_clearmemory, 0, [] () { addHook(hooks_removecells, 0, [] () { for(cell *c: removed_cells) clearing::score.erase(c); for(auto& am: adj_memo) am.clear(); + for(cell *c: removed_cells) kraken::half_killed.erase(c); eliminate_if(heat::offscreen_heat, is_cell_removed); eliminate_if(heat::offscreen_fire, is_cell_removed); eliminate_if(princess::infos, [] (princess::info*& i) { diff --git a/crossbow.cpp b/crossbow.cpp index 35c4fa56..b4e09037 100644 --- a/crossbow.cpp +++ b/crossbow.cpp @@ -374,6 +374,33 @@ EX void shoot() { vector pushes; + // for achievements + set kills; + vector> healthy_dragons; + map> kraken_hits; + int dragon_hits = 0; + + // for achievements + for(auto& mov: bowpath) { + cell *c = mov.prev.at; + if(c->monst == moDragonHead) { + bool healthy = true; + cell *c1 = c; + int qty = 0; + for(int i=0; ihitpoints) { healthy = false; break; } + if(c1->mondir == NODIR) break; + c1 = c1->move(c1->mondir); + qty++; + } + if(healthy) healthy_dragons.emplace_back(c, qty); + } + if(c->monst == moKrakenT && c->hitpoints) { + kraken_hits[kraken::head(c)].first++; + } + } + for(auto& mov: bowpath) { cell *c = mov.prev.at; cell *cf = mov.prev.cpeek(); @@ -401,6 +428,7 @@ EX void shoot() { mirror::breakMirror(mov.next, -1); eMonster m = c->monst; if(!m || isMimic(m)) continue; + if(m == moKrakenH) continue; if(!canAttack(cf, who, c, m, attackflags)) { if(among(m, moSleepBull, moHerdBull)) { @@ -420,11 +448,16 @@ EX void shoot() { bool push = (items[itCurseWeakness] || (isStunnable(c->monst) && c->hitpoints > 1)); push = push && (!(mov.flags & bpLAST) && monsterPushable(c)); + // for achievements + if(isDragon(m)) dragon_hits++; + if(m == moKrakenT && c->hitpoints) kraken_hits[kraken::head(c)].second++; + if(m && attackMonster(c, attackflags | AF_MSG, who)) hit_anything = true; if(!c->monst || isAnyIvy(m)) { spread_plague(cf, c, movei(mov.prev).rev().d, moPlayer); produceGhost(c, m, moPlayer); + kills.insert(m); } if(push) pushes.push_back(mov); @@ -446,6 +479,22 @@ EX void shoot() { reverse(bowpath.begin(), bowpath.end()); + // three achievements: + achievement_count("BOWVARIETY", kills.size(), 0); + + for(auto p: healthy_dragons) { + cell *c = p.first; + if(c->monst != moDragonHead && dragon_hits >= p.second) + achievement_gain_once("BOWDRAGON"); + } + + for(auto kh: kraken_hits) { + if(kh.second.first == 3 && kh.second.second == 3) { + if(kraken::half_killed[kh.first]) achievement_gain_once("BOWKRAKEN"); + else kraken::half_killed[kh.first] = true; + } + } + gen_bowpath_map(); }