Implemented ammo ressuplying

This commit is contained in:
Anuken
2018-04-24 21:38:57 -04:00
parent 8581213126
commit deefab8a5b
25 changed files with 259 additions and 114 deletions

View File

@@ -1,16 +1,16 @@
package io.anuke.mindustry.content;
import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.content.fx.ShootFx;
import io.anuke.mindustry.resource.Weapon;
public class Weapons {
public static final Weapon
blaster = new Weapon("blaster", 12, TurretBullets.basicIron) {
{
effect = ShootFx.shootSmall;
length = 2f;
}
};
blaster = new Weapon("blaster") {{
length = 1.5f;
reload = 15f;
roundrobin = true;
ejectEffect = ShootFx.shellEjectSmall;
setAmmo(AmmoTypes.basicIron);
}};
}

View File

@@ -90,15 +90,16 @@ public class ShootFx {
shellEjectSmall = new GroundEffect(30f, 400f, e -> {
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
float rot = e.rotation + 90f;
for(int i : Mathf.signs){
float len = (2f + e.finpow()*6f) * i;
float lr = rot + e.fin()*30f*i;
Draw.rect("white",
e.x + Angles.trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()),
e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()),
1f, 2f, rot + e.fin()*50f*i);
}
float rot = Math.abs(e.rotation) + 90f;
int i = Mathf.sign(e.rotation);
float len = (2f + e.finpow()*6f) * i;
float lr = rot + e.fin()*30f*i;
Draw.rect("white",
e.x + Angles.trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()),
e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()),
1f, 2f, rot + e.fin()*50f*i);
Draw.color();
}),

View File

