virtual void specialTick(double time, Position position) override { if (rottenTime == -1) rottenTime = time + rottingTime; if (time >= rottenTime && !rotten) { setName(rottenName); setViewObject(object2); corpseInfo.isSkeleton = true; } else { if (!rotten && getWeight() > 10 && Random.roll(20 + (rottenTime - time) / 10)) Effect::applyToPosition(position, EffectId::EMIT_POISON_GAS, EffectStrength::WEAK); if (getWeight() > 10 && !corpseInfo.isSkeleton && !position.getCoverInfo().covered && Random.roll(35)) { for (Position v : position.neighbors8(Random)) { PCreature vulture = CreatureFactory::fromId(CreatureId::VULTURE, position.getModel()->getPestTribe(), MonsterAIFactory::scavengerBird(v)); if (v.canEnter(vulture.get())) { v.addCreature(std::move(vulture)); v.globalMessage("A vulture lands near " + getTheName()); rottenTime -= 40; break; } } } } }
variant<AvatarInfo, AvatarMenuOption> getAvatarInfo(View* view, const PlayerCreaturesInfo* creatures, Options* options, CreatureFactory* creatureFactory) { auto keeperCreatureInfos = creatures->first; auto keeperCreatures = keeperCreatureInfos.transform([&](auto& elem) { return elem.creatureId.transform([&](auto& id) { auto ret = creatureFactory->fromId(id, getPlayerTribeId(elem.tribeAlignment)); for (auto& trait : elem.specialTraits) applySpecialTrait(trait, ret.get()); return ret; }); }); auto adventurerCreatureInfos = creatures->second; auto adventurerCreatures = adventurerCreatureInfos.transform([&](auto& elem) { return elem.creatureId.transform([&](auto& id) { return creatureFactory->fromId(id, getPlayerTribeId(elem.tribeAlignment)); }); }); vector<View::AvatarData> keeperAvatarData; for (int i : All(keeperCreatures)) keeperAvatarData.push_back(View::AvatarData { keeperCreatures[i].transform([](const auto& c) { return getUpgradedViewId(c.get()); }), keeperCreatures[i].transform([](const auto& c) { return c->getName().firstOrBare(); }), keeperCreatureInfos[i].tribeAlignment, keeperCreatures[i][0]->getName().identify(), PlayerRole::KEEPER, keeperCreatureInfos[i].description }); vector<View::AvatarData> adventurerAvatarData; for (int i : All(adventurerCreatures)) adventurerAvatarData.push_back(View::AvatarData { adventurerCreatures[i].transform([](const auto& c) { return getUpgradedViewId(c.get()); }), adventurerCreatures[i].transform([](const auto& c) { return c->getName().firstOrBare(); }), adventurerCreatureInfos[i].tribeAlignment, adventurerCreatures[i][0]->getName().identify(), PlayerRole::ADVENTURER, adventurerCreatureInfos[i].description }); auto result1 = view->chooseAvatar(concat(keeperAvatarData, adventurerAvatarData), options); if (auto option = result1.getValueMaybe<AvatarMenuOption>()) return *option; auto result = result1.getReferenceMaybe<View::AvatarChoice>(); variant<KeeperCreatureInfo, AdventurerCreatureInfo> creatureInfo; PCreature ret; if (result->creatureIndex < keeperCreatures.size()) { creatureInfo = creatures->first[result->creatureIndex]; ret = std::move(keeperCreatures[result->creatureIndex][result->genderIndex]); ret->getName().setBare("Keeper"); } else { creatureInfo = creatures->second[result->creatureIndex - keeperCreatures.size()]; ret = std::move(adventurerCreatures[result->creatureIndex - keeperCreatures.size()][result->genderIndex]); ret->getName().setBare("Adventurer"); } auto villains = creatureInfo.visit([](const auto& elem) { return elem.tribeAlignment;}); return AvatarInfo{std::move(ret), creatureInfo, villains }; }
PCreature TimeQueue::removeCreature(Creature* cRef) { int ind = -1; for (int i : All(creatures)) if (creatures[i].get() == cRef) { ind = i; break; } CHECK(ind > -1) << "Creature not found"; PCreature ret = std::move(creatures[ind]); creatures.erase(creatures.begin() + ind); dead.insert(ret.get()); return ret; }
bool Level::landCreature(vector<Position> landing, PCreature creature) { if (landCreature(landing, creature.get())) { model->addCreature(std::move(creature)); return true; } else return false; }
bool Level::landCreature(StairKey key, PCreature creature) { if (landCreature(key, creature.get())) { model->addCreature(std::move(creature)); return true; } else return false; }
void Level::addCreature(Vec2 position, PCreature c) { Creature* ref = c.get(); model->addCreature(std::move(c)); putCreature(position, ref); }
Vec2 Level::landCreature(vector<Vec2> landing, PCreature creature) { Vec2 pos = landCreature(landing, creature.get()); model->addCreature(std::move(creature)); return pos; }
Vec2 Level::landCreature(StairDirection direction, StairKey key, PCreature creature) { Vec2 pos = landCreature(direction, key, creature.get()); model->addCreature(std::move(creature)); return pos; }
void TimeQueue::addCreature(PCreature c) { queue.push({c.get(), c->getTime()}); creatures.push_back(std::move(c)); }
void Level::Builder::putCreature(Vec2 pos, PCreature creature) { creature->setPosition(transform(pos)); creatures.push_back(NOTNULL(std::move(creature))); }
void Deity::onPrayer(Creature* c) { bool prayerAnswered = false; for (Epithet epithet : randomPermutation(epithets)) { if (contains(usedEpithets, epithet)) continue; bool noEffect = false; switch (epithet) { case Epithet::DEATH: { PCreature death = CreatureFactory::fromId(CreatureId::DEATH, Tribes::get(TribeId::KILL_EVERYONE)); for (Vec2 v : c->getPosition().neighbors8(true)) if (c->getLevel()->inBounds(v) && c->getLevel()->getSquare(v)->canEnter(death.get())) { c->privateMessage("Death appears before you."); c->getLevel()->addCreature(v, std::move(death)); break; } if (death) noEffect = true; break; } case Epithet::WAR: grantGift(c, chooseRandom( {ItemId::SPECIAL_SWORD, ItemId::SPECIAL_BATTLE_AXE, ItemId::SPECIAL_WAR_HAMMER}), name); break; case Epithet::WISDOM: grantGift(c, chooseRandom({ItemId::MUSHROOM_BOOK, ItemId::POTION_BOOK, ItemId::AMULET_BOOK}), name); break; case Epithet::DESTRUCTION: applyEffect(c, EffectType::DESTROY_EQUIPMENT, ""); break; case Epithet::SECRETS: grantGift(c, ItemId::INVISIBLE_POTION, name); break; case Epithet::LIGHTNING: c->bleed(0.9); c->you(MsgType::ARE, "struck by a lightning bolt!"); break; case Epithet::FEAR: applyEffect(c, EffectType::PANIC, name + " puts fear in your heart"); break; case Epithet::MIND: if (Random.roll(2)) applyEffect(c, EffectType::RAGE, name + " fills your head with anger"); else applyEffect(c, EffectType::HALLU, ""); break; case Epithet::CHANGE: if (Random.roll(2) && c->getEquipment().getItem(EquipmentSlot::WEAPON)) { PCreature snake = CreatureFactory::fromId(CreatureId::SNAKE, Tribes::get(TribeId::PEST)); for (Vec2 v : c->getPosition().neighbors8(true)) if (c->getLevel()->inBounds(v) && c->getLevel()->getSquare(v)->canEnter(snake.get())) { c->getLevel()->addCreature(v, std::move(snake)); c->steal({c->getEquipment().getItem(EquipmentSlot::WEAPON)}); c->privateMessage("Ouch!"); c->you(MsgType::YOUR, "weapon turns into a snake!"); break; } if (!snake) break; } for (Item* it : randomPermutation(c->getEquipment().getItems())) { if (it->getType() == ItemType::POTION) { c->privateMessage("Your " + it->getName() + " changes color!"); c->steal({it}); c->take(ItemFactory::potions().random()); break; } if (it->getType() == ItemType::SCROLL) { c->privateMessage("Your " + it->getName() + " changes label!"); c->steal({it}); c->take(ItemFactory::scrolls().random()); break; } if (it->getType() == ItemType::AMULET) { c->privateMessage("Your " + it->getName() + " changes shape!"); c->steal({it}); c->take(ItemFactory::amulets().random()); break; } } break; case Epithet::HEALTH: if (c->getHealth() < 1 || c->lostLimbs()) applyEffect(c, EffectType::HEAL, "You feel a healing power overcoming you"); else { if (Random.roll(4)) grantGift(c, ItemId::HEALING_AMULET, name); else grantGift(c, ItemId::HEALING_POTION, name, Random.getRandom(1, 4)); } break; case Epithet::NATURE: grantGift(c, ItemId::FRIENDLY_ANIMALS_AMULET, name); break; // case Epithet::LOVE: grantGift(c, ItemId::PANIC_MUSHROOM, name); break; case Epithet::WEALTH: grantGift(c, ItemId::GOLD_PIECE, name, Random.getRandom(100, 200)); break; case Epithet::DEFENSE: grantGift(c, ItemId::DEFENSE_AMULET, name); break; case Epithet::DARKNESS: applyEffect(c, EffectType::BLINDNESS, ""); break; case Epithet::CRAFTS: applyEffect(c, chooseRandom({EffectType::ENHANCE_ARMOR, EffectType::ENHANCE_WEAPON}), ""); break; // case Epithet::HUNTING: grantGift(c, ItemId::PANIC_MUSHROOM, name); break; default: noEffect = true; } usedEpithets.push_back(epithet); if (!noEffect) { prayerAnswered = true; break; } } if (!prayerAnswered) c->privateMessage("Your prayer is not answered."); }