diff --git a/src/main/java/com/comandante/creeper/entity/EntityManager.java b/src/main/java/com/comandante/creeper/entity/EntityManager.java index 2ef351a7b6cd1d3b133778b8235264c7d121af4f..3ca44ca907082f3a6d0f9e69fa206fd9e0f81c17 100644 --- a/src/main/java/com/comandante/creeper/entity/EntityManager.java +++ b/src/main/java/com/comandante/creeper/entity/EntityManager.java @@ -97,6 +97,11 @@ public class EntityManager { Map.Entry<String, Player> next = players.next(); ticketRunnerService.submit(next.getValue()); } + Iterator<Map.Entry<String, Npc>> entries = npcs.entrySet().iterator(); + while (entries.hasNext()) { + Map.Entry<String, Npc> next = entries.next(); + ticketRunnerService.submit(next.getValue()); + } } catch (InterruptedException ie) { throw new RuntimeException("Problem with ticker."); } diff --git a/src/main/java/com/comandante/creeper/fight/FightRun.java b/src/main/java/com/comandante/creeper/fight/FightRun.java index 8b59b2730bc02d009726a84f7e6585af8b57bcb1..e1d811aba84cb4495e3f59fa8d8b6b57419e79ae 100644 --- a/src/main/java/com/comandante/creeper/fight/FightRun.java +++ b/src/main/java/com/comandante/creeper/fight/FightRun.java @@ -36,11 +36,13 @@ public class FightRun implements Callable<FightResults> { gameManager.getPlayerManager().savePlayerMetadata(playerMetadata); - FightResults fightResults = new FightResultsBuilder().setNpcWon(false).setPlayerWon(false).createFightResults();; + FightResults fightResults = new FightResultsBuilder().setNpcWon(false).setPlayerWon(false).createFightResults(); + if (playerStats.getCurrentHealth() <= 0) { gameManager.getChannelUtils().write(player.getPlayerId(), "You died."); gameManager.getChannelUtils().writeToRoom(player.getPlayerId(), player.getPlayerName() + " is now dead."); + npc.setIsInFight(false); fightResults = new FightResultsBuilder().setNpcWon(true).setPlayerWon(false).createFightResults(); } diff --git a/src/main/java/com/comandante/creeper/npc/Derper.java b/src/main/java/com/comandante/creeper/npc/Derper.java index 56eb33a3cab5fddceb16d8d48622506213a9bc4a..b9210f721f7aad03f1dcec74c58b75d5dfa2845a 100644 --- a/src/main/java/com/comandante/creeper/npc/Derper.java +++ b/src/main/java/com/comandante/creeper/npc/Derper.java @@ -2,6 +2,9 @@ package com.comandante.creeper.npc; import com.comandante.creeper.managers.GameManager; +import com.comandante.creeper.room.Area; +import com.google.common.base.Optional; +import com.google.common.collect.Sets; import java.util.Arrays; import java.util.List; @@ -22,7 +25,7 @@ public class Derper extends Npc { public Derper(GameManager gameManager, Integer roomId) { - super(gameManager, roomId, NAME, colorName, 0, NpcStats.DERPER.createStats(), "derper's face is melted"); + super(gameManager, roomId, NAME, colorName, 0, NpcStats.DERPER.createStats(), "derper's face is melted", Optional.of(Sets.newHashSet(Area.NEWBIE_ZONE))); this.random = new Random(); } diff --git a/src/main/java/com/comandante/creeper/npc/DruggedPimp.java b/src/main/java/com/comandante/creeper/npc/DruggedPimp.java index 15aa39d1fdd3ac876a3693c9cf7fd6d7f13fabbe..cc53d4a8b7589218b5aedbd7d4799847ca6e82a5 100644 --- a/src/main/java/com/comandante/creeper/npc/DruggedPimp.java +++ b/src/main/java/com/comandante/creeper/npc/DruggedPimp.java @@ -1,6 +1,9 @@ package com.comandante.creeper.npc; import com.comandante.creeper.managers.GameManager; +import com.comandante.creeper.room.Area; +import com.google.common.base.Optional; +import com.google.common.collect.Sets; import java.util.Random; @@ -17,7 +20,7 @@ public class DruggedPimp extends Npc { .append(RESET).toString(); public DruggedPimp(GameManager gameManager, Integer roomId) { - super(gameManager, roomId, NAME, colorName, 0, NpcStats.DRUGGED_PIMP.createStats(), "a drugged pimp is dead and broke"); + super(gameManager, roomId, NAME, colorName, 0, NpcStats.DRUGGED_PIMP.createStats(), "a drugged pimp is dead and broke", Optional.of(Sets.newHashSet(Area.NEWBIE_ZONE))); this.random = new Random(); } diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java index dc85ee9ac6df74e7263ced0cb63934fdff307f85..992b889bb79531a1c517072c0ba57051552519a8 100644 --- a/src/main/java/com/comandante/creeper/npc/Npc.java +++ b/src/main/java/com/comandante/creeper/npc/Npc.java @@ -1,9 +1,15 @@ package com.comandante.creeper.npc; -import com.comandante.creeper.managers.GameManager; import com.comandante.creeper.entity.CreeperEntity; +import com.comandante.creeper.managers.GameManager; +import com.comandante.creeper.room.Area; import com.comandante.creeper.stat.Stats; +import com.google.common.base.Optional; + +import java.util.HashSet; +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import static com.comandante.creeper.server.Color.RED; import static com.comandante.creeper.server.Color.RESET; @@ -17,24 +23,33 @@ public abstract class Npc extends CreeperEntity { private long lastPhraseTimestamp; private final GameManager gameManager; - private final Integer roomId; + private Integer roomId; private final String name; private final String colorName; private final Stats stats; private final String dieMessage; + private final Optional<HashSet<Area>> roamAreas; + private AtomicBoolean isInFight = new AtomicBoolean(false); + Random random = new Random(); public abstract Npc create(GameManager gameManager, Integer roomId); @Override public void run() { - //System.out.println(getName() + " tick..."); + if (randInt(0, 100) < 2) { + if (!isInFight.get() && roamAreas.isPresent()) { + System.out.println("roam!" + getEntityId()); + NpcMover npcMover = new NpcMover(); + npcMover.roam(getGameManager(), getEntityId()); + } + } } public String getColorName() { return colorName; } - protected Npc(GameManager gameManager, Integer roomId, String name, String colorName, long lastPhraseTimestamp, Stats stats, String dieMessage) { + protected Npc(GameManager gameManager, Integer roomId, String name, String colorName, long lastPhraseTimestamp, Stats stats, String dieMessage, Optional<HashSet<Area>> roamAreas) { this.gameManager = gameManager; this.roomId = roomId; this.name = name; @@ -42,6 +57,19 @@ public abstract class Npc extends CreeperEntity { this.lastPhraseTimestamp = lastPhraseTimestamp; this.stats = stats; this.dieMessage = dieMessage; + this.roamAreas = roamAreas; + } + + public Optional<HashSet<Area>> getRoamAreas() { + return roamAreas; + } + + public boolean getIsInFight() { + return this.isInFight.get(); + } + + public void setIsInFight(boolean isInFight) { + this.isInFight.set(isInFight); } public Stats getStats() { @@ -68,6 +96,10 @@ public abstract class Npc extends CreeperEntity { return dieMessage; } + public void setRoomId(Integer roomId) { + this.roomId = roomId; + } + public void npcSay(Integer roomId, String message) { StringBuilder sb = new StringBuilder(); sb.append(RED); @@ -75,4 +107,8 @@ public abstract class Npc extends CreeperEntity { sb.append(RESET); } + private int randInt(int min, int max) { + return random.nextInt((max - min) + 1) + min; + } + } diff --git a/src/main/java/com/comandante/creeper/npc/NpcMover.java b/src/main/java/com/comandante/creeper/npc/NpcMover.java new file mode 100644 index 0000000000000000000000000000000000000000..d3278e985a81f1ebb3ea709e1821482b99b8eae7 --- /dev/null +++ b/src/main/java/com/comandante/creeper/npc/NpcMover.java @@ -0,0 +1,88 @@ +package com.comandante.creeper.npc; + +import com.comandante.creeper.managers.GameManager; +import com.comandante.creeper.room.Area; +import com.comandante.creeper.room.Room; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class NpcMover { + + static Random random = new Random(); + + public void roam(final GameManager gameManager, String npcId) { + final Npc npcEntity = gameManager.getEntityManager().getNpcEntity(npcId); + Integer roomId = npcEntity.getRoomId(); + Room npcCurrentRoom = gameManager.getRoomManager().getRoom(roomId); + Set<Integer> possibleExits = getPossibleExits(npcCurrentRoom); + Predicate<Integer> isRoamable = new Predicate<Integer>() { + @Override + public boolean apply(Integer roomId) { + Room room = gameManager.getRoomManager().getRoom(roomId); + for (Area roomArea : room.getAreas()) { + if (npcEntity.getRoamAreas().get().contains(roomArea)) { + return true; + } + } + return false; + } + }; + List<Integer> canRoam = Lists.newArrayList(Iterables.filter(possibleExits, isRoamable)); + int i = random.nextInt(canRoam.size()); + Integer destinationRoomId = canRoam.get(i); + String exitMessage = getExitMessage(npcCurrentRoom, destinationRoomId); + npcCurrentRoom.getNpcIds().remove(npcId); + gameManager.roomSay(npcCurrentRoom.getRoomId(), npcEntity.getName() + " " + exitMessage, ""); + gameManager.getRoomManager().getRoom(destinationRoomId).getNpcIds().add(npcId); + npcEntity.setRoomId(destinationRoomId); + gameManager.roomSay(destinationRoomId, npcEntity.getName() + " has arrived.", ""); + } + + public String getExitMessage(Room room, Integer exitRoomId) { + if (room.getUpId().isPresent() && room.getUpId().get().equals(exitRoomId)) { + return "exited up."; + } + if (room.getDownId().isPresent() && room.getDownId().get().equals(exitRoomId)) { + return "exited down."; + } + if (room.getNorthId().isPresent() && room.getNorthId().get().equals(exitRoomId)) { + return "exited to the north."; + } + if (room.getSouthId().isPresent() && room.getSouthId().get().equals(exitRoomId)) { + return "exited to the south."; + } + if (room.getEastId().isPresent() && room.getEastId().get().equals(exitRoomId)) { + return "exited to the east."; + } + if (room.getWestId().isPresent() && room.getWestId().get().equals(exitRoomId)) { + return "exited to the west.."; + } + return ""; + } + + public Set<Integer> getPossibleExits(Room room) { + List<Optional<Integer>> opts = Lists.newArrayList(); + opts.add(room.getDownId()); + opts.add(room.getUpId()); + opts.add(room.getNorthId()); + opts.add(room.getSouthId()); + opts.add(room.getEastId()); + opts.add(room.getWestId()); + + Set<Integer> exits = Sets.newHashSet(); + for (Optional<Integer> opt: opts) { + if (opt.isPresent()){ + exits.add(opt.get()); + } + } + return exits; + } + +} diff --git a/src/main/java/com/comandante/creeper/room/Area.java b/src/main/java/com/comandante/creeper/room/Area.java new file mode 100644 index 0000000000000000000000000000000000000000..2434eab6ffe6132cd065436818780ecb35ccce2e --- /dev/null +++ b/src/main/java/com/comandante/creeper/room/Area.java @@ -0,0 +1,6 @@ +package com.comandante.creeper.room; + +public enum Area { + DEFAULT, + NEWBIE_ZONE +} diff --git a/src/main/java/com/comandante/creeper/room/Room.java b/src/main/java/com/comandante/creeper/room/Room.java index 6d2a50bec06a22d93505ddd8670d1838a27045cd..ae3b032f1061ae1436ee75dad5729d326f72f8cc 100644 --- a/src/main/java/com/comandante/creeper/room/Room.java +++ b/src/main/java/com/comandante/creeper/room/Room.java @@ -28,7 +28,7 @@ public abstract class Room extends CreeperEntity { private final Set<String> itemIds = Sets.newConcurrentHashSet(); private List<ItemSpawner> itemSpawners = Lists.newArrayList(); private List<NpcSpawner> npcSpawners = Lists.newArrayList(); - + private Set<Area> areas = Sets.newHashSet(Area.DEFAULT); public Room(Integer roomId, String roomTitle, @@ -50,6 +50,14 @@ public abstract class Room extends CreeperEntity { this.roomDescription = roomDescription; } + public Set<Area> getAreas() { + return areas; + } + + public void setAreas(Set<Area> areas) { + this.areas = areas; + } + public String getRoomTitle() { return roomTitle; } diff --git a/src/main/java/com/comandante/creeper/room/RoomBuilders.java b/src/main/java/com/comandante/creeper/room/RoomBuilders.java index 0a7456e7a6a97f0275b542d0b69c7ef910e2ed40..e74903249371abff5578f08ab7a4f21323fc9b2e 100644 --- a/src/main/java/com/comandante/creeper/room/RoomBuilders.java +++ b/src/main/java/com/comandante/creeper/room/RoomBuilders.java @@ -9,6 +9,7 @@ import com.comandante.creeper.spawner.ItemSpawner; import com.comandante.creeper.spawner.NpcSpawner; import com.comandante.creeper.spawner.SpawnRule; import com.google.common.base.Optional; +import com.google.common.collect.Sets; /** * Created by Brian Kearney on 8/24/2014. @@ -33,10 +34,12 @@ public class RoomBuilders { basicRoom.addItemSpawner(new ItemSpawner(ItemType.KEY, new SpawnRule(30, 1, 10), gameManager)); basicRoom.addNpcSpawner(new NpcSpawner(new Derper(gameManager, basicRoom.getRoomId()), gameManager, new SpawnRule(10, 5))); basicRoom.addNpcSpawner(new NpcSpawner(new DruggedPimp(gameManager, basicRoom.getRoomId()), gameManager, new SpawnRule(10, 5))); + basicRoom.setAreas(Sets.newHashSet(Area.NEWBIE_ZONE)); entityManager.addEntity(basicRoom); - entityManager.addEntity(new BasicRoom( + + BasicRoom room1 = new BasicRoom( 2, "Quarter Deck", Optional.of(3), @@ -45,9 +48,10 @@ public class RoomBuilders { Optional.of(5), Optional.of(6), Optional.<Integer>absent(), - "You are standing on the quarter deck of the Training Encampment. Federation flags line the walls of this large room. A statue of the Grand Marshal of the Federation sit in the back. A Private on watch is behind a desk in the center of the room. To the west you hear the sounds of gun fire. To the east a sentry stands by a door waiting to scan the credentials of anyone looking for access to the armory. A staircase leads up stairs. You get the feeling only high ranking officers are allowed on the second floor. To the north is a door leading to the training fields.\r\n")); - - entityManager.addEntity(new BasicRoom( + "You are standing on the quarter deck of the Training Encampment. Federation flags line the walls of this large room. A statue of the Grand Marshal of the Federation sit in the back. A Private on watch is behind a desk in the center of the room. To the west you hear the sounds of gun fire. To the east a sentry stands by a door waiting to scan the credentials of anyone looking for access to the armory. A staircase leads up stairs. You get the feeling only high ranking officers are allowed on the second floor. To the north is a door leading to the training fields.\r\n"); + room1.setAreas(Sets.newHashSet(Area.NEWBIE_ZONE)); + entityManager.addEntity(room1); + BasicRoom room2 = new BasicRoom( 3, "Training Field", Optional.of(8), @@ -56,9 +60,14 @@ public class RoomBuilders { Optional.<Integer>absent(), Optional.<Integer>absent(), Optional.<Integer>absent(), - "You are standing on the center of a massive training field. You see a large field with a track surrounding it. A main pathway connects from back gate to the north to the main Federation building. Soldiers of all ranks are going about their business here.\r\n")); + "You are standing on the center of a massive training field. You see a large field with a track" + + " surrounding it. A main pathway connects from back gate to the north to the main Federation" + + " building. Soldiers of all ranks are going about their business here.\r\n"); + room2.setAreas(Sets.newHashSet(Area.NEWBIE_ZONE)); - entityManager.addEntity(new BasicRoom( + entityManager.addEntity(room2); + + BasicRoom room3 = new BasicRoom( 4, "Armory", Optional.<Integer>absent(), @@ -67,7 +76,13 @@ public class RoomBuilders { Optional.of(2), Optional.<Integer>absent(), Optional.<Integer>absent(), - "You are standing in the Federation Training Encampment armory. A counter extends from wall to wall separating you from the stock. A Lieutenant is standing behind the counter filling out paper work. You can see shelves extending to the back of the room fully stocked with Federation issued weapons. The door closes and locks behind you.\r\n")); + "You are standing in the Federation Training Encampment armory. A counter extends from wall to wall" + + " separating you from the stock. A Lieutenant is standing behind the counter filling out paper" + + " work. You can see shelves extending to the back of the room fully stocked with Federation" + + " issued weapons. The door closes and locks behind you.\r\n"); + room3.setAreas(Sets.newHashSet(Area.NEWBIE_ZONE)); + + entityManager.addEntity(room3); entityManager.addEntity(new BasicRoom( 5, diff --git a/src/main/java/com/comandante/creeper/server/command/KillCommand.java b/src/main/java/com/comandante/creeper/server/command/KillCommand.java index f0f297c44c5520fb60b343662274585512f94f78..0424fb34fbd67cc3999bdbaf8f5eaa365d8a036c 100644 --- a/src/main/java/com/comandante/creeper/server/command/KillCommand.java +++ b/src/main/java/com/comandante/creeper/server/command/KillCommand.java @@ -48,6 +48,7 @@ public class KillCommand extends Command { for (String npcId : npcIds) { Npc npcEntity = getGameManager().getEntityManager().getNpcEntity(npcId); if (npcEntity.getName().equals(target)) { + npcEntity.setIsInFight(true); FightRun fightRun = new FightRun(player, npcEntity, getGameManager()); Future<FightResults> fight = getGameManager().getFightManager().fight(fightRun); creeperSession.setActiveFight(Optional.of(fight)); diff --git a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java index 651c2ae853399be73c636d7cc01aaa020ed69645..73dcc2dc92fb6219ca713613b34ac6e04fd2e8c2 100644 --- a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java +++ b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java @@ -13,7 +13,7 @@ public class NpcSpawner extends CreeperEntity { private final Npc npc; private final GameManager gameManager; private final SpawnRule spawnRule; - private int noTicks = 0; + private int noTicks; private final Random random = new Random(); private Integer roomId; @@ -21,6 +21,7 @@ public class NpcSpawner extends CreeperEntity { this.npc = npc; this.gameManager = gameManager; this.spawnRule = spawnRule; + this.noTicks = spawnRule.getSpawnIntervalTicks(); } public void incTicks() {