@@ -143,7 +143,7 @@ public class Control extends Module{
Events.on(ResetEvent.class, () -> {
upgrades.reset();
player.weaponLeft = player.weaponRight = Weapons.blaster;
player.weapon = Weapons.blaster;
player.team = Team.blue;
player.inventory.clear();

View File

@@ -26,8 +26,8 @@ public class NetCommon extends Module {
if (player == null) return;
player.weaponLeft = Upgrade.getByID(packet.left);
player.weaponRight = Upgrade.getByID(packet.right);
player.weapon = Upgrade.getByID(packet.weapon);
player.weapon = Upgrade.getByID(packet.weapon);
});
Net.handle(BlockTapPacket.class, (packet) -> {

View File

@@ -35,6 +35,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.EffectEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.*;
@@ -65,7 +66,7 @@ public class Renderer extends RendererModule{
Lines.setCircleVertices(14);
Core.cameraScale = baseCameraScale;
Effects.setEffectProvider((effect, color, x, y, rotation) -> {
Effects.setEffectProvider((effect, color, x, y, rotation, data) -> {
if(effect == Fx.none) return;
if(Settings.getBool("effects")){
Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight)
@@ -82,6 +83,10 @@ public class Renderer extends RendererModule{
entity.rotation = rotation;
entity.lifetime = effect.lifetime;
id = entity.set(x, y).add(effectGroup).id;
if(data instanceof Entity){
entity.setParent((Entity)data);
}
}
if(effect instanceof GroundEffect){

View File

@@ -27,6 +27,7 @@ public class Bullet extends BulletEntity<BulletType>{
bullet.owner = owner;
bullet.velocity.set(0, type.speed).setAngle(angle);
bullet.velocity.add(owner instanceof Unit ? ((Unit)owner).velocity : Vector2.Zero);
bullet.hitbox.setSize(type.hitsize);
bullet.team = team;

View File

@@ -11,10 +11,7 @@ import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.resource.Mech;
import io.anuke.mindustry.resource.Upgrade;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.resource.*;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Effects;
@@ -23,10 +20,7 @@ import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
import io.anuke.ucore.util.Translator;
import io.anuke.ucore.util.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -46,8 +40,7 @@ public class Player extends Unit{
public boolean isAdmin;
public Color color = new Color();
public Weapon weaponLeft = Weapons.blaster;
public Weapon weaponRight = Weapons.blaster;
public Weapon weapon = Weapons.blaster;
public Mech mech = Mechs.standard;
public float targetAngle = 0f;
@@ -72,8 +65,8 @@ public class Player extends Unit{
@Override
public void onRemoteShoot(BulletType type, float x, float y, float rotation, short data) {
Weapon weapon = Upgrade.getByID((byte)data);
weapon.shoot(player, x, y, rotation);
Weapon weapon = Upgrade.getByID(Bits.getLeftByte(data));
weapon.shoot(player, x, y, rotation, Bits.getRightByte(data) == 1);
}
@Override
@@ -184,8 +177,7 @@ public class Player extends Unit{
Draw.rect(mname, x, y, rotation -90);
for (int i : Mathf.signs) {
Weapon weapon = i < 0 ? weaponLeft : weaponRight;
tr.trns(rotation - 90, 4*i, 3);
tr.trns(rotation - 90, 4*i, 3 - weapon.getRecoil(this, i > 0)*1.5f);
float w = i > 0 ? -8 : 8;
Draw.rect(weapon.name + "-equip", x + tr.x, y + tr.y, w, 8, rotation - 90);
}
@@ -269,8 +261,8 @@ public class Player extends Unit{
boolean shooting = control.input().canShoot() && control.input().isShooting();
if(shooting){
weaponLeft.update(player, true);
weaponRight.update(player, false);
weapon.update(player, true);
weapon.update(player, false);
}
if(dashing && timer.get(timerDash, 3) && movement.len() > 0){
@@ -302,6 +294,16 @@ public class Player extends Unit{
rotation = Mathf.slerpDelta(rotation, targetAngle, 0.2f);
}
@Override
public boolean acceptsAmmo(Item item) {
return weapon.getAmmoType(item) != null && inventory.canAcceptAmmo(weapon.getAmmoType(item));
}
@Override
public void addAmmo(Item item) {
inventory.addAmmo(weapon.getAmmoType(item));
}
@Override
public Player add(){
return add(playerGroup);
@@ -339,8 +341,7 @@ public class Player extends Unit{
public void writeSpawn(ByteBuffer buffer) {
buffer.put((byte)name.getBytes().length);
buffer.put(name.getBytes());
buffer.put(weaponLeft.id);
buffer.put(weaponRight.id);
buffer.put(weapon.id);
buffer.put(mech.id);
buffer.put(isAdmin ? 1 : (byte)0);
buffer.putInt(Color.rgba8888(color));
@@ -355,8 +356,7 @@ public class Player extends Unit{
byte[] n = new byte[nlength];
buffer.get(n);
name = new String(n);
weaponLeft = Upgrade.getByID(buffer.get());
weaponRight = Upgrade.getByID(buffer.get());
weapon = Upgrade.getByID(buffer.get());
mech = Upgrade.getByID(buffer.get());
isAdmin = buffer.get() == 1;
color.set(buffer.getInt());

View File

@@ -3,6 +3,7 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Effects;
@@ -18,12 +19,13 @@ import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends SyncEntity implements SerializableEntity {
//total duration of hit effect
/**total duration of hit flash effect*/
public static final float hitDuration = 9f;
public StatusController status = new StatusController();
public UnitInventory inventory = new UnitInventory(100);
public UnitInventory inventory = new UnitInventory(100, 100);
public Team team = Team.blue;
public Vector2 velocity = new Vector2();
public float hitTime;
public float drownTime;
@@ -146,6 +148,8 @@ public abstract class Unit extends SyncEntity implements SerializableEntity {
}
}
public abstract boolean acceptsAmmo(Item item);
public abstract void addAmmo(Item item);
public abstract float getMass();
public abstract boolean isFlying();
public abstract float getSize();

View File

@@ -5,10 +5,37 @@ import io.anuke.mindustry.resource.*;
public class UnitInventory {
private final AmmoEntry ammo = new AmmoEntry(AmmoType.getByID(0), 0);
private ItemStack item;
private int capacity;
private int capacity, ammoCapacity;
public UnitInventory(int capacity) {
public UnitInventory(int capacity, int ammoCapacity) {
this.capacity = capacity;
this.ammoCapacity = ammoCapacity;
}
public AmmoType getAmmo() {
return ammo.type;
}
public boolean hasAmmo(){
return ammo.amount > 0;
}
public void useAmmo(){
ammo.amount --;
}
public int ammoCapacity(){
return ammoCapacity;
}
public boolean canAcceptAmmo(AmmoType type){
return ammo.amount + type.quantityMultiplier <= ammoCapacity;
}
public void addAmmo(AmmoType type){
if(ammo.type != type) ammo.amount = 0;
ammo.type = type;
ammo.amount += Math.min((int)type.quantityMultiplier, ammoCapacity - ammo.amount);
}
public int capacity(){
@@ -33,6 +60,8 @@ public class UnitInventory {
public void clear(){
item = null;
ammo.amount = 0;
ammo.type = AmmoType.getByID(0);
}
public boolean hasItem(){
@@ -48,7 +77,6 @@ public class UnitInventory {
}
}
public ItemStack getItem(){
if(!hasItem()) throw new RuntimeException("This inventory has no item! Check hasItem() first.");
return item;

View File

@@ -96,6 +96,20 @@ public class Units {
return result[0];
}
/**Iterates over all units in a rectangle.*/
public static void getNearby(Team team, Rectangle rect, Consumer<Unit> cons){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
if(!group.isEmpty()){
Entities.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
//now check all enemy players
Entities.getNearby(playerGroup, rect, player -> {
if(((Unit)player).team == team) cons.accept((Unit)player);
});
}
/**Iterates over all units in a rectangle.*/
public static void getNearby(Rectangle rect, Consumer<Unit> cons){
@@ -128,4 +142,6 @@ public class Units {
}
});
}
}

View File

@@ -47,7 +47,7 @@ public class GroundEffectEntity extends EffectEntity {
public GroundEffect(float life, float staticLife, EffectRenderer draw) {
super(life, draw);
this.staticLife = staticLife;
this.isStatic = false;
this.isStatic = true;
}
public GroundEffect(boolean isStatic, float life, EffectRenderer draw) {

View File

@@ -0,0 +1,44 @@
package io.anuke.mindustry.entities.effect;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.resource.Item;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
public class ItemTransferEffect extends Entity {
private static final float size = 5f;
private static final float alpha = 0.1f;
private final Item item;
private final Entity target;
public ItemTransferEffect(Item item, float x, float y, Entity target) {
this.x = x;
this.y = y;
this.item = item;
this.target = target;
}
@Override
public void update() {
x = Mathf.lerpDelta(x, target.x, alpha);
y = Mathf.lerpDelta(y, target.y, alpha);
if(distanceTo(target) <= 2f){
remove();
}
}
@Override
public void draw() {
float s = size;
Draw.rect(item.region, x, y, s, s);
}
@Override
public <T extends Entity> T add() {
return super.add(Vars.effectGroup);
}
}

View File

@@ -6,6 +6,7 @@ import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.resource.Item;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
@@ -39,6 +40,16 @@ public class BaseUnit extends Unit{
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
}
//TODO
@Override
public boolean acceptsAmmo(Item item) {
return false;
}
@Override
public void addAmmo(Item item) {
}
//TODO
@Override
public float getSize() {

View File

@@ -106,7 +106,7 @@ public class DesktopInput extends InputHandler{
for(int i = 1; i <= 6 && i <= control.upgrades().getWeapons().size; i ++){
if(Inputs.keyTap("weapon_" + i)){
player.weaponLeft = player.weaponRight = control.upgrades().getWeapons().get(i - 1);
player.weapon = control.upgrades().getWeapons().get(i - 1);
if(Net.active()) NetEvents.handleWeaponSwitch();
}
}

View File

@@ -63,8 +63,7 @@ public class NetEvents {
public static void handleWeaponSwitch(){
WeaponSwitchPacket packet = new WeaponSwitchPacket();
packet.left = Vars.player.weaponLeft.id;
packet.right = Vars.player.weaponRight.id;
packet.weapon = Vars.player.weapon.id;
packet.playerid = Vars.player.id;
Net.send(packet, SendMode.tcp);
}

View File

@@ -123,7 +123,7 @@ public class NetworkIO {
control.upgrades().getWeapons().add(Upgrade.getByID(stream.readByte()));
}
player.weaponLeft = player.weaponRight = control.upgrades().getWeapons().peek();
player.weapon = control.upgrades().getWeapons().peek();
Entities.clear();
player.id = pid;

View File

@@ -376,20 +376,18 @@ public class Packets {
public static class WeaponSwitchPacket implements Packet{
public int playerid;
public byte left, right;
public byte weapon;
@Override
public void write(ByteBuffer buffer) {
buffer.putInt(playerid);
buffer.put(left);
buffer.put(right);
buffer.put(weapon);
}
@Override
public void read(ByteBuffer buffer) {
playerid = buffer.getInt();
left = buffer.get();
right = buffer.get();
weapon = buffer.get();
}
}

View File

@@ -1,21 +1,30 @@
package io.anuke.mindustry.resource;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Bits;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
public class Weapon extends Upgrade{
/**minimum cursor distance from player, fixes 'cross-eyed' shooting.*/
protected static float minPlayerDist = 20f;
/**ammo type map. set with setAmmo()*/
protected ObjectMap<Item, AmmoType> ammoMap = new ObjectMap<>();
/**shell ejection effect*/
protected Effect ejectEffect = Fx.none;
/**weapon reload in frames*/
protected float reload;
/**sound made when shooting*/
protected String shootsound = "shoot";
/**amount of shots per fire*/
protected int shots = 1;
/**spacing in degrees between multiple shots, if applicable*/
@@ -24,56 +33,79 @@ public class Weapon extends Upgrade{
protected float inaccuracy = 0f;
/**intensity and duration of each shot's screen shake*/
protected float shake = 0f;
/**effect displayed when shooting*/
protected Effect effect;
/**shoot barrel length*/
protected float length = 3f;
/**whether to shoot the weapons in different arms one after another, rather an all at once*/
/**whether to shoot the weapons in different arms one after another, rather than all at once*/
protected boolean roundrobin = false;
/**translator for vector calulations*/
protected Translator tr = new Translator();
protected Weapon(String name, float reload){
protected Weapon(String name){
super(name);
this.reload = reload;
}
public void update(Player p, boolean left){
int t = left ? 1 : 2;
int t2 = !left ? 1 : 2;
if(p.timer.get(t, reload)){
if(p.inventory.hasAmmo() && p.timer.get(t, reload)){
if(roundrobin){
p.timer.reset(t2, reload/2f);
}
float ang = Angles.mouseAngle(p.x, p.y);
tr.set(Graphics.mouseWorld()).sub(p.x, p.y);
if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist);
float cx = tr.x + p.x, cy = tr.y + p.y;
float ang = tr.angle();
tr.trns(ang - 90, 4f * Mathf.sign(left), length + 1f);
shoot(p, p.x + tr.x, p.y + tr.y, Angles.mouseAngle(p.x + tr.x, p.y + tr.y));
shoot(p, p.x + tr.x, p.y + tr.y, Angles.angle(p.x + tr.x, p.y + tr.y, cx, cy), left);
}
}
void shootInternal(Player p, float x, float y, float rotation){
Angles.shotgun(shots, spacing, rotation, f -> bullet(p, x, y, f + Mathf.range(inaccuracy)));
tr.trns(rotation, 3f);
if(effect != null) Effects.effect(effect, x + tr.x, y + tr.y, rotation);
Effects.shake(shake, shake, x, y);
Effects.sound(shootsound, x, y);
public float getRecoil(Player player, boolean left){
return 1f-Mathf.clamp(player.timer.getTime(left ? 1 : 2)/reload);
}
public float getReload(){
return reload;
}
public void shoot(Player p, float x, float y, float angle){
shootInternal(p, x, y, angle);
public void shoot(Player p, float x, float y, float angle, boolean left){
shootInternal(p, x, y, angle, left);
if(Net.active() && p == Vars.player){
NetEvents.handleShoot(Vars.player, x, y, angle, id);
NetEvents.handleShoot(Vars.player, x, y, angle, Bits.packShort(id, (byte)(left ? 1 : 0)));
}
p.inventory.useAmmo();
}
public AmmoType getAmmoType(Item item){
return ammoMap.get(item);
}
protected void setAmmo(AmmoType... types){
for(AmmoType type : types){
ammoMap.put(type.item, type);
}
}
void shootInternal(Player p, float x, float y, float rotation, boolean left){
Angles.shotgun(shots, spacing, rotation, f -> bullet(p, x, y, f + Mathf.range(inaccuracy)));
tr.trns(rotation, 3f);
AmmoType type = p.inventory.getAmmo();
Effects.shake(shake, shake, x, y);
Effects.effect(ejectEffect, x, y, rotation * -Mathf.sign(left));
Effects.effect(type.shootEffect, x + tr.x, y + tr.y, rotation, p);
Effects.effect(type.smokeEffect, x + tr.x, y + tr.y, rotation, p);
}
void bullet(Unit owner, float x, float y, float angle){
tr.trns(angle, 3f);
//TODO implement!
//Bullet.create(type, owner, x + tr.x, y + tr.y, angle);
Bullet.create(owner.inventory.getAmmo().bullet, owner, x + tr.x, y + tr.y, angle);
}
}

View File

@@ -104,7 +104,7 @@ public class PlayerListFragment implements Fragment{
public void draw(){
float s = getWidth() / 12f;
for(int i : Mathf.signs){
Draw.rect((i < 0 ? player.weaponLeft.name : player.weaponRight.name)
Draw.rect((player.weapon.name)
+ "-equip", x + s * 6 + i * 3*s, y + s*6 + 2*s, -8*s*i, 8*s);
}
}

View File

@@ -38,7 +38,6 @@ public abstract class Turret extends Block{
protected Effect shootEffect = Fx.none;
protected Effect smokeEffect = Fx.none;
protected Effect ammoUseEffect = Fx.none;
protected String shootsound = "shoot";
protected int ammoPerShot = 1;
protected float ammoEjectBack = 1f;

View File

@@ -1,24 +1,43 @@
package io.anuke.mindustry.world.blocks.types.storage;
import com.badlogic.gdx.math.Rectangle;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.effect.ItemTransferEffect;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Lines;
import static io.anuke.mindustry.Vars.state;
public class CoreBlock extends StorageBlock {
private static Rectangle rect = new Rectangle();
protected int timerSupply = timers ++;
protected float supplyRadius = 50f;
protected float supplyInterval = 5f;
public CoreBlock(String name) {
super(name);
solid = true;
destructible = true;
update = true;
unbreakable = true;
size = 3;
hasItems = true;
itemCapacity = 2000;
}
@Override
public void drawSelect(Tile tile){
Draw.color("accent");
Lines.dashCircle(tile.drawx(), tile.drawy(), supplyRadius);
Draw.color();
}
@Override
public void onDestroyed(Tile tile){
//TODO more dramatic effects
super.onDestroyed(tile);
@@ -32,31 +51,26 @@ public class CoreBlock extends StorageBlock {
public void handleItem(Item item, Tile tile, Tile source){
if(Net.server() || !Net.active()) super.handleItem(item, tile, source);
}
/*
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
return item.material && state.inventory.getAmount(item) < capacity;
}
public void update(Tile tile) {
@Override
public Item removeItem(Tile tile, Item item){
for(int i = 0; i < state.inventory.getItems().length; i ++){
if(state.inventory.getItems()[i] > 0 && (item == null || item.id == i)){
if(Net.server() || !Net.active()) state.inventory.getItems()[i] --;
return Item.getByID(i);
}
if(tile.entity.timer.get(timerSupply, supplyInterval)){
rect.setSize(supplyRadius*2).setCenter(tile.drawx(), tile.drawy());
Units.getNearby(tile.getTeam(), rect, unit -> {
if(unit.distanceTo(tile.drawx(), tile.drawy()) > supplyRadius) return;
for(int i = 0; i < tile.entity.items.items.length; i ++){
Item item = Item.getByID(i);
if(tile.entity.items.items[i] > 0 && unit.acceptsAmmo(item)){
tile.entity.items.items[i] --;
unit.addAmmo(item);
new ItemTransferEffect(item, tile.drawx(), tile.drawy(), unit).add();
return;
}
}
});
}
return null;
}
@Override
public boolean hasItem(Tile tile, Item item){
for(int i = 0; i < state.inventory.getItems().length; i ++){
if(state.inventory.getItems()[i] > 0 && (item == null || item.id == i)){
return true;
}
}
return false;
}*/
}