diff --git a/src/Ai.cpp b/src/Ai.cpp index 1b8c680..c3941cd 100644 --- a/src/Ai.cpp +++ b/src/Ai.cpp @@ -6,71 +6,108 @@ // After losing his sight static const int TRACKING_TURNS = 3; -Ai *Ai::create(TCODZip &zip) { - AiType type=(AiType)zip.getInt(); - Ai *ai=NULL; - switch(type) { - case PLAYER: ai = new PlayerAi(); break; - case MONSTER: ai = new MonsterAi(); break; - case CONFUSED_MONSTER: ai = new ConfusedMonsterAi(0, NULL); break; - } - ai->load(zip); - return ai; -} - -/* Player AI */ -PlayerAi::PlayerAi() : xpLevel(1) { } - -const int LEVEL_UP_BASE=200; -const int LEVEL_UP_FACTOR=150; - -int PlayerAi::getNextLevelXp() { - return LEVEL_UP_BASE + xpLevel*LEVEL_UP_FACTOR; -} - -void PlayerAi::update(Actor *owner) { - int levelUpXp = getNextLevelXp(); - if(owner->destructible->xp >= levelUpXp) { - xpLevel++; - owner->destructible->xp -= levelUpXp; - engine.gui->message(TCODColor::yellow, "Your battle skills grow stronger! You reached level %d", xpLevel); - engine.gui->menu.clear(); - engine.gui->menu.addItem(Menu::CONSTITUTION, "Constitution (+20HP)"); - engine.gui->menu.addItem(Menu::STRENGTH, "Strength (+1 Attack)"); - engine.gui->menu.addItem(Menu::AGILITY, "Agility (+1 Defense)"); - Menu::MenuItemCode menuItem=engine.gui->menu.pick(Menu::PAUSE); - switch(menuItem) { - case Menu::CONSTITUTION: - owner->destructible->maxHp+=20; - owner->destructible->hp+=20; - break; - case Menu::STRENGTH: - owner->attacker->power+=1; - break; - case Menu::AGILITY: - owner->destructible->defense+=1; - break; - default: break; - } - } +MonsterAi::MonsterAi() : moveCount(0) { } +void MonsterAi::update(Actor *owner) { if(owner->destructible && owner->destructible->isDead()) { return; } - int dx=0, dy=0; + if(engine.map->isInFov(owner->x, owner->y)) { + // We can see the player, move towards him + moveCount=TRACKING_TURNS; + } else { + moveCount--; + } + if(moveCount > 0) { + moveOrAttack(owner, engine.player->x, engine.player->y); + } +} +void MonsterAi::moveOrAttack(Actor *owner, int targetx, int targety) { + int dx = targetx - owner->x; + int dy = targety - owner->y; + int stepdx = (dx > 0 ? 1:-1); + int stepdy = (dy > 0 ? 1:-1); + float distance=sqrtf(dx*dx+dy*dy); + if(distance >= 2) { + dx = (int)(round(dx/distance)); + dy = (int)(round(dy/distance)); + if(engine.map->canWalk(owner->x+dx, owner->y+dy)) { + owner->x += dx; + owner->y += dy; + } else if(engine.map->canWalk(owner->x+stepdx, owner->y)) { + owner->x += stepdx; + } else if(engine.map->canWalk(owner->x, owner->y+stepdy)) { + owner->y += stepdy; + } + } else if(owner->attacker) { + owner->attacker->attack(owner, engine.player); + } +} +void MonsterAi::load(TCODZip &zip) { + moveCount = zip.getInt(); +} +void MonsterAi::save(TCODZip &zip) { + zip.putInt(MONSTER); + zip.putInt(moveCount); +} + +TemporaryAi::TemporaryAi(int nbTurns) : nbTurns(nbTurns) { } +void TemporaryAi::update(Actor *owner) { + nbTurns--; + if(nbTurns == 0) { + owner->ai = oldAi; + delete this; + } +} +void TemporaryAi::applyTo(Actor *actor) { + oldAi = actor->ai; + actor->ai = this; +} +void TemporaryAi::load(TCODZip &zip) { + nbTurns=zip.getInt(); + oldAi=Ai::create(zip); +} +void TemporaryAi::save(TCODZip &zip) { + zip.putInt(CONFUSED_MONSTER); + zip.putInt(nbTurns); + oldAi->save(zip); +} + +ConfusedMonsterAi::ConfusedMonsterAi(int nbTurns) : TemporaryAi(nbTurns) { } +void ConfusedMonsterAi::update(Actor *owner) { + TCODRandom *rng = TCODRandom::getInstance(); + int dx = rng->getInt(-1, 1); + int dy = rng->getInt(-1, 1); + if(dx != 0 || dy != 0) { + int destx = owner->x + dx; + int desty = owner->y + dy; + if(engine.map->canWalk(destx, desty)) { + owner->x = destx; + owner->y = desty; + } else { + Actor *actor=engine.getActor(destx, desty); + if(actor) { + owner->attacker->attack(owner, actor); + } + } + } + TemporaryAi::update(owner); +} + +void PlayerAi::update(Actor *owner) { + if(owner->destructible && owner->destructible->isDead()) { + return; + } + int dx=0,dy=0; switch(engine.lastKey.vk) { - case TCODK_UP: case TCODK_KP8: dy=-1; break; - case TCODK_DOWN: case TCODK_KP2: dy=1; break; - case TCODK_LEFT: case TCODK_KP4: dx=-1; break; - case TCODK_RIGHT: case TCODK_KP6: dx=1; break; - case TCODK_KP7: dy=dx=-1; break; - case TCODK_KP9: dy=-1;dx=1; break; - case TCODK_KP1: dy=1;dx=-1; break; - case TCODK_KP3: dy=dx=1; break; + case TCODK_UP: dy=-1; break; + case TCODK_DOWN: dy=1; break; + case TCODK_LEFT: dx=-1; break; + case TCODK_RIGHT: dx=1; break; case TCODK_CHAR: handleActionKey(owner, engine.lastKey.c); break; - default:break; + default: break; } if(dx != 0 || dy != 0) { - engine.gameStatus=Engine::NEW_TURN; + engine.gameStatus = Engine::NEW_TURN; if(moveOrAttack(owner, owner->x+dx, owner->y+dy)) { engine.map->computeFov(); } @@ -106,6 +143,15 @@ bool PlayerAi::moveOrAttack(Actor *owner, int targetx, int targety) { void PlayerAi::handleActionKey(Actor *owner, int ascii) { switch(ascii) { + case 'd': // Drop item + { + Actor *actor = chooseFromInventory(owner); + if(actor) { + actor->pickable->drop(actor, owner); + engine.gameStatus = Engine::NEW_TURN; + } + } + break; case 'g': // pickup item { bool found=false; @@ -131,22 +177,13 @@ void PlayerAi::handleActionKey(Actor *owner, int ascii) { break; case 'i': // Display inventory { - Actor *actor=choseFromInventory(owner); + Actor *actor=chooseFromInventory(owner); if(actor) { actor->pickable->use(actor, owner); engine.gameStatus=Engine::NEW_TURN; } } break; - case 'd': // Drop item - { - Actor *actor = choseFromInventory(owner); - if(actor) { - actor->pickable->drop(actor, owner); - engine.gameStatus = Engine::NEW_TURN; - } - } - break; case '>': if(engine.stairs->x == owner->x && engine.stairs->y == owner->y) { engine.nextLevel(); @@ -157,13 +194,16 @@ void PlayerAi::handleActionKey(Actor *owner, int ascii) { } } -Actor *PlayerAi::choseFromInventory(Actor *owner) { +Actor *PlayerAi::chooseFromInventory(Actor *owner) { static const int INVENTORY_WIDTH=50; static const int INVENTORY_HEIGHT=28; static TCODConsole con(INVENTORY_WIDTH, INVENTORY_HEIGHT); + // Display the inventory frame con.setDefaultForeground(TCODColor(200, 180, 50)); - con.printFrame(0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT, true, TCOD_BKGND_DEFAULT, "inventory"); + con.printFrame(0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT, true, + TCOD_BKGND_DEFAULT, "Inventory"); + // Display the items with their keyboard shortcut con.setDefaultForeground(TCODColor::white); int shortcut='a'; @@ -175,11 +215,13 @@ Actor *PlayerAi::choseFromInventory(Actor *owner) { y++; shortcut++; } + // blit the inventory console on the root console TCODConsole::blit(&con, 0, 0, INVENTORY_WIDTH, INVENTORY_HEIGHT, TCODConsole::root, engine.screenWidth/2 - INVENTORY_WIDTH/2, engine.screenHeight/2 - INVENTORY_HEIGHT/2); TCODConsole::flush(); + // wait for a key press TCOD_key_t key; TCODSystem::waitForEvent(TCOD_EVENT_KEY_PRESS, &key, NULL, true); @@ -192,94 +234,29 @@ Actor *PlayerAi::choseFromInventory(Actor *owner) { return NULL; } +Ai *Ai::create(TCODZip &zip) { + AiType type=(AiType)zip.getInt(); + Ai *ai=NULL; + switch(type) { + case PLAYER: ai = new PlayerAi(); break; + case MONSTER: ai = new MonsterAi(); break; + case CONFUSED_MONSTER: ai = new ConfusedMonsterAi(0); break; + } + ai->load(zip); + return ai; +} + +/* Player AI */ +PlayerAi::PlayerAi() : xpLevel(1) { } + +const int LEVEL_UP_BASE=200; +const int LEVEL_UP_FACTOR=150; + +int PlayerAi::getNextLevelXp() { + return LEVEL_UP_BASE + xpLevel*LEVEL_UP_FACTOR; +} + void PlayerAi::load(TCODZip &zip) { } void PlayerAi::save(TCODZip &zip) { zip.putInt(PLAYER); } - - -/* Monster AI */ -void MonsterAi::update(Actor *owner) { - if(owner->destructible && owner->destructible->isDead()) { - return; - } - if(engine.map->isInFov(owner->x, owner->y)) { - // We can see the player. Move towards him. - moveCount=TRACKING_TURNS; - } else { - moveCount--; - } - if(moveCount > 0) { - moveOrAttack(owner, engine.player->x, engine.player->y); - } -} - -void MonsterAi::moveOrAttack(Actor *owner, int targetx, int targety) { - int dx = targetx - owner->x; - int dy = targety - owner->y; - int stepdx = (dx > 0 ? 1:-1); - int stepdy = (dy > 0 ? 1:-1); - - float distance=sqrtf(dx*dx+dy*dy); - - if(distance >= 2) { - dx = (int)(round(dx/distance)); - dy = (int)(round(dy/distance)); - if(engine.map->canWalk(owner->x+dx, owner->y+dy)) { - owner->x += dx; - owner->y += dy; - } else if(engine.map->canWalk(owner->x + stepdx, owner->y)) { - owner->x += stepdx; - } else if(engine.map->canWalk(owner->x, owner->y + stepdy)) { - owner->y += stepdy; - } - } else if(owner->attacker) { - owner->attacker->attack(owner, engine.player); - } -} - -void MonsterAi::load(TCODZip &zip) { - moveCount = zip.getInt(); -} -void MonsterAi::save(TCODZip &zip) { - zip.putInt(MONSTER); - zip.putInt(moveCount); -} - -TemporaryAi::TemporaryAi(int nbTurns) : nbTurns(nbTurns) { } -/* RIGHT HERE */ - -ConfusedMonsterAi::ConfusedMonsterAi(int nbTurns, Ai *oldAi) - : nbTurns(nbTurns), oldAi(oldAi) { } -void ConfusedMonsterAi::update(Actor *owner) { - TCODRandom *rng = TCODRandom::getInstance(); - int dx = rng->getInt(-1, 1); - int dy = rng->getInt(-1, 1); - if(dx != 0 || dy != 0) { - int destx = owner->x + dx; - int desty = owner->y + dy; - if(engine.map->canWalk(destx, desty)) { - owner->x = destx; - owner->y = desty; - } else { - Actor *actor = engine.getActor(destx, desty); - if(actor) { - owner->attacker->attack(owner, actor); - } - } - } - nbTurns--; - if(nbTurns == 0) { - owner->ai = oldAi; - delete this; - } -} -void ConfusedMonsterAi::load(TCODZip &zip) { - nbTurns=zip.getInt(); - oldAi=Ai::create(zip); -} -void ConfusedMonsterAi::save(TCODZip &zip) { - zip.putInt(CONFUSED_MONSTER); - zip.putInt(nbTurns); - oldAi->save(zip); -} diff --git a/src/Ai.hpp b/src/Ai.hpp index 15eb92f..d9f943c 100644 --- a/src/Ai.hpp +++ b/src/Ai.hpp @@ -20,11 +20,12 @@ public : protected : bool moveOrAttack(Actor *owner, int targetx, int targety); void handleActionKey(Actor *owner, int ascii); - Actor *choseFromInventory(Actor *owner); + Actor *chooseFromInventory(Actor *owner); }; class MonsterAi : public Ai { public : + MonsterAi(); void update(Actor *owner); void load(TCODZip &zip); void save(TCODZip &zip); @@ -38,18 +39,15 @@ public: TemporaryAi(int nbTurns); void update(Actor *owner); void applyTo(Actor *actor); -protected: - int nbTurns; - Ai *oldAi; -}; - -class ConfusedMonsterAi : public Ai { -public: - ConfusedMonsterAi(int nbTurns, Ai *oldAi); - void update(Actor *owner); void load(TCODZip &zip); void save(TCODZip &zip); protected: int nbTurns; Ai *oldAi; }; + +class ConfusedMonsterAi : public TemporaryAi { +public: + ConfusedMonsterAi(int nbTurns); + void update(Actor *owner); +}; diff --git a/src/Map.cpp b/src/Map.cpp index 5fd7e4e..2323f81 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -178,28 +178,41 @@ void Map::addItem(int x, int y) { Actor *healthPotion = new Actor(x, y, '!', "Health Potion", TCODColor::violet); healthPotion->blocks=false; - healthPotion->pickable=new Healer(4); + healthPotion->pickable=new Pickable(NULL, new HealthEffect(4, NULL)); engine.actors.push(healthPotion); } else if(dice < 70 + 10) { // Create a scroll of lightning bolt Actor *scrollOfLightningBolt = new Actor(x, y, '#', "Scroll of lightning bolt", TCODColor::lightYellow); scrollOfLightningBolt->blocks = false; - scrollOfLightningBolt->pickable = new LightningBolt(5, 20); + scrollOfLightningBolt->pickable = new Pickable( + new TargetSelector(TargetSelector::CLOSEST_MONSTER, 5), + new HealthEffect(-20, "A lightning bolt strikes the %s with a loud CRACK!\n" + "The damage is %g hit points." + ) + ); engine.actors.push(scrollOfLightningBolt); } else if(dice < 70 + 10 + 10) { // Create a scroll of fireball Actor *scrollOfFireball = new Actor(x, y, '#', "Scroll of fireball", TCODColor::lightYellow); scrollOfFireball->blocks = false; - scrollOfFireball->pickable = new Fireball(3, 12); + scrollOfFireball->pickable = new Pickable( + new TargetSelector(TargetSelector::SELECTED_RANGE, 3), + new HealthEffect(-12, "The %s gets burned for %g points.") + ); engine.actors.push(scrollOfFireball); } else { // create a scroll of confusion Actor *scrollOfConfusion = new Actor(x, y, '#', "Scroll of confusion", TCODColor::lightYellow); scrollOfConfusion->blocks=false; - scrollOfConfusion->pickable = new Confuser(10,8); + scrollOfConfusion->pickable = new Pickable( + new TargetSelector(TargetSelector::SELECTED_MONSTER, 5), + new AiChangeEffect(new ConfusedMonsterAi(10), + "The eyes of the %s look vacant,\nas it starts to stumble around." + ) + ); engine.actors.push(scrollOfConfusion); } } diff --git a/src/Pickable.cpp b/src/Pickable.cpp index 0a2bd41..8035910 100644 --- a/src/Pickable.cpp +++ b/src/Pickable.cpp @@ -1,49 +1,6 @@ #include "main.hpp" -bool Pickable::pick(Actor *owner, Actor *wearer) { - if(wearer->container && wearer->container->add(owner)) { - engine.actors.remove(owner); - return true; - } - return false; -} - -bool Pickable::use(Actor *owner, Actor *wearer) { - if(wearer->container) { - wearer->container->remove(owner); - delete owner; - return true; - } - return false; -} - -void Pickable::drop(Actor *owner, Actor *wearer) { - if(wearer->container) { - wearer->container->remove(owner); - engine.actors.push(owner); - owner->x = wearer->x; - owner->y = wearer->y; - engine.gui->message(TCODColor::lightGrey, "%s drops a %s.", - wearer->name, owner->name); - } -} - -/* Pickable Factory */ -Pickable *Pickable::create(TCODZip &zip) { - PickableType type=(PickableType)zip.getInt(); - Pickable *pickable=NULL; - switch(type) { - case HEALER: pickable = new Healer(0); break; - case LIGHTNING_BOLT: pickable = new LightningBolt(0, 0); break; - case CONFUSER: pickable = new Confuser(0, 0); break; - case FIREBALL: pickable = new Fireball(0, 0); break; - } - pickable->load(zip); - return pickable; -} - -TargetSelector::TargetSelector(SelectorType type, float range) : - type(type), range(range) { } +TargetSelector::TargetSelector(SelectorType type, float range) : type(type), range(range) { } void TargetSelector::selectTargets(Actor *wearer, TCODList & list) { switch(type) { case CLOSEST_MONSTER: { @@ -95,114 +52,34 @@ void TargetSelector::selectTargets(Actor *wearer, TCODList & list) { } } -/* Sub-Pickables */ -Healer::Healer(float amount) : amount(amount) { } -bool Healer::use(Actor *owner, Actor *wearer) { - if(wearer->destructible) { - float amountHealed = wearer->destructible->heal(amount); - if(amountHealed > 0) { - return Pickable::use(owner, wearer); - } +void TargetSelector::save(TCODZip &zip) { + int persistType = 0; + switch(type) { + case CLOSEST_MONSTER: persistType = 1; break; + case SELECTED_MONSTER: persistType = 2; break; + case WEARER_RANGE: persistType = 3; break; + case SELECTED_RANGE: persistType = 4; break; } - return false; -} -void Healer::load(TCODZip &zip) { - amount=zip.getFloat(); -} -void Healer::save(TCODZip &zip) { - zip.putInt(HEALER); - zip.putFloat(amount); -} - -LightningBolt::LightningBolt(float range, float damage) - : range(range), damage(damage) { } -bool LightningBolt::use(Actor *owner, Actor *wearer) { - Actor *closestMonster = engine.getClosestMonster( - wearer->x, wearer->y, range); - if(!closestMonster) { - engine.gui->message(TCODColor::lightGrey, "No enemy is close enough to strike."); - return false; - } - // Hit closest monster for hit points - engine.gui->message(TCODColor::lightBlue, - "A lightning bolt strikes the %s with a loud thunder!\nThe damage is %g hit points.", - closestMonster->name, damage); - closestMonster->destructible->takeDamage(closestMonster, damage); - return Pickable::use(owner, wearer); -} -void LightningBolt::load(TCODZip &zip) { - range=zip.getFloat(); - damage=zip.getFloat(); -} -void LightningBolt::save(TCODZip &zip) { - zip.putInt(LIGHTNING_BOLT); - zip.putFloat(range); - zip.putFloat(damage); -} - -Fireball::Fireball(float range, float damage) - : LightningBolt(range, damage) { } -bool Fireball::use(Actor *owner, Actor *wearer) { - engine.gui->message(TCODColor::cyan, "Left-click a target tile for the fireball,\nor right-click to cancel."); - int x, y; - if(!engine.pickATile(&x, &y)) { - return false; - } - // Burn everything in (including player) - engine.gui->message(TCODColor::orange, "The fireball explodes, burning everything within %g tiles!", range); - for(Actor **iterator=engine.actors.begin(); - iterator != engine.actors.end(); iterator++) { - Actor *actor = *iterator; - if(actor->destructible && !actor->destructible->isDead() - && actor->getDistance(x, y) <= range) { - engine.gui->message(TCODColor::orange, "The %s gets burned for %g hit points.", - actor->name, damage); - actor->destructible->takeDamage(actor, damage); - } - } - return Pickable::use(owner, wearer); -} -void Fireball::save(TCODZip &zip) { - zip.putInt(FIREBALL); - zip.putFloat(range); - zip.putFloat(damage); -} - -Confuser::Confuser(int nbTurns, float range) - : nbTurns(nbTurns), range(range) { } -bool Confuser::use(Actor *owner, Actor *wearer) { - engine.gui->message(TCODColor::cyan, "Left-click an enemy to confuse it,\nor right-click to cancel."); - int x, y; - if(!engine.pickATile(&x, &y, range)) { - return false; - } - Actor *actor = engine.getActor(x, y); - if(!actor) { - return false; - } - // Confuse the monster for turns - Ai *confusedAi = new ConfusedMonsterAi(nbTurns, actor->ai); - actor->ai = confusedAi; - engine.gui->message(TCODColor::lightGreen, "The eyes of the %s look vacant,\nas he starts to stumble around!", actor->name); - return Pickable::use(owner, wearer); -} -void Confuser::load(TCODZip &zip) { - nbTurns=zip.getInt(); - range=zip.getFloat(); -} -void Confuser::save(TCODZip &zip) { - zip.putInt(CONFUSER); - zip.putInt(nbTurns); + zip.putInt(persistType); zip.putFloat(range); } -HealthEffect::HealthEffect(float amount, const char *message) - : amount(amount), message(message) { } +void TargetSelector::load(TCODZip &zip) { + int persistType = zip.getInt(); + switch(persistType) { + case 1: type = CLOSEST_MONSTER; break; + case 2: type = SELECTED_MONSTER; break; + case 3: type = WEARER_RANGE; break; + case 4: type = SELECTED_RANGE; break; + } + range = zip.getFloat(); +} +HealthEffect::HealthEffect(float amount, const char *message) : amount(amount), message(message) { } bool HealthEffect::applyTo(Actor *actor) { if(!actor->destructible) return false; if(amount > 0) { - float pointsHealed = actor->destructible->heal(amount); + float pointsHealed=actor->destructible->heal(amount); if(pointsHealed > 0) { if(message) { engine.gui->message(TCODColor::lightGrey, message, actor->name, pointsHealed); @@ -211,7 +88,7 @@ bool HealthEffect::applyTo(Actor *actor) { } } else { if(message && -amount-actor->destructible->defense > 0) { - engine.gui->message(TCODColor::lightGrey, message, actor->name, + engine.gui->message(TCODColor::lightGrey, message, actor->name, -amount-actor->destructible->defense); } if(actor->destructible->takeDamage(actor, -amount) > 0) { @@ -220,3 +97,92 @@ bool HealthEffect::applyTo(Actor *actor) { } return false; } + +AiChangeEffect::AiChangeEffect(TemporaryAi *newAi, const char *message) : + newAi(newAi), message(message) { } +bool AiChangeEffect::applyTo(Actor *actor) { + newAi->applyTo(actor); + if(message) { + engine.gui->message(TCODColor::lightGrey, message, actor->name); + } + return true; +} + +Pickable::Pickable(TargetSelector *selector, Effect *effect) + : selector(selector), effect(effect) { } +Pickable::~Pickable() { + if(selector) delete selector; + if(effect) delete effect; +} + +bool Pickable::pick(Actor *owner, Actor *wearer) { + if(wearer->container && wearer->container->add(owner)) { + engine.actors.remove(owner); + return true; + } + return false; +} + +void Pickable::drop(Actor *owner, Actor *wearer) { + if(wearer->container) { + wearer->container->remove(owner); + engine.actors.push(owner); + owner->x = wearer->x; + owner->y = wearer->y; + engine.gui->message(TCODColor::lightGrey, "%s drops a %s.", + wearer->name, owner->name); + } +} + +bool Pickable::use(Actor *owner, Actor *wearer) { + TCODList list; + if(selector) { + selector->selectTargets(wearer, list); + } else { + list.push(wearer); + } + bool succeed=false; + for(Actor **it=list.begin(); it!=list.end(); it++) { + if(effect->applyTo(*it)) { + succeed=true; + } + } + if(succeed) { + if(wearer->container) { + wearer->container->remove(owner); + delete owner; + } + } + return succeed; +} + +void Pickable::save(TCODZip &zip) { + zip.putInt(selector != NULL); + zip.putInt(effect != NULL); + if(selector) selector->save(zip); + //if(effect) effect->save(zip); +} + +void Pickable::load(TCODZip &zip) { + bool hasSelector = zip.getInt(); + bool hasEffect = zip.getInt(); + if(hasSelector) { + selector = new TargetSelector(TargetSelector::CLOSEST_MONSTER, 0); + selector->load(zip); + } +/* + if(hasEffect) { + effect = new Effect(); + effect->load(zip); + } +*/ +} + + +/* Pickable Factory */ +Pickable *Pickable::create(TCODZip &zip) { + Pickable *pickable=NULL; + pickable->load(zip); + return pickable; +} + diff --git a/src/Pickable.hpp b/src/Pickable.hpp index aca9876..cc8ca80 100644 --- a/src/Pickable.hpp +++ b/src/Pickable.hpp @@ -1,4 +1,4 @@ -class TargetSelector { +class TargetSelector : public Persistent { public: enum SelectorType { CLOSEST_MONSTER, @@ -8,63 +8,35 @@ public: }; TargetSelector(SelectorType type, float range); void selectTargets(Actor *wearer, TCODList& list); + void save(TCODZip &zip); + void load(TCODZip &zip); + protected: SelectorType type; float range; }; -class Effect { +class Effect /*: public Persistent */{ public: virtual bool applyTo(Actor *actor) = 0; +// void save(TCODZip &zip); +// void load(TCODZip &zip); }; class Pickable : public Persistent { public: + Pickable(TargetSelector *selector, Effect *effect); + virtual ~Pickable(); bool pick(Actor *owner, Actor *wearer); void drop(Actor *owner, Actor *wearer); - virtual bool use(Actor *owner, Actor *wearer); + bool use(Actor *owner, Actor *wearer); static Pickable *create(TCODZip &zip); + void save(TCODZip &zip); + void load(TCODZip &zip); + protected: - enum PickableType { - HEALER, LIGHTNING_BOLT, CONFUSER, FIREBALL - }; -}; - -/* Sub-Pickables */ -class Healer : public Pickable { -public: - float amount; // how much? - Healer(float amount); - bool use(Actor *owner, Actor *wearer); - void load(TCODZip &zip); - void save(TCODZip &zip); -}; - -/* Aggro Spells */ -class LightningBolt: public Pickable { -public: - float range, damage; - LightningBolt(float range, float damage); - bool use(Actor *owner, Actor *wearer); - void load(TCODZip &zip); - void save(TCODZip &zip); -}; - -class Fireball : public LightningBolt { -public: - Fireball(float range, float damage); - bool use(Actor *owner, Actor *wearer); - void save(TCODZip &zip); -}; - -class Confuser : public Pickable { -public: - int nbTurns; - float range; - Confuser(int nbTurns, float range); - bool use(Actor *owner, Actor *wearer); - void load(TCODZip &zip); - void save(TCODZip &zip); + TargetSelector *selector; + Effect *effect; }; /* Effects */ @@ -76,3 +48,11 @@ public: bool applyTo(Actor *actor); }; +class AiChangeEffect : public Effect { +public: + TemporaryAi *newAi; + const char *message; + + AiChangeEffect(TemporaryAi *newAi, const char *message); + bool applyTo(Actor *actor); +}; diff --git a/src/main.hpp.gch b/src/main.hpp.gch index c4830af..14d734c 100644 Binary files a/src/main.hpp.gch and b/src/main.hpp.gch differ