diff --git a/build.xml b/build.xml index 5ff1538..9ef6936 100644 --- a/build.xml +++ b/build.xml @@ -1,59 +1,66 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/no/arcticdrakefox/wolfbot/management/GameCore.java b/src/no/arcticdrakefox/wolfbot/management/GameCore.java index d40fc5e..6e190d4 100644 --- a/src/no/arcticdrakefox/wolfbot/management/GameCore.java +++ b/src/no/arcticdrakefox/wolfbot/management/GameCore.java @@ -24,6 +24,7 @@ import com.google.common.collect.Collections2; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; public class GameCore { public static void lynchVote(String senderS, String targetS, WolfBotModel data, MessageType type) { @@ -54,6 +55,8 @@ public static void lynchVote(String senderS, String targetS, WolfBotModel data, endDay(true, data); } + + public static void drop(String name, String sender, WolfBotModel data){ if (data.getState() == State.None || data.getState() == State.Starting) { @@ -234,7 +237,7 @@ public static void startNight(WolfBotModel data) { public static void endNight(WolfBotModel data) { // Kill the timer first: endNightTimer.cancel(); // Javadoc says this is safe when called by a TimerTask. We'll see. - killWolfVote(data); + calculateNightKills(data); data.getWolfBot().sendNightEndMessages(); checkDead(data); if (!checkVictory(data)) @@ -304,36 +307,88 @@ public int compare(Player o1, Player o2) } } - public static void killWolfVote(WolfBotModel data) { - Player wolfVote = data.getPlayers().getVote(true); - if (wolfVote != null) { - Player baner = data.getPlayers().getPlayerTargeting(wolfVote, - Role.baner); - if (baner != null) { - wolfVote = null; - if (baner.getVote().equals(baner)) { - data.getWolfBot().sendIrcMessage( - baner.getName(), - Messages.getString("GameCore.vigilanti.multualTarget")); //$NON-NLS-1$ - } else { - data.getWolfBot().sendIrcMessage( - baner.getName(), Messages.getString("GameCore.vigilanti.killWolf", //$NON-NLS-1$ - baner.getVote())); + + + /** + * + * @param data + */ + public static void calculateNightKills(WolfBotModel data) { + Collection> kills = Sets.newHashSet(); + + + // Wolf stuff. + { + Player wolfVote = data.getPlayers().getVote(true); + String deathMessage; + if (WolfBotModel.getInstance().getSilentMode()) { + deathMessage = Messages.getString("GameCore.wolfKill.noReveal", //$NON-NLS-1$ + bold(wolfVote.getName())); + } else { + deathMessage = Messages.getString("GameCore.wolfKill.reveal", //$NON-NLS-1$ + bold(wolfVote.getName()), wolfVote.getRole().toStringColor()); + } + + kills.add(new Pair(wolfVote,deathMessage)); + } + + List livingPlayers = data.getPlayers().getLivingPlayers(); + + ret_k: + for (Player p : livingPlayers) { + Pair kill = p.kill(data.getState()); + if (kill != null) { + for (Pair k : kills) { + if (k.fst().equals(kill.fst())) continue ret_k; } + kills.add(kill); } } - if (wolfVote == null - || data.getPlayers().getPlayerTargeting(wolfVote, Role.baner) != null) { + + for (Player p : livingPlayers) { + p.save(data.getState(), kills); + } + + + if (kills.isEmpty()) { data.getWolfBot().sendIrcMessage(data.getChannel(), Messages.getString("GameCore.noWolfKill")); //$NON-NLS-1$ } else { - if (WolfBotModel.getInstance().getSilentMode()) { - wolfVote.die(Messages.getString("GameCore.wolfKill.noReveal", //$NON-NLS-1$ - bold(wolfVote.getName()))); - } else { - wolfVote.die(Messages.getString("GameCore.wolfKill.reveal", //$NON-NLS-1$ - bold(wolfVote.getName()), wolfVote.getRole().toStringColor())); + for(Pair k: kills) { + k.fst().die(k.snd()); } } + + +// +// if (wolfVote != ns) { +// Player baner = data.getPlayers().getPlayerTargeting(wolfVote, +// Role.baner); +// if (baner != null) { +// wolfVote = null; +// if (baner.getVote().equals(baner)) { +// data.getWolfBot().sendIrcMessage( +// baner.getName(), +// Messages.getString("GameCore.vigilanti.multualTarget")); //$NON-NLS-1$ +// } else { +// data.getWolfBot().sendIrcMessage( +// baner.getName(), Messages.getString("GameCore.vigilanti.killWolf", //$NON-NLS-1$ +// baner.getVote())); +// } +// } +// } +// if (wolfVote == null +// || data.getPlayers().getPlayerTargeting(wolfVote, Role.baner) != null) { +// data.getWolfBot().sendIrcMessage(data.getChannel(), +// Messages.getString("GameCore.noWolfKill")); //$NON-NLS-1$ +// } else { +// if (WolfBotModel.getInstance().getSilentMode()) { +// wolfVote.die(Messages.getString("GameCore.wolfKill.noReveal", //$NON-NLS-1$ +// bold(wolfVote.getName()))); +// } else { +// wolfVote.die(Messages.getString("GameCore.wolfKill.reveal", //$NON-NLS-1$ +// bold(wolfVote.getName()), wolfVote.getRole().toStringColor())); +// } +// } } } \ No newline at end of file diff --git a/src/no/arcticdrakefox/wolfbot/management/Messages.java b/src/no/arcticdrakefox/wolfbot/management/Messages.java index 86c6a2b..8f5955a 100644 --- a/src/no/arcticdrakefox/wolfbot/management/Messages.java +++ b/src/no/arcticdrakefox/wolfbot/management/Messages.java @@ -27,7 +27,7 @@ public static String getString(String key, Object... args) { try { return MessageFormat.format(RESOURCE_BUNDLE.getString(key), args); } catch (MissingResourceException ex) { - return "Missing String in properties file."; + return "Missing String in properties file. \"" + key + "\" not found."; } } } diff --git a/src/no/arcticdrakefox/wolfbot/management/Pair.java b/src/no/arcticdrakefox/wolfbot/management/Pair.java new file mode 100644 index 0000000..7b4f7ae --- /dev/null +++ b/src/no/arcticdrakefox/wolfbot/management/Pair.java @@ -0,0 +1,51 @@ +package no.arcticdrakefox.wolfbot.management; + +public class Pair { + T1 a; + T2 b; + + public Pair(T1 a, T2 b) { + super(); + this.a = a; + this.b = b; + } + + public T1 fst() { + return a; + } + + public T2 snd() { + return b; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((a == null) ? 0 : a.hashCode()); + result = prime * result + ((b == null) ? 0 : b.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Pair other = (Pair) obj; + if (a == null) { + if (other.a != null) + return false; + } else if (!a.equals(other.a)) + return false; + if (b == null) { + if (other.b != null) + return false; + } else if (!b.equals(other.b)) + return false; + return true; + } +} \ No newline at end of file diff --git a/src/no/arcticdrakefox/wolfbot/management/Player.java b/src/no/arcticdrakefox/wolfbot/management/Player.java index f6855eb..7be9493 100644 --- a/src/no/arcticdrakefox/wolfbot/management/Player.java +++ b/src/no/arcticdrakefox/wolfbot/management/Player.java @@ -1,6 +1,9 @@ package no.arcticdrakefox.wolfbot.management; +import java.util.Collection; + import no.arcticdrakefox.wolfbot.model.Role; +import no.arcticdrakefox.wolfbot.model.State; public abstract class Player { @@ -55,4 +58,16 @@ protected final String targetNotFound(String name){ public abstract String nightEnd(); public abstract String helpText(); + + /** + * Does this player kill someone? + * @param time + * @return + */ + public Pair kill(State time) { + return null; + } + + public void save(State time, Collection> players) { } + } \ No newline at end of file diff --git a/src/no/arcticdrakefox/wolfbot/model/Role.java b/src/no/arcticdrakefox/wolfbot/model/Role.java index e8b542d..45272ad 100644 --- a/src/no/arcticdrakefox/wolfbot/model/Role.java +++ b/src/no/arcticdrakefox/wolfbot/model/Role.java @@ -7,6 +7,7 @@ import no.arcticdrakefox.wolfbot.roles.ApprenticeScry; import no.arcticdrakefox.wolfbot.roles.AuraScry; import no.arcticdrakefox.wolfbot.roles.Baner; +import no.arcticdrakefox.wolfbot.roles.BodyGuard; import no.arcticdrakefox.wolfbot.roles.Devil; import no.arcticdrakefox.wolfbot.roles.Diseased; import no.arcticdrakefox.wolfbot.roles.Ghost; @@ -24,6 +25,7 @@ import org.jibble.pircbot.Colors; public enum Role { + bodyguard (BodyGuard.class, Team.Villagers), villager (Villager.class, Team.Villagers), wolf (Wolf.class, Team.Wolves), scry (Scry.class, Team.Villagers), diff --git a/src/no/arcticdrakefox/wolfbot/roles/Baner.java b/src/no/arcticdrakefox/wolfbot/roles/Baner.java index 933e832..e1226b2 100644 --- a/src/no/arcticdrakefox/wolfbot/roles/Baner.java +++ b/src/no/arcticdrakefox/wolfbot/roles/Baner.java @@ -1,9 +1,14 @@ package no.arcticdrakefox.wolfbot.roles; +import java.util.Collection; +import java.util.Iterator; + import no.arcticdrakefox.wolfbot.management.Messages; import no.arcticdrakefox.wolfbot.management.Player; import no.arcticdrakefox.wolfbot.management.PlayerList; import no.arcticdrakefox.wolfbot.model.Role; +import no.arcticdrakefox.wolfbot.model.State; +import no.arcticdrakefox.wolfbot.management.Pair; public class Baner extends Player { @@ -60,6 +65,19 @@ public String nightAction(String message, PlayerList players) { return null; } + + @Override + public void save(State time, Collection> players) { + super.save(time, players); + + for (Iterator> iterator = players.iterator(); iterator.hasNext();) { + Pair pair = (Pair) iterator.next(); + if (pair.fst().equals(getVote())) { + players.remove(pair); + } + } + } + @Override public String nightEnd() { return null; diff --git a/src/no/arcticdrakefox/wolfbot/roles/BodyGuard.java b/src/no/arcticdrakefox/wolfbot/roles/BodyGuard.java new file mode 100644 index 0000000..b6b46f7 --- /dev/null +++ b/src/no/arcticdrakefox/wolfbot/roles/BodyGuard.java @@ -0,0 +1,78 @@ +package no.arcticdrakefox.wolfbot.roles; + +import no.arcticdrakefox.wolfbot.management.Messages; +import no.arcticdrakefox.wolfbot.management.Player; +import no.arcticdrakefox.wolfbot.management.PlayerList; +import no.arcticdrakefox.wolfbot.model.Role; + +public class BodyGuard extends Player { + + Player lastTarget = null; + + public BodyGuard(String name){ + super(name); + } + + @Override + public boolean isWolf() { + return false; + } + + @Override + public Role getRole() { + return Role.bodyguard; + } + + @Override + public String roleInfo(PlayerList players) { + return Messages.getString("BodyGuard.description"); //$NON-NLS-1$ + } + + @Override + public String nightStart() { + isReady = false; + return Messages.getString("BodyGuard.nightInstructions"); //$NON-NLS-1$ + } + + @Override + public String nightAction(String message, PlayerList players) { + String[] args = message.trim().split(" ", 2); //$NON-NLS-1$ + if (args[0].equals("!bane")){ //$NON-NLS-1$ + if (args.length != 2) + return Messages.getString("BodyGuard.correctUsage"); //$NON-NLS-1$ + Player target = players.getPlayer(args[1]); + if (target == null) + return targetNotFound(args[1]); + else if (target == lastTarget) { + return Messages.getString("BodyGuard.sameTarget"); + } else { + if (target.isAlive()){ + vote(target); + lastTarget= target; + isReady = true; + if (target.equals(this)) + return Messages.getString("BodyGuard.selfGuard"); //$NON-NLS-1$ + else + return Messages.getString("BodyGuard.guard", new Object[] {target}); //$NON-NLS-1$ + } else + return Messages.getString("BodyGuard.tooLate", new Object[] {target}); //$NON-NLS-1$ + } + } else if (args[0].equals("!rest")){ //$NON-NLS-1$ + lastTarget = null; + isReady = true; + vote = null; + return Messages.getString("BodyGuard.rest"); //$NON-NLS-1$ + } else + return null; + } + + @Override + public String nightEnd() { + return null; + } + + @Override + public String helpText() { + return Messages.getString("BodyGuard.help"); //$NON-NLS-1$ + } +} diff --git a/src/no/arcticdrakefox/wolfbot/roles/messages.properties b/src/no/arcticdrakefox/wolfbot/roles/messages.properties index 3b69a53..6a72961 100644 --- a/src/no/arcticdrakefox/wolfbot/roles/messages.properties +++ b/src/no/arcticdrakefox/wolfbot/roles/messages.properties @@ -61,6 +61,17 @@ Baner.selfBane=You fortify your defenses and set up traps. The wolves will never Baner.tooLate=You are too late to save {0}, they are dead already. +BodyGuard.guard=You don your shades. {0} will not die on your watch\! +BodyGuard.correctUsage=Correct usage: \!guard +BodyGuard.description=You are a BodyGuard, you can protect a player from harm. You must chose a diffrent player each night. +BodyGuard.help=The BodyGuard can protect a member of the village each night, including themselves. That player will not die this turn. +BodyGuard.nightInstructions=It''s time. \!guard a player or \!rest +BodyGuard.rest=You give up. The village can die for all you care. +BodyGuard.selfGuard=You fortify your defenses and set up traps. The wolves will never catch you\! +BodyGuard.sameTarget=You can't target the same person two nights in a row. +!{0} = TARGET +BodyGuard.tooLate=You are too late to save {0}, they are dead already. + #Devil Devil.intro=You are a devil, an evil creature. You may check a person''s role each night, or sacrifice someone. The wolves are {0}, and you are on their side\! Devil.multipleScryError=You may only scry one person each night. @@ -136,7 +147,7 @@ Vigilante.help=The vigilante can attempt to \!kill someone at night - hopefully Vigilante.intro=You are the vigilante, capable of enforcing justice on your own at night. Vigilante.killed.reveal=As the villagers search {0}''s home, they find a silver blade stuck in their throat. A vigilante struck down this {1} tonight\! -Vigilante.killed.noveal=As the villagers search {0}''s home, they find a silver blade stuck in their throat. A vigilante struck tonight\! +Vigilante.killed.noreveal=As the villagers search {0}''s home, they find a silver blade stuck in their throat. A vigilante struck tonight\! Vigilante.KilledFirst=Under the cover of darkness, you open {0}''s door, but before you can step in you feel a searing pain running down your back. As your slump around on the ground, a large, gnarling shadow stands above you... Vigilante.KilledInnosent=Under the cover of darkness, you hide behind {0}''s bedroom door and jab a silver knife in their throat as they pass. As they lay bleeding, you realize that you have taken an innocent life. You mutter a respectful prayer and head home sullenly. @@ -203,6 +214,8 @@ GameCore.retired.someoneElse=-{0} cut off {1}''s arm. {2} retires from the game. GameCore.skip.count=2 GameCore.skip.0=The villagers can''t agree on who to lynch and decide to drink beer instead. Hurrah\! GameCore.skip.1=The villagers go for a swim instead of lynching people today. +GameCore.skip.2=The villagers agree that they can't agree so go to bed instead of lyching. +GameCore.skip.3=With so many \!skip votes the villagers agree to skip on home. GameCore.startCancled=Start cancelled. GameCore.thanks=Thanks for playing\! Say \!start to go again\!