*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Persistent;
+
/**
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public class Ability {
- public final String name;
+ public String name;
private int level;
+ public Ability() {
+ }
+
+ public Ability(String name, int level) {
+ this.name = name;
+ this.level = level;
+ }
+
public Ability(String name) {
this.name = name;
}
// fixme copyrihgts
package duskz.server.entityz;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Persistent;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import duskz.protocol.DuskMessage;
import duskz.protocol.Wearing;
import java.io.BufferedWriter;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public abstract class Active extends Thing {
/**
// object? player?
// I don' think mobs can have clans - factions are used instead, clan/race
// candiates for class beteen active and player/pet
- String clan;
/**
* Race, mobs can't have races.
*/
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE, relatedEntity = Race.class)
+ long raceid;
+ @NotPersistent
Race race;
- Equipment wornItems = new Equipment();
- Inventory inventory = new Inventory();
+ Inventory2 inventory = new Inventory2();
/**
* Sleeping state
*/
/**
* Tracks actives following in a pack
*/
- protected Pack pack;
+ // FIXME: it is persistent
+ @NotPersistent
+ volatile protected Pack pack;
/**
* Does this leader allow following at the moment.
*/
- boolean canLead = true;
+ @NotPersistent
+ volatile boolean canLead = true;
/**
* Allowed to move
*/
- protected boolean moveable = true;
+ @NotPersistent
+ volatile protected boolean moveable = true;
/**
* "step" of image: basically last direction moved.
*/
- protected int imageStep;
+ @NotPersistent
+ volatile protected int imageStep;
/**
* Live conditions
*/
/**
* If fighting, current battle
*/
- protected Battle battle;
+ @NotPersistent
+ volatile protected Battle battle;
/**
* Damage done, accumulates until you lose, where it is used to give
* bonus experience to your the winners
*/
- int damageDone;
+ @NotPersistent
+ volatile int damageDone;
//
private final HashMap<String, Ability> skills = new HashMap<>();
// FIXME: SpellAbility subclasses Ability
/**
* Pending moves, processed one at a time during movement tick
*/
+ @NotPersistent
final private LinkedList<String> moveQueue = new LinkedList<>();
/**
* Pending commands, this is only used during battle
*/
+ @NotPersistent
final private LinkedList<String[]> battleCommands = new LinkedList<>();
/**
* Tick of last state change, such as sleeping, etc.
*/
- int flagsChanged;
+ @NotPersistent
+ volatile int flagsChanged;
/**
* Tick of last condition change
*/
- int conditionsChanged;
+ @NotPersistent
+ volatile int conditionsChanged;
+
+ protected Active() {
+ }
Active(Game game) {
super(game);
}
- Wearable parseWearable(String value) {
+ Held parseWearable(int where, String value) {
// format is name,durability,uses
System.out.println("parse wearable: " + value);
Wearable w = (Wearable) game.createItem(args[0].toLowerCase());
+ Held h = null;
+
if (w != null) {
- w.durability = Long.valueOf(args[1]);
- w.uses = Integer.valueOf(args[2]);
+ h = new Held(w);
+ h.wear = Long.valueOf(args[1]);
+ h.used = Integer.valueOf(args[2]);
}
- return w;
+ return h;
}
// TODO: this probably needs some 'exporter' on Thing
- Holdable parseHoldable(String value) {
+ Held parseHoldable(String value) {
// format is name,durability,uses ... but durability is only used on Wearables
// FIXME: fix exporter ... not so easy, everything is an item, even weapons.
Holdable h = (Holdable) game.createItem(args[0].toLowerCase());
+ Held he = new Held(h);
+
// blah ... nice eh?
if (h instanceof Wearable) {
- ((Wearable) h).durability = Long.valueOf(args[1]);
+ (he).wear = Long.valueOf(args[1]);
}
- h.uses = Integer.valueOf(args[2]);
+ he.used = Integer.valueOf(args[2]);
- return h;
+ return he;
}
/* *
case "race":
race = game.getRace(value);
break;
- case "clan":
- clan = value;
+ case "privs":
+ privs = Integer.valueOf(value);
break;
case "wield":
- wornItems.wear(Wearing.WIELD, parseWearable(value));
+ inventory.add(parseWearable(Wearing.WIELD, value));
break;
case "arms":
- wornItems.wear(Wearing.ARMS, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.ARMS, value));
break;
case "legs":
- wornItems.wear(Wearing.LEGS, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.LEGS, value));
break;
case "torso":
- wornItems.wear(Wearing.TORSO, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.TORSO, value));
break;
case "waist":
- wornItems.wear(Wearing.WAIST, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.WAIST, value));
break;
case "neck":
- wornItems.wear(Wearing.NECK, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.NECK, value));
break;
case "skull":
- wornItems.wear(Wearing.SKULL, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.SKULL, value));
break;
case "eyes":
- wornItems.wear(Wearing.EYES, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.EYES, value));
break;
case "hands":
- wornItems.wear(Wearing.HANDS, parseWearable(value));
+ inventory.wear(parseWearable(Wearing.HANDS, value));
break;
// FIXME: should it specify the item type?
case "item":
}
writeProperty(out, "exp", exp);
writeProperty(out, "gold", gold);
- writeProperty(out, "clan", clan);
+ writeProperty(out, "privs", privs);
// FIXME: hack for mobile, race doesn't apply
- for (int i = 0; i < Wearing.WEARING_COUNT; i++) {
- Wearable w = wornItems.getWorn(i);
- if (w != null) {
- writeProperty(out, Wearing.wornNames[i], w.name + "," + w.durability + "," + w.uses);
- }
- }
+ // for (int i = 0; i < Wearing.WEARING_COUNT; i++) {
+ // Wearable w = wornItems.getWorn(i);
+ // if (w != null) {
+ // writeProperty(out, Wearing.wornNames[i], w.name + "," + w.durability + "," + w.uses);
+ // }
+ // }
if (race != null)
writeProperty(out, "race", race.name);
variables.writeProperties(out);
conditions.writeProperties(out);
}
+ public int getPrivs() {
+ return privs;
+ }
+
public int getStat(int key) {
return stats[key] + race.stats[key] + bonus[key];
}
public void addStat(int key, int value) {
setStat(key, stats[key] + value);
}
-
+
public int getBonus(int key) {
return bonus[key];
}
}
public int getRange() {
- Weapon item = (Weapon) wornItems.getWorn(Wearing.WIELD);
+ Held h = inventory.getWorn(Wearing.WIELD);
- return item != null ? item.range : 1;
+ return h != null ? ((Weapon) h.holdable).range : 1;
}
public int getRangeWithBonus() {
return true;
}
+ public void addSkill(String name, int level) {
+ Ability a = skills.get(name);
+
+ if (a != null) {
+ level += a.getLevel();
+ }
+ skills.put(name, new Ability(name, level));
+ }
+
public boolean isMoveable() {
return moveable;
}
* @param amount
*/
public void weaponDamage(int amount) {
- Wearable item = wornItems.damageItem(Wearing.WIELD, amount);
+ Held item = inventory.damageItem(Wearing.WIELD, amount);
if (item != null) {
- chatMessage("Your " + item.name + " breaks.");
+ chatMessage("Your " + item.getName() + " breaks.");
// FIXME: onUnwear(item);
//if (isPlayer()) {
// updateEquipment();
}
public void armourDamage(int damage) {
- int total = wornItems.armourCount();
+ int total = inventory.armourCount();
if (total == 0) {
return;
}
for (int i = Wearing.ARMS; i < Wearing.WEARING_COUNT; i++) {
- Wearable item = wornItems.damageItem(i, damage / total);
+ Held item = inventory.damageItem(i, damage / total);
if (item != null) {
- chatMessage("Your " + item.name + " breaks.");
+ chatMessage("Your " + item.getName() + " breaks.");
//FIXME: onUnwear(item);
//updateStats();
//updateEquipment();
dir = moveQueue.removeFirst();
}
- System.out.println("move " + name + " tick: " + dir);
+ System.out.println("move " + getName() + " tick: " + dir);
switch (dir.charAt(0)) {
case 'n':
if ((x == leader.x) && (y == leader.y)) {
return false;
} else if (Math.abs(x - oldx) + Math.abs(y - oldy) > 1) {
- leader.chatMessage(name + " is no longer following you.");
- chatMessage("You are no longer following " + leader.name + ".");
+ leader.chatMessage(getName() + " is no longer following you.");
+ chatMessage("You are no longer following " + leader.getName() + ".");
pack.removeFollower(this);
return false;
// search by name
for (TileMap.MapData md : map.range(x, y, game.viewRange)) {
for (Thing t : md.entities) {
- if (t.name.equalsIgnoreCase(name)) {
+ if (t.getName().equalsIgnoreCase(name)) {
boolean see = true;
if (t instanceof Active) {
} else if (enemy.getType() == TYPE_PET) {
msg = ("You can't attack pets.");
} else if (distanceL1(enemy) > getRangeWithBonus()) {
- System.out.println("attack enemy =" + enemy.name + " distance =" + distanceL1(enemy) + " range = " + getRangeWithBonus());
+ System.out.println("attack enemy =" + enemy.getName() + " distance =" + distanceL1(enemy) + " range = " + getRangeWithBonus());
msg = ("They're too far away.");
} else if (!game.onCanAttack(this, enemy)) {
msg = ("You can't attack them.");
}
public int getArmourMod() {
- return wornItems.armourMod();
+ return inventory.armourMod();
}
public int getArmourModWithBonus() {
}
public int getDamageMod() {
- Wearable item = wornItems.getWorn(Wearing.WIELD);
+ Held item = inventory.getWorn(Wearing.WIELD);
if (item != null)
- return item.mod;
+ return ((Wearable) item.holdable).mod;
return 100;
}
r2 = this.getSkillLevel("close combat");
}
if (r2 < 0) {
- s.append(this.name).append(" missed.");
+ s.append(this.getName()).append(" missed.");
battle.hitMessage(this, target, 0, "Missed!");
} else if (dodgeRoll(target, r2)) {
- s.append(target.name).append(" dodged ").append(this.name).append("'s attack");
+ s.append(target.getName()).append(" dodged ").append(this.getName()).append("'s attack");
battle.hitMessage(this, target, 0, "Dodged!");
} else {
// FIXME: audio
if (i < 0) {
i = 0;
}
- s.append(this.name + " did " + i + " to " + target.name);
+ s.append(this.getName()).append(" did ").append(i).append(" to ").append(target.getName());
target.receivedDamage(i);
this.causedDamage(i);
public void attack(Battle battle, Active target, int range) {
if (range > getRangeWithBonus()) {
// out of range
- battle.chatMessage(name + " is out of range");
+ battle.chatMessage(getName() + " is out of range");
} else {
StringBuilder msg = new StringBuilder();
@Override
public void look(Active viewer) {
- chatMessage(viewer.name + " is looking at you.");
- viewer.chatMessage(name + " has " + getCP() + "cp and " + getHP() + "/" + getHPMax() + "hp.");
+ chatMessage(viewer.getName() + " is looking at you.");
+ viewer.chatMessage(getName() + " has " + getCP() + "cp and " + getHP() + "/" + getHPMax() + "hp.");
if (description != null) {
viewer.chatMessage("Their description is: " + description);
}
"They are wearing %s on their hands."
};
for (int i = 0; i < formats.length; i++) {
- Wearable item = wornItems.getWorn(i);
+ Held item = inventory.getWorn(i);
if (item != null)
- viewer.chatMessage(String.format(formats[i], item.description));
+ viewer.chatMessage(String.format(formats[i], item.getDescription()));
}
}
*
* The item will be worn at the correct location.
*
+ * This is here to provide hooks for subclasses
+ *
* @param w
*/
- public void wearItem(Wearable w) {
- // FIXME: threads.
- if (inventory.contains(w)) {
- Wearable old = wornItems.wear(w.getWearing(), w);
-
- if (old != null) {
- inventory.add(old);
- }
- inventory.remove(w);
- }
+ public boolean wearItem(Held what) {
+ return inventory.wear(what);
}
public void wearCommand(String what) {
- Holdable h = inventory.get(what);
+ Held h = inventory.get(what);
String msg = null;
+
if (h != null) {
- if (h instanceof Wearable) {
- wearItem((Wearable) h);
- } else {
+ if (!wearItem(h))
msg = "You'd look pretty stupid trying to wear that!";
- }
- } else
+ } else {
msg = "You don't have that";
+ }
chatMessage(msg);
}
* @param index
*/
public void unwearAt(int index) {
- Wearable w = wornItems.unwear(index);
-
- // fIXME: onunwear/etc.
- if (w != null)
- inventory.add(w);
+ inventory.unwear(index);
}
/**
unwearAt(i);
}
} else {
- int index = Equipment.toIndex(what);
+ int index = Inventory2.toIndex(what);
+
+ if (index == -1) {
+ Held h = inventory.get(what);
- if (index == -1)
- index = wornItems.getWornIndex(what);
+ if (h != null)
+ index = h.where;
+ }
- if (index != -1) {
+ if (index != Wearing.INVENTORY) {
unwearAt(index);
} else {
chatMessage("You're not wearing that.");
Holdable item = (Holdable) thing;
game.removeThing(thing);
- inventory.add(item);
+
+ Held h = new Held();
+ h.holdable = item;
+ h.holdableID = item.ID;
+
+ inventory.add(h);
game.onItem(this, item, "get");
}
}
public void dropCommand(String what) {
- Holdable h = inventory.get(what);
+ Held h = inventory.get(what);
String msg = null;
if (h == null) {
- if (wornItems.isWearing(what)) {
- msg = ("You're wearing that, you cannot drop it.");
- } else {
- msg = ("You don't have that");
- }
- } else if (game.haveOnItem(h, "drop")) {
- game.onItem(this, h, "drop");
+ msg = ("You don't have that");
+ } else if (h.where != Wearing.INVENTORY) {
+ msg = ("You're wearing that, you cannot drop it.");
+ } else if (game.haveOnItem(h.holdable, "drop")) {
+ game.onItem(this, h.holdable, "drop");
} else {
inventory.remove(h);
- if (h.cost == 0) {
- msg = h.name + " vanishes into thin air.";
+ if (h.holdable.cost == 0) {
+ msg = h.getName() + " vanishes into thin air.";
} else {
- game.addThing(h, map, x, y);
+ game.addThing(h.holdable, map, x, y);
}
}
}
public void useCommand(String what) {
- Holdable item = inventory.get(what);
+ Held item = inventory.get(what);
String msg = null;
// TODO: check type?
if (item == null)
msg = "You don't have that.";
- else if (!game.haveOnItem(item, "use"))
+ else if (!game.haveOnItem(item.holdable, "use"))
msg = "That cannot be used.";
- else if (item.uses == 0)
+ else if (item.holdable.uses != -1 && item.used >= item.holdable.uses)
msg = "That is used up.";
else {
- if (item.uses != -1)
- item.uses--;
- game.onItem(this, item, "use");
+ item.used += 1;
+ game.onItem(this, item.holdable, "use");
}
chatMessage(msg);
}
public void drinkCommand(String what) {
- Holdable item = inventory.get(what);
+ Held item = inventory.get(what);
- if (item != null && item.getType() != TYPE_DRINK) {
+ if (item != null && item.holdable.getType() != TYPE_DRINK) {
chatMessage("You can't drink that.");
} else
useCommand(what);
}
public void eatCommand(String what) {
- Holdable item = inventory.get(what);
+ Held item = inventory.get(what);
- if (item != null && item.getType() != TYPE_FOOD) {
+ if (item != null && item.holdable.getType() != TYPE_FOOD) {
chatMessage("You can't eat that.");
} else
useCommand(what);
addStat(STAT_STR, inc);
}
- public List<Holdable> getAllItems(String name) {
+ public List<Held> getAllItems(String name) {
return inventory.getAll(name, Integer.MAX_VALUE);
}
- public void addItem(Holdable item) {
+ public void addItem(Held item) {
if (item != null) {
inventory.add(item);
- game.onItem(this, item, "get");
+ game.onItem(this, item.holdable, "get");
}
}
* @param item
* @return true if the item was in the inventory and could be removed.
*/
- public boolean removeItem(Holdable item) {
+ public boolean removeItem(Held item) {
// FIXME: what if worn?
if (item != null) {
return inventory.remove(item);
* @return
*/
public boolean isOwner(String key) {
- return inventory.get(key) != null
- || wornItems.isWearing(key);
+ return inventory.get(key) != null;
}
public boolean isWearing(String key) {
- return wornItems.isWearing(key);
+ return inventory.isWearing(key);
}
}
playerInSide1 = addToBattle(1, side1, side2, a, playerInSide1, playerInSide2);
}
- inpla1.localisedChat("-" + inpla1.name + " has attacked " + inpla2.name);
+ inpla1.localisedChat("-" + inpla1.getName() + " has attacked " + inpla2.getName());
// FIXME: inpla1.startBattle(inpla2);
// inpla2.startBattle(inpla1);
} catch (Exception e) {
// added.playMusic(1);
//}
}
- chatMessage(added.name + " has joined the battle.");
+ chatMessage(added.getName() + " has joined the battle.");
side.add(added);
added.enterBattle(this);
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Persistent;
import java.util.Objects;
/**
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public class Condition {
/**
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Persistent;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public class ConditionList {
private final HashMap<String, Condition> conditions = new HashMap<>();
+ @NotPersistent
private final List<Condition> endedConditions = new ArrayList<>();
/* ***************
public Container(Game game) {
super(game);
}
- int volumeLimit;
- int weightLimit;
+ public int volumeLimit;
+ public int weightLimit;
@Override
public int getType() {
BufferedWriter out = new BufferedWriter(new FileWriter(dst))) {
String line;
- item.name = src.getName();
+ item.setName(src.getName());
while ((line = in.readLine()) != null) {
line = line.trim();
out.append("type.");
out.append(item.getClass().getSimpleName());
out.append("=");
- out.append(item.name);
+ out.append(item.getName());
out.append('\n');
item.writeProperties(out);
--- /dev/null
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+package duskz.server.entityz;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Environment;
+import com.sleepycat.je.EnvironmentConfig;
+import com.sleepycat.persist.EntityCursor;
+import com.sleepycat.persist.EntityStore;
+import com.sleepycat.persist.PrimaryIndex;
+import com.sleepycat.persist.SecondaryIndex;
+import com.sleepycat.persist.StoreConfig;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+/**
+ *
+ * @author Michael Zucchi <notzed@gmail.com>
+ */
+public class DBTest {
+
+ public static void main(String[] args) throws IOException {
+ new File("/tmp/foo").mkdirs();
+
+ EnvironmentConfig envConfig = new EnvironmentConfig();
+ envConfig.setAllowCreate(true);
+ envConfig.setTransactional(true);
+ Environment env = new Environment(new File("/tmp/foo"), envConfig);
+
+// Open a transactional entity store.
+//
+ StoreConfig storeConfig = new StoreConfig();
+ storeConfig.setAllowCreate(true);
+ storeConfig.setTransactional(true);
+
+ // Persistent read-only data like mobs?
+ EntityStore gstore = new EntityStore(env, "GameStore", storeConfig);
+
+ storeConfig = new StoreConfig();
+ storeConfig.setAllowCreate(true);
+ storeConfig.setTransactional(true);
+
+ EntityStore store = new EntityStore(env, "LiveStore", storeConfig);
+
+ PrimaryIndex<Long, Player> playerByID = store.getPrimaryIndex(Long.class, Player.class);
+ SecondaryIndex<String, Long, Player> playerByName = store.getSecondaryIndex(playerByID, String.class, "name");
+ PrimaryIndex<Long, Race> raceByID = store.getPrimaryIndex(Long.class, Race.class);
+ SecondaryIndex<String, Long, Race> raceByName = store.getSecondaryIndex(raceByID, String.class, "name");
+
+ PrimaryIndex<Long, Holdable> itemsByID = store.getPrimaryIndex(Long.class, Holdable.class);
+
+ File g = new File("/home/notzed/dusk/game");
+
+ Game game = new Game();
+ game.init(g);
+
+ if (raceByName.get("human") == null) {
+ System.out.println("Create races\n");
+ for (Race r : game.races.values()) {
+ r.ID = 0;
+ raceByID.put(r);
+ }
+ }
+
+ if (playerByName.get("z") == null) {
+ Player p = new Player();
+ p.game = game;
+ p.load(new File(g, "players/z"));
+
+ p.race = raceByName.get(p.race.name);
+ p.raceid = p.race.ID;
+
+ playerByID.put(p);
+ }
+
+ // Load items
+ File items = new File(game.getRoot(), "defItems");
+ for (String n : items.list()) {
+ try {
+ Holdable h = game.createItem(n);
+ System.out.printf("item %s = %s %d\n", n, h, h.ID);
+ } catch (Exception ex) {
+ System.out.printf("error with item %s: %s\n", n, ex);
+ }
+ }
+
+ // Shops
+ for (GameShop s : game.gameShops.values()) {
+ System.out.println("game shop: " + s);
+ }
+
+ PrimaryIndex<Long, Sign> signByID = store.getPrimaryIndex(Long.class, Sign.class);
+ for (Sign s : game.signs.values()) {
+ s.ID = 0;
+ try {
+ System.out.printf("writing %s %s\n", s.getName(), s.description);
+ signByID.put(s);
+ } catch (DatabaseException ex) {
+ System.out.println("error writing: " + ex);
+ }
+ }
+
+ try (EntityCursor<Sign> ec = signByID.entities()) {
+ Sign s;
+ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
+ while ((s = ec.next()) != null) {
+ s.writeState(bw);
+ }
+ bw.close();
+ }
+
+ store.sync();
+
+ }
+}
for (int i = 0; i < worn.length; i++) {
Wearable item = worn[i];
if (item != null)
- sb.append(item.name).append('\n');
+ sb.append(item.getName()).append('\n');
else
sb.append("none\n");
}
for (int i = 0; i < worn.length; i++) {
Wearable item = worn[i];
if (item != null)
- msg.add(i, item.name);
+ msg.add(i, item.getName());
}
return msg;
for (int i=0;i<worn.length;i++) {
Wearable item = worn[i];
- if (item != null && what.equalsIgnoreCase(item.name))
+ if (item != null && what.equalsIgnoreCase(item.getName()))
return i;
}
return -1;
public boolean isWearing(String what) {
for (Wearable item : worn) {
- if (item != null && what.equalsIgnoreCase(item.name))
+ if (item != null && what.equalsIgnoreCase(item.getName()))
return true;
}
return false;
if (item != null) {
if (item.getWearing() != where) {
// FIXME: cachable exception?
- throw new RuntimeException("can't wear an item " + item.name
+ throw new RuntimeException("can't wear an item " + item.getName()
+ " type " + item.getClass().getSimpleName()
+ " at " + Wearing.wornNames[where]
+ " should be " + Wearing.wornNames[item.getWearing()]);
for (int i = 0; i < worn.length; i++) {
Wearable item = worn[i];
- if (item != null && name.equalsIgnoreCase(item.name)) {
+ if (item != null && name.equalsIgnoreCase(item.getName())) {
worn[i] = null;
return item;
}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Persistent;
+import com.sleepycat.persist.model.PrimaryKey;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
/**
* Faction is a group of mobs. TODO: should it override/merge the normal group thing
*/
+@Entity
public class Faction {
- final public String name;
+ @PrimaryKey(sequence = "FactionID")
+ public long ID;
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE)
+ public String name;
/**
* This is keyed on both player names and clans. Seems it should be two
* separate tables
*/
private final HashMap<String, Relation> relations = new HashMap<>();
- private Game game;
+ @NotPersistent
+ volatile private Game game;
private boolean changed = false;
+ public Faction() {
+ }
+
public Faction(String name, Game game) {
this.name = name;
this.game = game;
if (game.isPreference(Game.PREF_AI)) {
int delta = killer.getCP() - died.getCP();
- changed |= updateRelation(killer.name, delta);
+ changed |= updateRelation(killer.getName(), delta);
- if (killer.clan != null && !killer.clan.equals("none")) {
- changed |= updateRelation(killer.clan, delta);
+ if (killer instanceof Player) {
+ Player kp = (Player) killer;
+ if (kp.clan != null && !kp.clan.equals("none")) {
+ changed |= updateRelation(kp.clan, delta);
+ }
}
}
}
if (mob.onCanSeeActive(lt) && mob.canSee(lt.x, lt.y)) {
if (o.getType() == Thing.TYPE_PLAYER) {
+ Player p = (Player) o;
visiblePlayer = true;
- double relation = getRelationValue(lt.name);
- if (!(lt.clan == null || lt.clan.equals("none"))) {
- relation = (relation + getRelationValue(lt.clan)) / 2;
+ double relation = getRelationValue(lt.getName());
+ if (!(p.clan == null || p.clan.equals("none"))) {
+ relation = (relation + getRelationValue(p.clan)) / 2;
}
if (relation < 0 && (enemy == null || enemyrelation < relation)) {
enemy = lt;
enemyrelation = relation;
}
intConfidence += relation * lt.getTP();
- System.out.printf("mob '%s' can see player '%s' relation %f confidence=%d\n", mob.name, lt.name, relation, intConfidence);
+ System.out.printf("mob '%s' can see player '%s' relation %f confidence=%d\n", mob.getName(), lt.getName(), relation, intConfidence);
System.out.printf(" player points total = %d armour %d damage %d cmponent %f\n", lt.getTP(), lt.getArmourMod(), lt.getDamageMod(), relation * lt.getTP());
} else {
double relation;
Mobile m = (Mobile) lt;
- if (m.name.equals(mob.name)) {
+ if (m.getName().equals(mob.getName())) {
relation = m.groupRelation;
} else {
- relation = getRelationValue(m.name);
+ relation = getRelationValue(m.getName());
}
intConfidence += relation * m.getTP();
if (relation < 0 && (enemy == null || enemyrelation > relation)) {
enemyrelation = relation;
}
intConfidence += relation * lt.getTP();
- System.out.printf("mob '%s' can see mob '%s' relation %f confidence=%d\n", mob.name, lt.name, relation, intConfidence);
+ System.out.printf("mob '%s' can see mob '%s' relation %f confidence=%d\n", mob.getName(), lt.getName(), relation, intConfidence);
System.out.printf(" player points total = %d armour %d damage %d component %f\n", lt.getTP(), lt.getArmourMod(), lt.getDamageMod(), relation * lt.getTP());
}
}
}
//Fight
if (enemy.distanceL1(mob) <= mob.getRangeWithBonus()) {
- System.out.println(mob.name + " close enough, going into battle distance: " + enemy.distanceL1(mob) + " range: " + mob.getRangeWithBonus());
+ System.out.println(mob.getName() + " close enough, going into battle distance: " + enemy.distanceL1(mob) + " range: " + mob.getRangeWithBonus());
// close enough to attack, so stop moving
mob.clearMoveQueue();
mob.createBattle(enemy);
game.log.printError("runAI():" + mob.name + " had an error attacking " + enemy.name, e);
}*/
} else {
- System.out.println("Mob ai: move to enemy " + enemy.name + " " + enemy.x + "," + enemy.y);
+ System.out.println("Mob ai: move to enemy " + enemy.getName() + " " + enemy.x + "," + enemy.y);
mob.travelTo(enemy.x, enemy.y, false);
}
} else {
//Flee
int destX = mob.x + Integer.signum(mob.x - enemy.x) * game.viewRange;
int destY = mob.y + Integer.signum(mob.y - enemy.y) * game.viewRange;
- System.out.println("Mob ai: flee from " + enemy.name + " " + destX + "," + destY);
+ System.out.println("Mob ai: flee from " + enemy.getName() + " " + destX + "," + destY);
mob.travelTo(destX, destY, true);
}
}
*
* @author Tom Weingarten
*/
+ @Persistent
static class Relation {
String name;
try {
Mobile mob = new Mobile(this);
mob.load(file);
- allMobs.put(mob.name, mob);
+ allMobs.put(mob.getName(), mob);
//log.printf(Log.VERBOSE, "Mob class: %s", mob.name);
} catch (Exception ex) {
log.printf(ex, "Loading mob %s failed", file.getName());
// HACK: just copy to indices now
for (Mobile m : mobs.values()) {
- System.out.println("add mob " + m.name + " on " + m.map.name);
+ System.out.println("add mob " + m.getName() + " on " + m.map.name);
addThing(m);
}
for (Sign s : signs.values()) {
- System.out.println("add sign: " + s.name + " at " + s.x + ", " + s.y + " on map " + s.map.name);
+ System.out.println("add sign: " + s.getName() + " at " + s.x + ", " + s.y + " on map " + s.map.name);
addThing(s);
}
for (Shop s : gameShops.values()) {
- System.out.println("add shop: " + s.name + " at " + s.x + ", " + s.y + " on map " + s.map.name);
+ System.out.println("add shop: " + s.getName() + " at " + s.x + ", " + s.y + " on map " + s.map.name);
addThing(s);
}
switch (thing.getType()) {
case Thing.TYPE_PLAYER:
- players.remove(((Player) thing).name);
+ players.remove(((Player) thing).getName());
actives.remove(thing.ID);
break;
case Thing.TYPE_MOBILE:
switch (t.getType()) {
case Thing.TYPE_PLAYER: {
Player player = (Player) t;
- players.put(player.name, player);
+ players.put(player.getName(), player);
actives.put(player.ID, player);
break;
}
}
public boolean haveOnItem(Holdable trigger, String what) {
- return new File(onScriptDir, trigger.name + "." + what).exists();
+ return new File(onScriptDir, trigger.getName() + "." + what).exists();
}
/**
* @param what "get" or "drop", etc.
*/
public void onItem(Active owner, Holdable item, String what) {
- runScript(onScriptDir, item.name + "." + what,
+ runScript(onScriptDir, item.getName() + "." + what,
"game", this,
"owner", owner,
"item", item);
}
public boolean haveOnCondition(Holdable trigger, String what) {
- return new File(onConditionDir, trigger.name + "." + what).exists();
+ return new File(onConditionDir, trigger.getName() + "." + what).exists();
}
/**
* @throws BlockedIPException
*/
void registerPlayer(Player player) {
- logPasswordSuccess(player.name, player.getAddress());
+ logPasswordSuccess(player.getName(), player.getAddress());
- Player old = players.get(player.name);
+ Player old = players.get(player.getName());
if (old != null) {
old.chatMessage("Logged in again from: " + player.getAddress());
old.logout();
}
//throw new UnsupportedOperationException("Not supported yet.");
- players.put(player.name, player);
+ players.put(player.getName(), player);
things.put(player.ID, player);
actives.put(player.ID, player);
player.map.addEntity(player);
void unregisterPlayer(Player player) {
// TODO threading
player.map.removeEntity(player);
- players.remove(player.name);
+ players.remove(player.getName());
things.remove(player.ID);
actives.remove(player.ID);
}
@Override
public void buy(Active buyer, String what, int quantity) {
- Holdable h = items.get(what);
+ Held h = items.get(what);
if (h == null) {
- buyer.chatMessage(name + " doesn't sell those.");
+ buyer.chatMessage(getName() + " doesn't sell those.");
return;
}
- if (h instanceof Training) {
- Training t = (Training) h;
- if (!buyer.addExp(-h.cost * quantity)) {
+ if (h.holdable instanceof Training) {
+ Training t = (Training) h.holdable;
+ if (!buyer.addExp(-t.cost * quantity)) {
buyer.chatMessage("You can't afford that many.");
} else {
switch (t.skill) {
break;
default:
buyer.chatMessage("BUG: I don't know how to train " + t.skill);
- buyer.addExp(h.cost * quantity);
+ buyer.addExp(t.cost * quantity);
break;
}
}
} else {
- if (buyer.getGold() < h.cost * quantity) {
+ if (buyer.getGold() < h.holdable.cost * quantity) {
buyer.chatMessage("You can't afford that many.");
} else {
while (quantity > 0) {
- Holdable s = game.createItem(what);
- if (buyer.addGold(-h.cost)) {
- buyer.addItem(s);
+ // FIXME: db stuff
+
+ if (buyer.addGold(-h.holdable.cost)) {
+ Holdable s = game.createItem(what);
+ buyer.addItem(new Held(s));
}
quantity -= 1;
}
}
@Override
- public void sell(Active customer, List<Holdable> items) {
+ public void sell(Active customer, List<Held> items) {
// TODO: I really want to look up the item somewhere to see what
// this shop will buy the items for ...?
- for (Holdable h : items) {
+ for (Held h : items) {
if (customer.removeItem(h)) {
- customer.addGold(h.cost / 2);
+ customer.addGold(h.holdable.cost / 2);
}
}
}
--- /dev/null
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+package duskz.server.entityz;
+
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Persistent;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
+import duskz.protocol.Wearing;
+
+/**
+ * Volatile parts of a 'holdable' item.
+ *
+ * @author Michael Zucchi <notzed@gmail.com>
+ */
+@Persistent
+public class Held {
+
+ @SecondaryKey(relate = Relationship.MANY_TO_ONE, relatedEntity = Holdable.class)
+ public long holdableID;
+ @NotPersistent
+ public Holdable holdable;
+ /**
+ * Where it is, Wearing constants
+ */
+ public int where = Wearing.INVENTORY;
+ /**
+ * How many times it's been consumed
+ */
+ public int used;
+ /**
+ * For weapons, wear and tear
+ */
+ public long wear;
+
+ public Held() {
+ }
+
+ public Held(Holdable holdable) {
+ this.holdableID = holdable.ID;
+ this.holdable = holdable;
+ }
+
+ public String getName() {
+ return holdable.getName();
+ }
+
+ public String getDescription() {
+ return holdable.description;
+ }
+}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
+import duskz.protocol.Wearing;
import java.io.BufferedWriter;
import java.io.IOException;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
-public abstract class Holdable extends Thing {
+@Entity
+public class Holdable extends Thing {
- int cost;
+ // FIXME: these shouldn't be public
+ public int cost;
//int image;
- int volume;
- int weight;
- String onGet, onDrop;
- int uses = -1;
- String onUse;
+ public int volume;
+ public int weight;
+ public String onGet, onDrop, onUse;
+ public int uses = -1;
+ // new stuff
+ public int wearing = Wearing.INVENTORY;
+ /**
+ * TODO: move the readonly stuff into a different object
+ * then have two objects to wrap it, depending on context:
+ *
+ * Held when held
+ * MapItem when stored on a map
+ */
+ public Holdable() {
+ }
Holdable(Game game) {
super(game);
}
- abstract public int getWearing();
+ public int getWearing() {
+ return wearing;
+ }
+
+ @Override
+ public int getType() {
+ switch (wearing) {
+ case Wearing.TRAINING:
+ return TYPE_TRAINING;
+ case Wearing.DRINK:
+ return TYPE_DRINK;
+ case Wearing.FOOD:
+ return TYPE_FOOD;
+ case Wearing.CONTAINER:
+ return TYPE_CONTAINER;
+ case Wearing.INVENTORY:
+ return TYPE_ITEM;
+ case Wearing.WIELD:
+ return TYPE_WEAPON;
+ default:
+ return TYPE_ARMOUR;
+ }
+ }
public String getUnits() {
- return "gp";
+ switch (wearing) {
+ case Wearing.TRAINING:
+ return "exp";
+ default:
+ return "gp";
+ }
}
@Override
@Override
protected void writeProperties(BufferedWriter out) throws IOException {
- writeProperty(out, "name", name);
+ writeProperty(out, "name", getName());
writeProperty(out, "description", description);
//writeProperty(out, "map", map.name);
//writeProperty(out, "x", x);
int cost = (int) (h.cost * scale);
- msg.add(h.getWearing(), h.name, 1, cost, h.getUnits());
+ msg.add(h.getWearing(), h.getName(), 1, cost, h.getUnits());
}
return msg;
else {
// hack: shopping list
for (Holdable h : items) {
- viewer.chatMessage(String.format("%-20s %s", h.name, h.description));
+ viewer.chatMessage(String.format("%-20s %s", h.getName(), h.description));
}
}
}
*/
public Holdable get(String key) {
for (Holdable h : items) {
- if (key.equalsIgnoreCase(h.name))
+ if (key.equalsIgnoreCase(h.getName()))
return h;
}
return null;
public List<Holdable> getAll(String key, int maximum) {
ArrayList<Holdable> list = new ArrayList<>();
for (Holdable h : items) {
- if (h.name.equalsIgnoreCase(key)) {
+ if (h.getName().equalsIgnoreCase(key)) {
list.add(h);
if (list.size() >= maximum)
break;
--- /dev/null
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+package duskz.server.entityz;
+
+import com.sleepycat.persist.model.Persistent;
+import duskz.protocol.DuskMessage;
+import duskz.protocol.ListMessage;
+import duskz.protocol.TransactionMessage;
+import duskz.protocol.Wearing;
+import static duskz.protocol.Wearing.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A list of holdables.
+ *
+ * Original game had table by type, but that seems somewhat pointless overhead.
+ *
+ * This is a bit of a mis-mash right now just trying to get the code working
+ *
+ *
+ * @author Michael Zucchi <notzed@gmail.com>
+ */
+@Persistent
+public class Inventory2 {
+
+ final private ArrayList<Held> items = new ArrayList<>();
+
+ public TransactionMessage createTransactionMessage(Game game, int name, float scale) {
+ TransactionMessage msg = new TransactionMessage(name);
+
+ // TODO: count occurances here for player inventory?
+
+ for (Held held : items) {
+ // FIXME: how to represent skills
+
+ if (held.where == Wearing.INVENTORY) {
+ Holdable h = held.holdable;
+ int cost = (int) (h.cost * scale);
+
+ msg.add(h.getWearing(), h.getName(), 1, cost, h.getUnits());
+ }
+ }
+
+ return msg;
+ }
+
+ public DuskMessage createWearingMessage(Game game, int msgid) {
+ ListMessage msg = new ListMessage(msgid);
+
+ for (Held h : items) {
+ if (h.where != Wearing.INVENTORY) {
+ msg.add(h.where, h.holdable.getName());
+ }
+ }
+
+ return msg;
+ }
+
+ public void describeTo(Active viewer) {
+ if (items.isEmpty())
+ viewer.chatMessage("Nothing at the moment.");
+ else {
+ // hack: shopping list
+ for (Held h : items) {
+ viewer.chatMessage(String.format("%-20s %s", h.holdable.getName(), h.holdable.description));
+ }
+ }
+ }
+
+ /**
+ * Return the first item of the given type
+ *
+ * @param key
+ * @return
+ */
+ public Held get(String key) {
+ for (Held h : items) {
+ if (key.equalsIgnoreCase(h.holdable.getName()))
+ return h;
+ }
+ return null;
+ }
+
+ public void add(Held h) {
+ items.add(h);
+ }
+
+ public boolean remove(Held h) {
+ return items.remove(h);
+ }
+
+ public List<Held> getAll(String key, int maximum) {
+ ArrayList<Held> list = new ArrayList<>();
+ for (Held h : items) {
+ if (h.holdable.getName().equalsIgnoreCase(key)) {
+ list.add(h);
+ if (list.size() >= maximum)
+ break;
+ }
+ }
+ return list;
+ }
+
+ public boolean contains(Held h) {
+ return items.contains(h);
+ }
+
+ public boolean isWearing(String what) {
+ Held h = get(what);
+
+ return h != null && h.where != Wearing.INVENTORY;
+ }
+
+ public boolean wear(Held h) {
+ if (h.holdable.getWearing() == Wearing.INVENTORY)
+ return false;
+
+ h.where = h.holdable.getWearing();
+ return true;
+ }
+
+ public boolean unwear(int wearing) {
+ for (Held h : items) {
+ if (h.where == wearing) {
+ h.where = Wearing.INVENTORY;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Held getWorn(int wearing) {
+ for (Held h : items) {
+ if (h.where == wearing) {
+ return h;
+ }
+ }
+ return null;
+ }
+
+ public int armourCount() {
+ int count = 0;
+ for (Held h : items) {
+ if (h.where >= Wearing.ARMS && h.where <= Wearing.HANDS)
+ count++;
+ }
+ return count;
+ }
+ public static final float[] ARMOUR_MOD = {
+ 0f, 0.05f, 0.05f, 0.40f, 0.15f, 0.05f, 0.20f, 0.05f, 0.05f
+ };
+
+ public int armourMod() {
+ int mod = 0;
+
+ for (Held h : items) {
+ if (h.where >= Wearing.ARMS && h.where <= Wearing.HANDS)
+ mod += ARMOUR_MOD[h.where] * ((Armour) h.holdable).mod;
+ }
+ return mod;
+ }
+
+ /**
+ * Damage the specified item if it exists
+ *
+ * @param damage
+ * @return the weapon if it was destroyed
+ */
+ public Held damageItem(int index, int damage) {
+ for (Held h : items) {
+ if (h.where == index) {
+ Wearable w = (Wearable) h.holdable;
+
+ h.wear += damage;
+ if (w.durability != -1 && h.wear > w.durability) {
+ items.remove(h);
+ return h;
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static int toIndex(String where) {
+ switch (where.toLowerCase()) {
+ case "wielded":
+ return WIELD;
+ case "arms":
+ return ARMS;
+ case "legs":
+ return LEGS;
+ case "torso":
+ return TORSO;
+ case "waist":
+ return WAIST;
+ case "neck":
+ return NECK;
+ case "skull":
+ return SKULL;
+ case "eyes":
+ return EYES;
+ case "hands":
+ return HANDS;
+ }
+ return Wearing.INVENTORY;
+ }
+}
homeY = y;
if (faction == null)
//throw new IOException("Missing faction on " + name);
- System.out.println("Missing faction on " + name);
+ System.out.println("Missing faction on " + getName());
/*
setStat(STAT_HP, getHPMax());
setStat(STAT_MP, getMPMax());
@Override
public void chatMessage(Active from, String clan, String msg) {
// don't care except for debugging?
- System.out.println("mob: " + name + "=" + msg);
+ System.out.println("mob: " + getName() + "=" + msg);
}
@Override
// FIXME: Invoke "onBatte"
if (range > getRangeWithBonus()) {
- battle.chatMessage(name + " is out of range, moving closer. distance=" + range + " range=" + getRangeWithBonus() + " moveable=" + isMoveable());
+ battle.chatMessage(getName() + " is out of range, moving closer. distance=" + range + " range=" + getRangeWithBonus() + " moveable=" + isMoveable());
travelTo(target.x, target.y, false);
} else {
clearMoveQueue();
@Override
public void killedBattle(Battle battle, Active winner, ArrayList<Active> opponents) {
- chatMessage(this.name + " is killed.");
+ chatMessage(this.getName() + " is killed.");
splitMoney(1, opponents);
splitExp(0, opponents);
if (Math.random() < gi.probability) {
Holdable h = game.createItem(gi.name);
- winner.chatMessage("You got a " + h.name + ".");
- winner.addItem(h);
+ winner.chatMessage("You got a " + h.getName() + ".");
+ winner.addItem(new Held(h));
}
}
}
@Override
public void sayCommand(String text) {
- localisedChat("Mob " + name + " says: " + text);
+ localisedChat("Mob " + getName() + " says: " + text);
}
void respawn() {
*/
public boolean containsClanless() {
for (Active a : members) {
- if (a.clan.equals("none"))
- return true;
+ if (a instanceof Player) {
+ if (((Player)a).isClanless())
+ return true;
+ }
}
return false;
}
public void addFollower(Active follower) {
if (!members.isEmpty()) {
for (Active a : members) {
- a.chatMessage("You are now being followed by " + follower.name + ".");
+ a.chatMessage("You are now being followed by " + follower.getName() + ".");
}
- follower.chatMessage("You are now following " + members.get(members.size() - 1).name + ".");
+ follower.chatMessage("You are now following " + members.get(members.size() - 1).getName() + ".");
}
members.add(follower);
}
members.remove(follower);
for (Active a : members) {
- a.chatMessage(follower.name + " is no longer following you.");
+ a.chatMessage(follower.getName() + " is no longer following you.");
}
- follower.chatMessage("You are no longer following " + leader.name);
+ follower.chatMessage("You are no longer following " + leader.getName());
}
}
}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import duskz.protocol.DuskMessage;
import java.util.ArrayList;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Entity
public class Pet extends Active {
/**
* The pet's master.
*/
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE, relatedEntity = Player.class)
+ long playerid;
+ @NotPersistent
Player master;
+ public Pet() {
+ }
+
public Pet(Game game) {
super(game);
}
void leaveCommand() {
chatMessage("You cannot leave your master unless he unfollows you.");
}
-
+
@Override
protected boolean followTo(Active leader, int oldx, int oldy) {
@Override
public void killedBattle(Battle battle, Active winner, ArrayList<Active> opponents) {
- battle.chatMessage(name + " is wounded.");
+ battle.chatMessage(getName() + " is wounded.");
chatMessage("You have been wounded.");
splitMoney(game.goldLoseMod, opponents);
splitExp(game.expLoseMod, opponents);
@Override
public void sayCommand(String text) {
- localisedChat("Pet " + name + " says: " + text);
+ localisedChat("Pet " + getName() + " says: " + text);
}
}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import duskz.protocol.DuskMessage;
import duskz.protocol.DuskProtocol;
import duskz.protocol.EntityUpdateMessage;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Entity
public class Player extends Active implements DuskProtocol {
private HashSet<String> ignore = new HashSet<>();
// This shoudln't be stored like this ...
protected String password;
/**
- * Privilege level
+ * Player clan membership
+ * FIXME: db table
*/
- int privs;
+ String clan;
/**
* Players can have 1 pet
*/
- Pet pet;
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE, relatedEntity = Pet.class)
+ Long petid = null;
+
+ @NotPersistent
+// Pet pet;
/*
* State tracking
*/
/**
* Used to optimise network traffic
*/
- PlayerState state;
+ @NotPersistent
+ volatile PlayerState state;
/**
* Connection to client
*/
- private final PlayerConnection connection;
+ @NotPersistent
+ private volatile PlayerConnection connection;
/**
* Helper for commands
*/
- private final PlayerCommands commands;
+ @NotPersistent
+ private volatile PlayerCommands commands;
/**
* Helper for command line
*/
- private final Commands cmdline;
+ @NotPersistent
+ private volatile Commands cmdline;
+
+ public Player() {
+ }
public Player(Game game, PlayerConnection connection) {
super(game);
alive = connection != null;
}
+ protected void setConnection(PlayerConnection connection) {
+ this.connection = connection;
+ }
+
+ public Pet getPet() {
+ // lookup/activate pet if not done so
+ return null;
+ }
+
@Override
public int getType() {
return TYPE_PLAYER;
}
@Override
- public void wearItem(Wearable w) {
- super.wearItem(w);
+ public boolean wearItem(Held w) {
+ boolean res = super.wearItem(w);
wornChanged();
-
+ return res;
}
@Override
// sb.append(s);
// sb.append('>');
//}
- sb.append(this.name);
+ sb.append(this.getName());
en.entityName = sb.toString();
en.imageStep = (short) imageStep;
case "password":
password = value;
break;
+ case "clan":
+ clan = value;
+ break;
default:
super.setProperty(name, value);
}
writeProperty(out, "password", password);
super.writeProperties(out);
- writeProperty(out, "privs", privs);
+ writeProperty(out, "clan", clan);
+
+ Pet pet = getPet();
if (pet != null)
- writeProperty(out, "pet", pet.name);
+ writeProperty(out, "pet", pet.getName());
}
return clan == null || clan.equals("none");
}
+ public boolean inClan(String clan) {
+ return this.clan != null && this.clan.equals(clan);
+ }
+
/**
* Whether the acti
* FIXME: Who can have clans? if it's only players, fix Active to account for that.
public void fleeBattle(Battle battle, ArrayList<Active> opponents) {
super.fleeBattle(battle, opponents);
+ Pet pet = getPet();
+
if (pet != null) {
battle.removeParticipant(pet);
pet.fleeBattle(battle, opponents);
public void killedBattle(Battle battle, Active winner, ArrayList<Active> opponents) {
clearFollow();
- battle.chatMessage(name + " is killed.");
+ battle.chatMessage(getName() + " is killed.");
chatBattle("You have died.");
splitMoney(game.goldLoseMod, opponents);
splitExp(game.expLoseMod, opponents);
endBattle();
- game.globalChat(null, null, name + " has been killed by " + winner.name);
+ game.globalChat(null, null, getName() + " has been killed by " + winner.getName());
// FIXME: on player death script
game.onDeath(this, winner);
+ Pet pet = getPet();
+
if (pet != null) {
// how to pass this to battle?
// list2.remove(front2.getFollowing());
}
public void chatMessage(Active from, String clan, String msg) {
- if (from != null && from.getType() == TYPE_PLAYER && ignore.contains(from.name))
+ if (from != null && from.getType() == TYPE_PLAYER && ignore.contains(from.getName()))
return;
if (clan != null && !clan.equals(this.clan))
@Override
public void gossipCommand(String text) {
if (isVoiceAllowed()) {
- String title = name;
- if (privs > 2) {
+ String title = getName();
+ if (getPrivs() > 2) {
// && hasCondition("invis")
// && hasCondition("invis2")) {
title = "A god";
@Override
public void sayCommand(String text) {
if (isVoiceAllowed()) {
- String title = name;
- if (privs > 2) {
+ String title = getName();
+ if (getPrivs() > 2) {
// && hasCondition("invis")
// && hasCondition("invis2")) {
title = "A god";
@Override
void leaveCommand() {
boolean linkpet = false;
+
+ Pet pet = getPet();
+
if (pet != null) {
// Not really happy with this design here
if (pack.contains(pet)) {
}
void parseCommand(String cmd) {
- System.out.println(name + ": parse command: " + cmd);
+ System.out.println(getName() + ": parse command: " + cmd);
try {
cmdline.execute(cmd);
} catch (Exception ex) {
}
@Override
- public void addItem(Holdable item) {
+ public void addItem(Held item) {
super.addItem(item);
inventoryChanged();
}
@Override
- public boolean removeItem(Holdable item) {
+ public boolean removeItem(Held item) {
if (super.removeItem(item)) {
inventoryChanged();
return true;
res.add(FIELD_AUTH_REASON, "Login ok.");
player.send(res);
- setName("Player thread: " + player.name);
- sender.setName("Ouptut thread: " + player.name);
+ setName("Player thread: " + player.getName());
+ sender.setName("Ouptut thread: " + player.getName());
// log successful connection, etc.
//
return TYPE_PLAYER_SHOP;
}
- private void buy(Active buyer, List<Holdable> all) {
- for (Holdable h : all) {
+ private void buy(Active buyer, List<Held> all) {
+ for (Held h : all) {
items.remove(h);
buyer.addItem(h);
}
@Override
public void buy(Active buyer, String what, int quantity) {
- List<Holdable> all = items.getAll(what, quantity);
+ List<Held> all = items.getAll(what, quantity);
if (all.isEmpty()) {
- buyer.chatMessage(name + " doesn't have that for sale.");
+ buyer.chatMessage(getName() + " doesn't have that for sale.");
} else if (all.size() < quantity) {
- buyer.chatMessage(name + " doesn't have that many to sell.");
+ buyer.chatMessage(getName() + " doesn't have that many to sell.");
} else if (buyer == owner) {
buy(buyer, all);
- } else if (buyer.addGold(-all.get(0).cost * quantity * 3 / 4)) {
- gold += all.get(0).cost * quantity * 3 / 4;
+ } else if (buyer.addGold(-all.get(0).holdable.cost * quantity * 3 / 4)) {
+ gold += all.get(0).holdable.cost * quantity * 3 / 4;
buy(buyer, all);
} else {
buyer.chatMessage("You can't afford that.");
}
@Override
- public void sell(Active customer, List<Holdable> all) {
+ public void sell(Active customer, List<Held> all) {
if (owner != customer)
customer.chatMessage("You cannot sell to this shop.");
else {
- for (Holdable h : all) {
+ for (Held h : all) {
items.add(h);
customer.removeItem(h);
}
updateMap();
updateCheckShop();
} else if (overShop != null && overShop.inventoryChanged >= lastUpdate) {
- player.send(overShop.createTransactionMessage(MSG_UPDATE_MERCHANT));
+ player.send(overShop.createTransactionMessage(player.game, MSG_UPDATE_MERCHANT));
}
if (actions >= lastUpdate)
if (thing != null) {
overShop = thing;
- player.send(overShop.createTransactionMessage(MSG_UPDATE_MERCHANT));
+ player.send(overShop.createTransactionMessage(player.game, MSG_UPDATE_MERCHANT));
} else if (overShop != null) {
player.send(DuskMessage.create(MSG_EXIT_MERCHANT));
overShop = null;
}
void updateWorn() {
- player.send(player.wornItems.toMessage(MSG_EQUIPMENT));
+ player.send(player.inventory.createWearingMessage(player.game, MSG_EQUIPMENT));
}
void updateInventory() {
// FIXME: make player item sale price ratio adjustable
- player.send(player.inventory.createTransactionMessage(MSG_INVENTORY, 0.5f));
+ player.send(player.inventory.createTransactionMessage(player.game, MSG_INVENTORY, 0.5f));
}
void updateConditions() {
}*/
if (dx != 0 || dy != 0) {
- System.out.println("Thing " + thing.name + " moved: " + dx + ", " + dy);
+ System.out.println("Thing " + thing.getName() + " moved: " + dx + ", " + dy);
// TODO: rather than relative move, send the specific location/faceing direction?
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
+import com.sleepycat.persist.model.PrimaryKey;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import static duskz.server.entityz.Active.STAT_CON;
import static duskz.server.entityz.Active.STAT_DEX;
import static duskz.server.entityz.Active.STAT_HP;
import duskz.server.entityz.PropertyLoader.PropertyEntry;
import java.io.File;
import java.io.IOException;
+import java.util.HashMap;
/**
* Meta-data about race
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Entity(version = 2)
public class Race {
+ @PrimaryKey(sequence = "RaceID")
+ long ID;
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE)
public String name;
+ public String description;
public int image;
// Uses STAT_* constants from Active
public int stats[] = new int[12];
+ Inventory2 inventory = new Inventory2();
+ ConditionList conditionList = new ConditionList();
+ private HashMap<String, Ability> skills = new HashMap<>();
+ public String onBattle;
+ public String onDefeated;
+
+ public Race() {
+ }
+
+ public void addSkill(String name, int level) {
+ Ability a = skills.get(name);
+
+ if (a != null) {
+ level += a.getLevel();
+ }
+ skills.put(name, new Ability(name, level));
+ }
- Race() {
+ public void setCondition(String name, int duration) {
+ conditionList.setCondition(new Condition(name, duration));
+ }
+
+ public void addInventory(Holdable what, long wear, int used, boolean don) {
+ Held h = new Held(what);
+
+ h.wear = wear;
+ h.used = used;
+
+ inventory.add(h);
+ if (don)
+ inventory.wear(h);
}
boolean setProperty(String name, String value) {
r.name = file.getName();
try (PropertyLoader pl = new PropertyLoader(file)) {
- for (PropertyEntry pe: pl) {
+ for (PropertyEntry pe : pl) {
r.setProperty(pe.name, pe.value);
}
}
-
+
return r;
}
}
*/
public abstract class Shop extends Thing {
- Inventory items = new Inventory();
+ Inventory2 items = new Inventory2();
/**
* Tick of last inventory change.
*/
case "item":
Holdable h = game.createItem(value);
if (h != null) {
- System.out.println(this.name + " sells " + h.name);
- items.add(h);
+ System.out.println(this.getName() + " sells " + h.getName());
+ items.add(new Held(h));
} else
- game.log.printf(Log.ERROR, "Shop: %s, unkown item: %s", this.name, value);
+ game.log.printf(Log.ERROR, "Shop: %s, unkown item: %s", this.getName(), value);
break;
default:
super.setProperty(name, value);
* @param name
* @return
*/
- public TransactionMessage createTransactionMessage(int name) {
- return items.createTransactionMessage(name, 1);
+ public TransactionMessage createTransactionMessage(Game game, int name) {
+ return items.createTransactionMessage(game, name, 1);
}
@Override
public void look(Active viewer) {
if (description != null)
- viewer.chatMessage("You see " + name + ", " + description);
+ viewer.chatMessage("You see " + getName() + ", " + description);
else
- viewer.chatMessage("You see " + name);
+ viewer.chatMessage("You see " + getName());
viewer.chatMessage("Currently for sale:");
items.describeTo(viewer);
abstract public void buy(Active buyer, String what, int quantity);
- abstract public void sell(Active customer, List<Holdable> items);
+ abstract public void sell(Active customer, List<Held> items);
}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Entity;
import java.io.BufferedWriter;
import java.io.IOException;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Entity(version = 0)
class Sign extends Thing {
+ public Sign() {
+ }
+
public Sign(Game game) {
super(game);
}
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.NotPersistent;
+import com.sleepycat.persist.model.Persistent;
+import com.sleepycat.persist.model.PrimaryKey;
+import com.sleepycat.persist.model.Relationship;
+import com.sleepycat.persist.model.SecondaryKey;
import duskz.protocol.DuskMessage;
import duskz.protocol.EntityUpdateMessage;
import duskz.server.entityz.PropertyLoader.PropertyEntry;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public abstract class Thing implements Cloneable {
/**
public final static Comparator<Thing> cmpName = new Comparator<Thing>() {
@Override
public int compare(Thing o1, Thing o2) {
- return o1.name.compareTo(o2.name);
+ return o1.getName().compareTo(o2.getName());
}
};
- protected final Game game;
+ transient protected Game game;
/**
* Game unique id
*/
- public final long ID;
+ @PrimaryKey(sequence = "ID")
+ public long ID;
/**
* Name
+ * FIXME: this wont work for mobs will it?
*/
- public String name;
+ @SecondaryKey(relate = Relationship.ONE_TO_ONE)
+ private String name;
/**
* Description
*/
* /**
* Map object belongs to
*/
+ @NotPersistent
public TileMap map;
/**
* Location on map
/**
* Current image id. TODO: players get images from race instead.
*/
- protected int image;
+ public int image;
//
static long nextid = 1;
static Integer idlock = new Integer(0);
}
}
+ protected Thing() {
+ }
+
+ protected void setGame(Game game) {
+ this.game = game;
+ }
+
public Thing(Game game) {
this.ID = createID();
this.game = game;
en.name = name;
en.id = ID;
- en.entityName = this.name;
+ en.entityName = this.getName();
en.entityType = (byte) getType();
en.x = (short) x;
en.y = (short) y;
void setProperty(String name, String value) {
switch (name) {
case "name":
- this.name = value;
+ this.setName(value);
break;
case "description":
this.description = value;
* @throws IOException
*/
protected void writeProperties(BufferedWriter out) throws IOException {
- writeProperty(out, "name", name);
+ writeProperty(out, "name", getName());
writeProperty(out, "description", description);
writeProperty(out, "map", map.name);
writeProperty(out, "x", x);
* @throws IOException
*/
void writeState(BufferedWriter out) throws IOException {
- writeProperty(out, "name", name);
+ writeProperty(out, "name", getName());
writeProperty(out, "x", x);
writeProperty(out, "y", y);
}
out.append("type.");
out.append(getClass().getSimpleName());
out.append('=');
- out.append(name);
+ out.append(getName());
out.append('\n');
}
}
}
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
public interface ThingResolver {
Thing resolve(Game game, String klass, String name);
Thing thing = null;
try {
thing = createThing(game, klass);
- thing.name = name;
+ thing.setName(name);
thing.load(new File(base, name));
} catch (ClassNotFoundException | IOException ex) {
System.out.println("Cannot load prototype: " + ex);
Thing thing = null;
try {
thing = createThing(game, klass);
- thing.name = name;
+ thing.setName(name);
} catch (ClassNotFoundException ex) {
System.out.println("Cannot load prototype: " + ex);
}
add(thing);
}
} catch (IOException ex) {
- ex.printStackTrace();
+ ex.printStackTrace(System.out);
}
}
}
public void add(T thing) {
- HashSet<T> set = byName.get(thing.name);
+ HashSet<T> set = byName.get(thing.getName());
if (set == null) {
set = new HashSet<>();
- byName.put(thing.name, set);
+ byName.put(thing.getName(), set);
}
set.add(thing);
byID.put(thing.ID, thing);
}
public void remove(T thing) {
- HashSet<T> set = byName.get(thing.name);
+ HashSet<T> set = byName.get(thing.getName());
set.remove(thing);
if (set.isEmpty())
- byName.remove(thing.name);
+ byName.remove(thing.getName());
byID.remove(thing.ID);
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
// TODO: gzip?
public static final int MAGIC_LAYERED = 0x6d61707a;
+ /**
+ * Load just the map part of a map.
+ *
+ * TODO: sort something out with the alias stuff and loadLayered()
+ *
+ * @param is
+ * @param name
+ * @return
+ * @throws IOException
+ */
+ public static TileMap loadLayeredMap(InputStream is, String name) throws IOException {
+ TileMap map;
+
+ try (DataInputStream mapFile = new DataInputStream((is))) {
+ int magic = mapFile.readInt();
+ int version = mapFile.readInt();
+ int flags = mapFile.readInt();
+ int cols = mapFile.readInt();
+ int rows = mapFile.readInt();
+ int groundLayer = mapFile.readInt();
+ int layerCount = mapFile.readInt();
+
+ if (magic != MAGIC_LAYERED
+ || version != 0) {
+ throw new IOException("Invalid format/magic/unknown version");
+ }
+
+ System.out.println("Load map: " + name);
+ System.out.printf(" size: %dx%d\n", cols, rows);
+ System.out.printf(" groundLayer: %d\n", groundLayer);
+ System.out.printf(" layerCount: %d\n", layerCount);
+
+ map = new TileMap(name, cols, rows);
+
+ map.groundLayer = groundLayer;
+ map.layers = new TileLayer[layerCount];
+ for (int l = 0; l < layerCount; l++) {
+ int tx = mapFile.readInt();
+ int ty = mapFile.readInt();
+ int twidth = mapFile.readInt();
+ int theight = mapFile.readInt();
+ TileLayer tl;
+
+ System.out.printf(" layer %2d: at %3d,%3d size %3dx%3d\n", l, tx, ty, twidth, theight);
+ if (l == groundLayer)
+ tl = new TileLayer(tx, ty, twidth, theight, map.tiles);
+ else
+ tl = new TileLayer(tx, ty, twidth, theight);
+
+ map.layers[l] = tl;
+
+ for (int i = 0; i < twidth * theight; i++) {
+ tl.tiles[i] = mapFile.readShort();
+ }
+ }
+ }
+ return map;
+ }
+
/**
* Load a layered map. Format is:
* magic: int
public String getUnits() {
return "exp";
}
+
+ public void setSkill(String skill) {
+ this.skill = skill;
+ }
@Override
void setProperty(String name, String value) {
*/
package duskz.server.entityz;
+import com.sleepycat.persist.model.Persistent;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
*
* @author Michael Zucchi <notzed@gmail.com>
*/
+@Persistent
public class VariableList {
private HashMap<String, Object> map = new HashMap<>();
*/
public class Weapon extends Wearable {
- int range = 1;
+ public int range = 1;
public Weapon(Game game) {
super(game);
*/
public abstract class Wearable extends Holdable {
- int mod;
- long durability;
- String onWear, onUnwear;
+ public int mod;
+ public long durability;
+ public String onWear, onUnwear;
Wearable(Game game) {
super(game);