package rltut; public class Effect { protected int duration; public boolean isDone() { return duration < 1; } public Effect(int duration){ this.duration = duration; } public void update(Creature creature){ duration--; } public void start(Creature creature){ } public void end(Creature creature){ } }
And add a quaffEffect to Item class.
private Effect quaffEffect; public Effect quaffEffect() { return quaffEffect; } public void setQuaffEffect(Effect effect) { this.quaffEffect = effect; }
Now that we've got items that can have effects when quaffed it's time to add some potions to our StuffFactory. I'll start with three simple ones that show three ways of doing things.
Here's a simple one-time potion where the work happens in the start method:
public Item newPotionOfHealth(int depth){ Item item = new Item('!', AsciiPanel.white, "health potion"); item.setQuaffEffect(new Effect(1){ public void start(Creature creature){ if (creature.hp() == creature.maxHp()) return; creature.modifyHp(15); creature.doAction("look healthier"); } }); world.addAtEmptyLocation(item, depth); return item; }
Here is a potion that affects the creature each turn.
public Item newPotionOfPoison(int depth){ Item item = new Item('!', AsciiPanel.white, "poison potion"); item.setQuaffEffect(new Effect(20){ public void start(Creature creature){ creature.doAction("look sick"); } public void update(Creature creature){ super.update(creature); creature.modifyHp(-1); } }); world.addAtEmptyLocation(item, depth); return item; }
Here's one that will affect the creature at the start and restore it at the end.
public Item newPotionOfWarrior(int depth){ Item item = new Item('!', AsciiPanel.white, "warrior's potion"); item.setQuaffEffect(new Effect(20){ public void start(Creature creature){ creature.modifyAttackValue(5); creature.modifyDefenseValue(5); creature.doAction("look stronger"); } public void end(Creature creature){ creature.modifyAttackValue(-5); creature.modifyDefenseValue(-5); creature.doAction("look less strong"); } }); world.addAtEmptyLocation(item, depth); return item; }
And add a randomizer to help us add the new potions.
public Item randomPotion(int depth){ switch ((int)(Math.random() * 3)){ case 0: return newPotionOfHealth(depth); case 1: return newPotionOfPoison(depth); default: return newPotionOfWarrior(depth); } }
Now let's go back to the creature class and make sure it's calling the right methods at the right times. It will need a list of effects that are currently applied to it.
private List<Effect> effects; public ListList<Effect> effects(){ return effects; }
Don't forget to initialize it in the creature's constructor.
Add quaff method to Creature class. Since they're so similar, the quaff and eat methods can share some code.
public void quaff(Item item){ doAction("quaff a " + item.name()); consume(item); } public void eat(Item item){ doAction("eat a " + item.name()); consume(item); } private void consume(Item item){ if (item.foodValue() < 0) notify("Gross!"); addEffect(item.quaffEffect()); modifyFood(item.foodValue()); getRidOf(item); } private void addEffect(Effect effect){ if (effect == null) return; effect.start(this); effects.add(effect); }
Create a new method to update the effects each turn and remove any that are done. Don't forget to call the end method before removing the effect.
private void updateEffects(){ List<Effect> done = new ArrayList<Effect>(); for (Effect effect : effects){ effect.update(this); if (effect.isDone()) { effect.end(this); done.add(effect); } } effects.removeAll(done); }
Call this during the creature's update method. The player can't quaff anything until we create a QuaffScreen to go with our new behavior.
package rltut.screens; import rltut.Creature; import rltut.Item; public class QuaffScreen extends InventoryBasedScreen { public QuaffScreen(Creature player) { super(player); } protected String getVerb() { return "quaff"; } protected boolean isAcceptable(Item item) { return item.quaffEffect() != null; } protected Screen use(Item item) { player.quaff(item); return null; } }
I think I've said this before but that InventoryBasedScreen is really paying off. Now bind that to the 'q' key in the PlayScreen class and update the createItems method, also in the PlayScreen class, to add some potions. Try 3 or 4 per level to start with. Don't forget to update the HelpScreen too. Play around and change the durations or strengths or abundance of potions. Try adding some new ones that change the vision radius, heal over time, stop regeneration, consume extra food, or fill someone's stomach. I'm sure you can think of even more potions and effects. There you go; potions and effects that are simple and flexible. We're going to add a few more effects in the next tutorial when we add magic.
Wouldn't it be cool if throwing a potion at a creature caused the effect to apply to it? Easy-peasy.
private void throwAttack(Item item, Creature other) { commonAttack(other, attackValue / 2 + item.thrownAttackValue(), "throw a %s at the %s for %d damage", item.name(), other.name); other.addEffect(item.quaffEffect()); }
Then make sure the throw method removes the item if it has a quaffEffect and the target was a creature, otherwise it should add to the world like it already does. Now you can sit back and chuck poison bottles at goblins.
download the code
We are of the firm view and the opinion regarding all those prospects and hopefully for he future these would govern better grounds to follow herewith. computer science research paper
ReplyDeleteMinor typo "public ListList effects(){ ..." should be "public List effects(){ ...". I really like the apperance of the anonymous subclass "technique" but it took me a while to parse it as I hadn't seen it yet in my squeaky new Java career.
ReplyDelete