diff --git a/alone-rl.iml b/alone-rl.iml
index 942698b..e8ac48a 100644
--- a/alone-rl.iml
+++ b/alone-rl.iml
@@ -15,7 +15,7 @@
-
+
diff --git a/data/crafting.yml b/data/crafting.yml
index df53828..31f287f 100644
--- a/data/crafting.yml
+++ b/data/crafting.yml
@@ -3,7 +3,7 @@ sharp-stone:
sources: stone
tools: stone
-small-sharp-stone:
+stone-knife:
sources: sharp-stone
tools: stone
@@ -16,5 +16,17 @@ stone-axe:
tools: stone
stone-spear:
- sources: [small-sharp-stone, trunk, vine]
- tools: stone
+ sources: [stone-knife, trunk, vine]
+ tools: [stone-axe, stone-knife]
+
+arrow:
+ sources: branch
+ tools: stone-knife
+
+stone-arrow:
+ sources: [stone-knife, branch, vine]
+ tools: stone-knife
+
+bow:
+ sources: [trunk, vine]
+ tools: [stone-axe, stone-knife]
diff --git a/data/items.yml b/data/items.yml
index 13bc993..0855fe6 100644
--- a/data/items.yml
+++ b/data/items.yml
@@ -90,8 +90,8 @@ sharp-stone:
blue: 88
alpha: 255
-small-sharp-stone:
- name: a small, sharp stone
+stone-knife:
+ name: a stone knife
wearable:
where: HANDS
weapon:
@@ -143,7 +143,52 @@ stone-spear:
damageType: POINT
damage: 4
sprite:
- c: 244
+ c: 124
+ col:
+ red: 141
+ green: 104
+ blue: 21
+ alpha: 255
+
+arrow:
+ name: an arrow
+ weapon:
+ damageType: POINT
+ damage: 2
+ ammo:
+ usableBy: bow
+ sprite:
+ c: 196
+ col:
+ red: 141
+ green: 104
+ blue: 21
+ alpha: 255
+
+stone-arrow:
+ name: a stone-tip arrow
+ weapon:
+ damageType: POINT
+ damage: 3
+ ammo:
+ usableBy: bow
+ sprite:
+ c: 26
+ col:
+ red: 141
+ green: 104
+ blue: 21
+ alpha: 255
+
+bow:
+ name: a simple bow
+ wearable:
+ where: HANDS
+ weapon:
+ damageType: SHOOTER
+ damage: 1
+ sprite:
+ c: '('
col:
red: 141
green: 104
diff --git a/pom.xml b/pom.xml
index 76493e4..f7ef509 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
com.github.fabio-t
alone-rl
- 0.2.6
+ 0.2.7
jar
AloneRL
@@ -59,7 +59,7 @@
com.github.fabio-t
terrain-generator
- 0.1.0
+ 0.1.1
diff --git a/src/main/java/com/github/fabioticconi/alone/components/Ammo.java b/src/main/java/com/github/fabioticconi/alone/components/Ammo.java
new file mode 100644
index 0000000..6724db5
--- /dev/null
+++ b/src/main/java/com/github/fabioticconi/alone/components/Ammo.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015-2018 Fabio Ticconi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.github.fabioticconi.alone.components;
+
+import com.artemis.Component;
+
+/**
+ * Author: Fabio Ticconi
+ * Date: 02/03/18
+ */
+public class Ammo extends Component
+{
+ public String usableBy;
+
+ public Ammo()
+ {
+
+ }
+
+ public Ammo(final String usableBy)
+ {
+ this.usableBy = usableBy;
+ }
+}
diff --git a/src/main/java/com/github/fabioticconi/alone/components/Armour.java b/src/main/java/com/github/fabioticconi/alone/components/Armour.java
index 12577b5..ff2dce4 100644
--- a/src/main/java/com/github/fabioticconi/alone/components/Armour.java
+++ b/src/main/java/com/github/fabioticconi/alone/components/Armour.java
@@ -19,7 +19,7 @@
package com.github.fabioticconi.alone.components;
import com.artemis.Component;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import java.util.EnumMap;
@@ -29,22 +29,22 @@
*/
public class Armour extends Component
{
- // TODO we can improve this by using a primitive float array and WeaponType ordinals as indeces.
+ // TODO we can improve this by using a primitive float array and DamageType ordinals as indeces.
// which is what EnumMap does internally. We'd avoid autoboxing.
- public final EnumMap defences;
+ public final EnumMap defences;
public Armour()
{
- this.defences = new EnumMap<>(WeaponType.class);
+ this.defences = new EnumMap<>(DamageType.class);
}
public void set(final float slash, final float point, final float blunt, final float natural)
{
- this.defences.put(WeaponType.SLASH, slash);
- this.defences.put(WeaponType.POINT, point);
- this.defences.put(WeaponType.BLUNT, blunt);
+ this.defences.put(DamageType.SLASH, slash);
+ this.defences.put(DamageType.POINT, point);
+ this.defences.put(DamageType.BLUNT, blunt);
// a generic type for animal attacks
- this.defences.put(WeaponType.NATURAL, natural);
+ this.defences.put(DamageType.NATURAL, natural);
}
}
diff --git a/src/main/java/com/github/fabioticconi/alone/components/Weapon.java b/src/main/java/com/github/fabioticconi/alone/components/Weapon.java
index ffae2e5..981c090 100644
--- a/src/main/java/com/github/fabioticconi/alone/components/Weapon.java
+++ b/src/main/java/com/github/fabioticconi/alone/components/Weapon.java
@@ -19,7 +19,7 @@
package com.github.fabioticconi.alone.components;
import com.artemis.Component;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
/**
* Author: Fabio Ticconi
@@ -27,7 +27,7 @@
*/
public class Weapon extends Component
{
- public WeaponType damageType;
+ public DamageType damageType;
public float damage;
public Weapon()
@@ -35,12 +35,12 @@ public Weapon()
}
- public Weapon(final WeaponType damageType, final float damage)
+ public Weapon(final DamageType damageType, final float damage)
{
set(damageType, damage);
}
- public void set(final WeaponType damageType, final float damage)
+ public void set(final DamageType damageType, final float damage)
{
this.damageType = damageType;
this.damage = damage;
diff --git a/src/main/java/com/github/fabioticconi/alone/constants/WeaponType.java b/src/main/java/com/github/fabioticconi/alone/constants/DamageType.java
similarity index 94%
rename from src/main/java/com/github/fabioticconi/alone/constants/WeaponType.java
rename to src/main/java/com/github/fabioticconi/alone/constants/DamageType.java
index 8861d7d..cf3e8fe 100644
--- a/src/main/java/com/github/fabioticconi/alone/constants/WeaponType.java
+++ b/src/main/java/com/github/fabioticconi/alone/constants/DamageType.java
@@ -22,10 +22,11 @@
* Author: Fabio Ticconi
* Date: 04/11/17
*/
-public enum WeaponType
+public enum DamageType
{
SLASH,
POINT,
BLUNT,
- NATURAL
+ NATURAL,
+ SHOOTER
}
diff --git a/src/main/java/com/github/fabioticconi/alone/messages/ShootMsg.java b/src/main/java/com/github/fabioticconi/alone/messages/ShootMsg.java
new file mode 100644
index 0000000..99c3a93
--- /dev/null
+++ b/src/main/java/com/github/fabioticconi/alone/messages/ShootMsg.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015-2018 Fabio Ticconi
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package com.github.fabioticconi.alone.messages;
+
+import com.github.fabioticconi.alone.constants.Side;
+
+import java.awt.*;
+
+/**
+ * Author: Fabio Ticconi
+ * Date: 01/11/17
+ */
+public class ShootMsg extends AbstractMessage
+{
+ public final String item;
+ public final Side at;
+
+ public ShootMsg(final String item, final Side at)
+ {
+ this.item = item;
+ this.at = at;
+ }
+
+ @Override
+ public String format()
+ {
+ fgCol = Color.RED;
+
+ return String.format("%s %s %s towards %s",
+ actor,
+ thirdPerson ? "shoots" : "shoot",
+ item.toLowerCase(),
+ at.toString());
+ }
+}
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java
index b3becb2..adf2dc1 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/MapScreen.java
@@ -57,9 +57,10 @@ void regenerate()
final int seed = (int) (System.currentTimeMillis() / 1000);
final float freq = 3f / Math.max(Options.MAP_SIZE_X, Options.MAP_SIZE_Y);
- final HeightMap heightMap = new HeightMap().size(Options.MAP_SIZE_X, Options.MAP_SIZE_Y)
- .island(0.85f)
- .rivers(0.8f, 0.03f, 0.001f);
+ final HeightMap heightMap = new HeightMap()
+ .size(Options.MAP_SIZE_X, Options.MAP_SIZE_Y)
+ .island(0.85f)
+ .rivers(0.8f, 0.03f, 0.001f, 1);
heightMap.fractalNoise
.seed(seed)
diff --git a/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java b/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
index cb00f04..f56eb45 100644
--- a/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
+++ b/src/main/java/com/github/fabioticconi/alone/screens/PlayScreen.java
@@ -26,8 +26,8 @@
import com.github.fabioticconi.alone.Main;
import com.github.fabioticconi.alone.components.*;
import com.github.fabioticconi.alone.components.attributes.Sight;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.constants.Side;
-import com.github.fabioticconi.alone.constants.WeaponType;
import com.github.fabioticconi.alone.messages.AbstractMessage;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.Msg;
@@ -193,7 +193,7 @@ else if (keys.get(KeyEvent.VK_T))
{
keys.clear();
- final int weaponId = sItems.getWeapon(playerId, EnumSet.allOf(WeaponType.class), true);
+ final int weaponId = sItems.getWeapon(playerId, EnumSet.allOf(DamageType.class), true);
if (weaponId < 0)
{
@@ -204,6 +204,10 @@ else if (keys.get(KeyEvent.VK_T))
return 0f;
}
+
+ Main.pause();
+
+ screen.select(LookScreen.class);
}
else if (keys.get(KeyEvent.VK_W))
{
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/AttackSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/AttackSystem.java
index cf7f624..cc8dfc9 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/AttackSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/AttackSystem.java
@@ -25,7 +25,7 @@
import com.github.fabioticconi.alone.components.attributes.Agility;
import com.github.fabioticconi.alone.components.attributes.Skin;
import com.github.fabioticconi.alone.components.attributes.Strength;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.messages.DamageMsg;
import com.github.fabioticconi.alone.messages.KillMsg;
import com.github.fabioticconi.alone.messages.MissMsg;
@@ -35,6 +35,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.EnumSet;
import java.util.Random;
/**
@@ -137,23 +138,28 @@ public void doAction()
if (r.nextFloat() < toHit)
{
- float damage = cStrength.value + 2f;
- float armour = tSkin.value;
-
- // assuming the actor is unharmed, we use a generic "natural" attack
- WeaponType dmgType = WeaponType.NATURAL;
+ float damage = cStrength.value + 2f;
+ float armour = tSkin.value;
+ DamageType dmgType = DamageType.NATURAL;
// the weapon damage is added to the strength-based one, so that creatures
// wielding weapons can overcome stronger, unharmed creatures
- final int weaponId = sItem.getWeapon(actorId);
+ final int weaponId = sItem.getWeapon(actorId, EnumSet.allOf(DamageType.class), true);
if (weaponId >= 0)
{
final Weapon w = mWeapon.get(weaponId);
damage += w.damage;
dmgType = w.damageType;
}
+ // or maybe we ARE a weapon (eg, if thrown or shot)
+ else if (mWeapon.has(actorId))
+ {
+ final Weapon w = mWeapon.get(actorId);
+ damage += w.damage;
+ dmgType = w.damageType;
+ }
- final int armourId = sItem.getArmour(targetId);
+ final int armourId = sItem.getArmour(targetId, true);
if (armourId >= 0)
{
final Armour a = mArmour.get(armourId);
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/CrushSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/CrushSystem.java
index bcab54e..7d4e288 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/CrushSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/CrushSystem.java
@@ -25,7 +25,7 @@
import com.github.fabioticconi.alone.components.Weapon;
import com.github.fabioticconi.alone.components.actions.ActionContext;
import com.github.fabioticconi.alone.components.attributes.Strength;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.CrushMsg;
import net.mostlyoriginal.api.system.core.PassiveSystem;
@@ -77,7 +77,7 @@ public boolean tryAction()
if (targetId < 0 || !mCrush.has(targetId))
return false;
- final int hammerId = sItem.getWeapon(actorId, EnumSet.of(WeaponType.BLUNT), true);
+ final int hammerId = sItem.getWeapon(actorId, EnumSet.of(DamageType.BLUNT), true);
if (hammerId < 0)
{
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
index 6d675e8..c85da37 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/ItemSystem.java
@@ -25,7 +25,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fabioticconi.alone.components.*;
import com.github.fabioticconi.alone.components.actions.ActionContext;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.DropMsg;
import com.github.fabioticconi.alone.messages.EquipMsg;
@@ -58,6 +58,7 @@ public class ItemSystem extends PassiveSystem
ComponentMapper mArmour;
ComponentMapper mName;
ComponentMapper mObstacle;
+ ComponentMapper mAmmo;
MessageSystem msg;
MapSystem map;
@@ -176,6 +177,8 @@ public int makeItem(final String tag)
edit.add(template.crushable);
if (template.cuttable != null)
edit.add(template.cuttable);
+ if (template.ammo != null)
+ edit.add(template.ammo);
return id;
}
@@ -209,11 +212,6 @@ public EquipAction equip(final int actorId, final int targetId)
return a;
}
- public int getArmour(final int entityId)
- {
- return getArmour(entityId, true);
- }
-
public int getArmour(final int entityId, final boolean onlyEquipped)
{
final Inventory items = mInventory.get(entityId);
@@ -233,7 +231,7 @@ public int getArmour(final int entityId, final boolean onlyEquipped)
continue;
}
- // we might only want an equipped weapon
+ // we might only want a worn armour
if (!mArmour.has(itemId) || (onlyEquipped && !mEquip.has(itemId)))
continue;
@@ -268,17 +266,36 @@ public int getItem(final int entityId, final String tag, final boolean onlyEquip
return -1;
}
- public int getWeapon(final int entityId)
+ public int getAmmo(final int entityId, final String usableBy)
{
- return getWeapon(entityId, true);
+ final Inventory items = mInventory.get(entityId);
+
+ if (items == null)
+ return -1;
+
+ final int[] data = items.items.getData();
+ for (int i = 0, size = items.items.size(); i < size; i++)
+ {
+ final int itemId = data[i];
+
+ if (!mAmmo.has(itemId))
+ continue;
+
+ final Ammo ammo = mAmmo.get(itemId);
+
+ if (ammo.usableBy.equals(usableBy))
+ return itemId;
+ }
+
+ return -1;
}
public int getWeapon(final int entityId, final boolean onlyEquipped)
{
- return getWeapon(entityId, EnumSet.allOf(WeaponType.class), onlyEquipped);
+ return getWeapon(entityId, EnumSet.allOf(DamageType.class), onlyEquipped);
}
- public int getWeapon(final int entityId, final EnumSet weaponTypes, final boolean onlyEquipped)
+ public int getWeapon(final int entityId, final EnumSet damageTypes, final boolean onlyEquipped)
{
final Inventory items = mInventory.get(entityId);
@@ -296,7 +313,7 @@ public int getWeapon(final int entityId, final EnumSet weaponTypes,
final Weapon weapon = mWeapon.get(itemId);
- if (weaponTypes.contains(weapon.damageType))
+ if (damageTypes.contains(weapon.damageType))
return itemId;
}
@@ -314,6 +331,7 @@ public static class ItemTemplate
public Obstacle obstacle;
public Crushable crushable;
public Cuttable cuttable;
+ public Ammo ammo;
}
public class GetAction extends ActionContext
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/ThrowSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/ThrowSystem.java
index 0f84a67..973095a 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/ThrowSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/ThrowSystem.java
@@ -24,7 +24,7 @@
import com.github.fabioticconi.alone.components.attributes.Agility;
import com.github.fabioticconi.alone.components.attributes.Strength;
import com.github.fabioticconi.alone.constants.Side;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.ThrowMsg;
import com.github.fabioticconi.alone.utils.Coords;
@@ -53,6 +53,7 @@ public class ThrowSystem extends PassiveSystem
ComponentMapper mAgility;
ComponentMapper mName;
ComponentMapper mEquip;
+ ComponentMapper mWeapon;
StaminaSystem sStamina;
BumpSystem sBump;
@@ -73,6 +74,8 @@ public class ThrowAction extends ActionContext
{
public List path;
+ float cooldown;
+
@Override
public boolean tryAction()
{
@@ -99,7 +102,7 @@ public boolean tryAction()
if (inventory == null)
return false;
- final int weaponId = sItem.getWeapon(actorId, EnumSet.allOf(WeaponType.class), true);
+ int weaponId = sItem.getWeapon(actorId, EnumSet.allOf(DamageType.class), true);
if (weaponId < 0)
{
@@ -108,6 +111,27 @@ public boolean tryAction()
return false;
}
+ cooldown = 0.06f;
+
+ final Weapon weapon = mWeapon.get(weaponId);
+
+ if (weapon.damageType == DamageType.SHOOTER)
+ {
+ final Name bowName = mName.get(weaponId);
+
+ // the ammo will be thrown at the next step, not the bow
+ weaponId = sItem.getAmmo(actorId, bowName.tag);
+
+ cooldown = 0.04f;
+
+ if (weaponId < 0)
+ {
+ msg.send(actorId, new CannotMsg("shoot", "with only ".concat(bowName.name)));
+
+ return false;
+ }
+ }
+
// it's close enough to strike, so we transform this in a bump action
if (Coords.distanceChebyshev(p.x, p.y, t.pos.x, t.pos.y) == 1)
{
@@ -163,7 +187,6 @@ public void doAction()
// how long does it take the object to move one step?
// TODO should be based on thrower's strength and weapon characteristics, maybe
- final float cooldown = 0.05f;
mSpeed.create(weaponId).set(cooldown);
mPath.create(weaponId).set(cooldown, path);
diff --git a/src/main/java/com/github/fabioticconi/alone/systems/TreeSystem.java b/src/main/java/com/github/fabioticconi/alone/systems/TreeSystem.java
index 0945322..ccde487 100644
--- a/src/main/java/com/github/fabioticconi/alone/systems/TreeSystem.java
+++ b/src/main/java/com/github/fabioticconi/alone/systems/TreeSystem.java
@@ -24,7 +24,7 @@
import com.github.fabioticconi.alone.components.Speed;
import com.github.fabioticconi.alone.components.actions.ActionContext;
import com.github.fabioticconi.alone.components.attributes.Strength;
-import com.github.fabioticconi.alone.constants.WeaponType;
+import com.github.fabioticconi.alone.constants.DamageType;
import com.github.fabioticconi.alone.messages.CannotMsg;
import com.github.fabioticconi.alone.messages.CutMsg;
import net.mostlyoriginal.api.system.core.PassiveSystem;
@@ -75,7 +75,7 @@ public boolean tryAction()
if (!mCuttable.has(treeId))
return false;
- final int axeId = sItem.getWeapon(actorId, EnumSet.of(WeaponType.SLASH), false);
+ final int axeId = sItem.getWeapon(actorId, EnumSet.of(DamageType.SLASH), false);
if (axeId < 0)
{