Unit weapon rework, titan and bomber enemies added, various fixes

This commit is contained in:
Anuken
2018-06-26 22:48:18 -04:00
parent 03277c69af
commit c89123b18a
48 changed files with 1154 additions and 879 deletions

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.content;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.bullets.*;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.content.fx.ShootFx;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.type.AmmoType;
@@ -9,7 +10,7 @@ import io.anuke.mindustry.type.ContentList;
public class AmmoTypes implements ContentList {
public static AmmoType bulletTungsten, bulletLead, bulletCarbide, bulletThorium, bulletSilicon, bulletThermite,
shotgunTungsten,
shotgunTungsten, bombExplosive, bombIncendiary,
flakLead, flakExplosive, flakPlastic, flakSurge, missileExplosive, missileIncindiary, missileSurge,
artilleryCarbide, artilleryThorium, artilleryPlastic, artilleryHoming, artilleryIncindiary,
basicFlame, lancerLaser, lightning, spectreLaser, meltdownLaser, fuseShotgun, oil, water, lava, cryofluid;
@@ -63,6 +64,16 @@ public class AmmoTypes implements ContentList {
recoil = 1f;
}};
bombExplosive = new AmmoType(Items.blastCompound, WeaponBullets.bombExplosive, 3) {{
shootEffect = Fx.none;
smokeEffect = Fx.none;
}};
bombIncendiary = new AmmoType(Items.thermite, WeaponBullets.bombIncendiary, 3) {{
shootEffect = Fx.none;
smokeEffect = Fx.none;
}};
//flak
flakLead = new AmmoType(Items.lead, FlakBullets.lead, 5) {{

View File

@@ -2,19 +2,16 @@ package io.anuke.mindustry.content;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.entities.units.types.Drone;
import io.anuke.mindustry.entities.units.types.Scout;
import io.anuke.mindustry.entities.units.types.Vtol;
import io.anuke.mindustry.entities.units.types.*;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.type.ContentList;
import io.anuke.mindustry.type.StatusEffect;
public class UnitTypes implements ContentList {
public static UnitType drone, scout, vtol;
public static UnitType drone, scout, vtol, monsoon, titan;
@Override
public void load() {
drone = new UnitType("drone", team -> new Drone(drone, team)){{
drone = new UnitType("drone", Drone.class, Drone::new){{
isFlying = true;
drag = 0.01f;
speed = 0.2f;
@@ -23,26 +20,43 @@ public class UnitTypes implements ContentList {
range = 50f;
}};
scout = new UnitType("scout", team -> new Scout(scout, team)){{
scout = new UnitType("scout", Scout.class, Scout::new){{
maxVelocity = 1.1f;
speed = 0.2f;
drag = 0.4f;
range = 40f;
setAmmo(AmmoTypes.bulletLead);
weapon = Weapons.blaster;
}};
vtol = new UnitType("vtol", team -> new Vtol(vtol, team)){{
titan = new UnitType("titan", Titan.class, Titan::new){{
maxVelocity = 0.8f;
speed = 0.18f;
drag = 0.4f;
range = 10f;
weapon = Weapons.shockgun;
}};
vtol = new UnitType("vtol", Vtol.class, Vtol::new){{
speed = 0.3f;
maxVelocity = 2f;
maxVelocity = 2.1f;
drag = 0.01f;
isFlying = true;
reload = 7;
setAmmo(AmmoTypes.bulletLead);
}};
monsoon = new UnitType("monsoon", Monsoon.class, Monsoon::new){{
health = 300;
speed = 0.2f;
maxVelocity = 1.5f;
drag = 0.01f;
isFlying = true;
reload = 7;
weapon = Weapons.bomber;
}};
}
@Override
public Array<? extends Content> getAll() {
return StatusEffect.all();
return UnitType.all();
}
}

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.content;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.content.fx.ShootFx;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.type.ContentList;
@@ -8,7 +9,7 @@ import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.type.Weapon;
public class Weapons implements ContentList {
public static Weapon blaster, shockgun, sapper, swarmer;
public static Weapon blaster, shockgun, sapper, swarmer, bomber;
@Override
public void load() {
@@ -48,6 +49,17 @@ public class Weapons implements ContentList {
ejectEffect = ShootFx.shellEjectSmall;
setAmmo(AmmoTypes.bulletThermite);
}};
bomber = new Weapon("bomber") {{
length = 0f;
width = 2f;
reload = 5f;
roundrobin = true;
ejectEffect = Fx.none;
velocityRnd = 1f;
inaccuracy = 40f;
setAmmo(AmmoTypes.bombExplosive);
}};
}
@Override

View File

@@ -1,10 +1,19 @@
package io.anuke.mindustry.content.bullets;
import io.anuke.mindustry.content.fx.BulletFx;
import io.anuke.mindustry.entities.bullet.BasicBulletType;
import io.anuke.mindustry.entities.bullet.BombBulletType;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.entities.effect.Fire;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.world;
public class WeaponBullets extends BulletList {
public static BulletType tungstenShotgun;
public static BulletType tungstenShotgun, bombExplosive, bombIncendiary;
@Override
public void load() {
@@ -17,5 +26,37 @@ public class WeaponBullets extends BulletList {
drag = 0.04f;
}
};
bombExplosive = new BombBulletType(20f, 20f, "shell"){
{
bulletWidth = 9f;
bulletHeight = 13f;
hiteffect = BulletFx.flakExplosion;
}
};
bombIncendiary = new BombBulletType(20f, 20f, "shell"){
{
bulletWidth = 9f;
bulletHeight = 13f;
hiteffect = BulletFx.flakExplosion;
backColor = Palette.darkFlame;
frontColor = Palette.lightFlame;
}
@Override
public void hit(Bullet b, float x, float y) {
super.hit(b, x, y);
for (int i = 0; i < 3; i++) {
float cx = x + Mathf.range(10f);
float cy = y + Mathf.range(10f);
Tile tile = world.tileWorld(cx, cy);
if(tile != null){
Fire.create(tile);
}
}
}
};
}
}

View File

@@ -15,13 +15,8 @@ import io.anuke.mindustry.entities.effect.ItemDrop;
import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.entities.traits.TypeTrait;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.entities.units.types.Drone;
import io.anuke.mindustry.entities.units.types.Scout;
import io.anuke.mindustry.entities.units.types.Vtol;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.type.ContentList;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.type.StatusEffect;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.ColorMapper;
import io.anuke.ucore.core.Effects;
@@ -60,6 +55,7 @@ public class ContentLoader {
new TurretBullets(),
new WeaponBullets(),
//ammotypes
new AmmoTypes(),
@@ -117,8 +113,8 @@ public class ContentLoader {
Log.info("--- CONTENT INFO ---");
Log.info("Blocks loaded: {0}\nItems loaded: {1}\nLiquids loaded: {2}\nUpgrades loaded: {3}\nUnits loaded: {4}\nAmmo types loaded: {5}\nBullet types loaded: {6}\nStatus effects loaded: {7}\nRecipes loaded: {8}\nEffects loaded: {9}\nTotal content classes: {10}",
Block.all().size, io.anuke.mindustry.type.Item.all().size, Liquid.all().size,
io.anuke.mindustry.type.Mech.all().size, UnitType.getAllTypes().size, io.anuke.mindustry.type.AmmoType.all().size, BulletType.all().size, StatusEffect.all().size, io.anuke.mindustry.type.Recipe.all().size, Effects.all().size, content.length);
Block.all().size, Item.all().size, Liquid.all().size, Mech.all().size, UnitType.all().size,
AmmoType.all().size, BulletType.all().size, StatusEffect.all().size, Recipe.all().size, Effects.all().size, content.length);
Log.info("-------------------");
@@ -138,15 +134,13 @@ public class ContentLoader {
//TODO clear all content.
}
/**Registers sync IDs for all types of sync entities.*/
/**Registers sync IDs for all types of sync entities.
* Do not register units here!*/
private static void registerTypes(){
Player.typeID = TypeTrait.registerType(Player::new);
Drone.typeID = TypeTrait.registerType(Drone::new);
Vtol.typeID = TypeTrait.registerType(Vtol::new);
Scout.typeID = TypeTrait.registerType(Scout::new);
ItemDrop.typeID = TypeTrait.registerType(ItemDrop::new);
Fire.typeID = TypeTrait.registerType(Fire::new);
Puddle.typeID = TypeTrait.registerType(Puddle::new);
Bullet.typeID = TypeTrait.registerType(Bullet::new);
TypeTrait.registerType(Player.class, Player::new);
TypeTrait.registerType(ItemDrop.class, ItemDrop::new);
TypeTrait.registerType(Fire.class, Fire::new);
TypeTrait.registerType(Puddle.class, Puddle::new);
TypeTrait.registerType(Bullet.class, Bullet::new);
}
}

View File

@@ -16,6 +16,7 @@ import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.impl.SolidEntity;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Physics;
import io.anuke.ucore.util.Translator;
@@ -108,8 +109,10 @@ public class Damage {
}
/**Damages all entities and blocks in a radius that are enemies of the team.*/
public static void damageUnits(Team team, float x, float y, float size, float damage, Consumer<Unit> acceptor) {
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor) {
Consumer<Unit> cons = entity -> {
if(!predicate.test(entity)) return;
entity.getHitbox(hitrect);
if (!hitrect.overlaps(rect)) {
return;
@@ -134,13 +137,14 @@ public class Damage {
/**Damages all entities and blocks in a radius that are enemies of the team.*/
public static void damage(Team team, float x, float y, float radius, float damage){
Consumer<Unit> cons = entity -> {
if(entity.distanceTo(x, y) > radius){
if(entity.team == team || entity.distanceTo(x, y) > radius){
return;
}
float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage);
entity.damage(amount);
//TODO better velocity displacement
entity.getVelocity().add(tr.set(entity.x - x, entity.y - y).setLength(damage*2f));
float dst = tr.set(entity.x - x, entity.y - y).len();
entity.getVelocity().add(tr.setLength((1f-dst/radius) * 2f));
};
rect.setSize(radius *2).setCenter(x, y);

View File

@@ -11,20 +11,14 @@ import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.effect.ItemDrop;
import io.anuke.mindustry.entities.effect.ScorchDecal;
import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.traits.CarriableTrait;
import io.anuke.mindustry.entities.traits.CarryTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.net.In;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Mech;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
@@ -34,10 +28,7 @@ import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.trait.SolidTrait;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.ThreadQueue;
import io.anuke.ucore.util.Timer;
import io.anuke.ucore.util.*;
import java.io.DataInput;
import java.io.DataOutput;
@@ -45,11 +36,10 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BuilderTrait, CarryTrait {
public static int typeID = -1;
public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait {
private static final int timerShootLeft = 0;
private static final int timerShootRight = 1;
public static final int timerShootLeft = 0;
public static final int timerShootRight = 1;
public static final int timerSync = 2;
//region instance variables, constructor
@@ -90,6 +80,21 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
//region unit and event overrides, utility methods
@Override
public Timer getTimer() {
return timer;
}
@Override
public int getShootTimer(boolean left) {
return left ? timerShootLeft : timerShootRight;
}
@Override
public Weapon getWeapon() {
return mech.weapon;
}
@Override
public float getMinePower() {
return mech.mineSpeed;
@@ -123,11 +128,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
}
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public CarriableTrait getCarry() {
return carrying;
@@ -538,8 +538,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
protected void updateShooting(){
if(isShooting()){
mech.weapon.update(this, true, pointerX, pointerY);
mech.weapon.update(this, false, pointerX, pointerY);
mech.weapon.update(this, pointerX, pointerY);
}
}

View File

@@ -31,7 +31,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait {
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait {
/**total duration of hit flash effect*/
public static final float hitDuration = 9f;
/**Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.*/
@@ -53,6 +53,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
protected float hitTime;
protected float drownTime;
@Override
public UnitInventory getInventory() {
return inventory;
}
@Override
public float getRotation() {
return rotation;
@@ -191,7 +196,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
public void avoidOthers(float avoidRange){
EntityPhysics.getNearby(getGroup(), x, y, avoidRange*2f, t -> {
if(t == this || (t instanceof Unit && ((Unit) t).isDead())) return;
if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying())))) return;
float dst = distanceTo(t);
if(dst > avoidRange) return;
velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange))));

View File

@@ -0,0 +1,16 @@
package io.anuke.mindustry.entities.bullet;
public class BombBulletType extends BasicBulletType {
public BombBulletType(float damage, float radius, String sprite) {
super(0.7f, 0, sprite);
splashDamageRadius = radius;
splashDamage = damage;
collidesTiles = false;
collides = false;
bulletShrink = 0.7f;
lifetime = 30f;
drag = 0.05f;
keepVelocity = false;
}
}

View File

@@ -27,8 +27,6 @@ import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.world;
public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncTrait{
public static int typeID = -1;
private static Vector2 vector = new Vector2();
private Team team;
@@ -56,7 +54,9 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
bullet.data = data;
bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl);
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero);
if(type.keepVelocity){
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero);
}
bullet.hitbox.setSize(type.hitsize);
bullet.team = team;
@@ -119,11 +119,6 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
return super.getDamage();
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public boolean isSyncing(){
return type.syncable;

View File

@@ -29,6 +29,8 @@ public abstract class BulletType extends BaseBulletType<Bullet> implements Conte
public boolean collidesTiles = true;
/**Whether this bullet types collides with anything at all.*/
public boolean collides = true;
/**Whether velocity is inherited from the shooter.*/
public boolean keepVelocity = true;
public BulletType(float speed, float damage){
this.id = lastid ++;

View File

@@ -34,8 +34,6 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
private static final IntMap<Fire> map = new IntMap<>();
private static final float baseLifetime = 1000f;
public static int typeID = -1;
private int loadedPosition = -1;
private Tile tile;
private Block block;
@@ -71,11 +69,6 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
/**Deserialization use only!*/
public Fire(){}
@Override
public int getTypeID() {
return typeID;
}
@Override
public float lifetime() {
return lifetime;
@@ -137,11 +130,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
if(damage){
entity.damage(0.4f);
}
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, unit -> {
if(!unit.isFlying()) {
unit.applyEffect(StatusEffects.burning, 0.8f);
}
});
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, unit -> !unit.isFlying(), unit -> unit.applyEffect(StatusEffects.burning, 0.8f));
}
}

View File

@@ -37,8 +37,6 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawTrait, VelocityTrait, TimeTrait, TargetTrait, Poolable {
public static int typeID = -1;
private static final float sinkLifetime = 80f;
private Interpolator interpolator = new Interpolator();
@@ -98,11 +96,6 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
return Team.none;
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public float lifetime() {
return 60*60;

View File

@@ -49,8 +49,6 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
private static final Rectangle rect2 = new Rectangle();
private static int seeds;
public static int typeID = -1;
private int loadedPosition = -1;
private float updateTime;
@@ -269,11 +267,6 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
reset();
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public void write(DataOutput data) throws IOException {
data.writeFloat(x);

View File

@@ -0,0 +1,7 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.entities.UnitInventory;
public interface InventoryTrait {
UnitInventory getInventory();
}

View File

@@ -0,0 +1,12 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.type.Weapon;
import io.anuke.ucore.entities.trait.VelocityTrait;
import io.anuke.ucore.util.Timer;
public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{
Timer getTimer();
int getShootTimer(boolean left);
Weapon getWeapon();
}

View File

@@ -1,18 +1,24 @@
package io.anuke.mindustry.entities.traits;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectIntMap;
import io.anuke.ucore.function.Supplier;
public interface TypeTrait {
int[] lastRegisteredID = {0};
Array<Supplier<? extends TypeTrait>> registeredTypes = new Array<>();
ObjectIntMap<Class<? extends TypeTrait>> typeToID = new ObjectIntMap<>();
/**Register and return a type ID. The supplier should return a fresh instace of that type.*/
static int registerType(Supplier<? extends TypeTrait> supplier){
static <T extends TypeTrait> void registerType(Class<T> type, Supplier<T> supplier){
if(typeToID.get(type, -1) != -1){
throw new RuntimeException("Type is already registered: '" + type + "'!");
}
registeredTypes.add(supplier);
int result = lastRegisteredID[0];
typeToID.put(type, result);
lastRegisteredID[0] ++;
return result;
}
/**Registers a syncable type by ID.*/
@@ -23,6 +29,11 @@ public interface TypeTrait {
return registeredTypes.get(id);
}
/**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.*/
int getTypeID();
/**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.
* Do not override!*/
default int getTypeID(){
int id = typeToID.get(getClass(), -1);
if(id == -1) throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?");
return id;
}
}

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.entities.units;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
@@ -10,24 +9,22 @@ import io.anuke.mindustry.content.fx.ExplosionFx;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.effect.ScorchDecal;
import io.anuke.mindustry.entities.traits.ShooterTrait;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.TeamInfo.TeamData;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.net.In;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.units.UnitFactory.UnitFactoryEntity;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
@@ -38,13 +35,13 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public abstract class BaseUnit extends Unit{
private static int timerIndex = 0;
public abstract class BaseUnit extends Unit implements ShooterTrait{
protected static int timerIndex = 0;
protected static final int timerTarget = timerIndex++;
protected static final int timerReload = timerIndex++;
protected static final Array<Tile> nearbyCores = new Array<>();
protected static final int timerShootLeft = timerIndex++;
protected static final int timerShootRight = timerIndex++;
protected UnitType type;
protected Timer timer = new Timer(5);
@@ -55,7 +52,10 @@ public abstract class BaseUnit extends Unit{
protected Squad squad;
protected int spawner = -1;
public BaseUnit(UnitType type, Team team){
/**Initialize the type and team of this unit. Only call once!*/
public void init(UnitType type, Team team){
if(this.type != null) throw new RuntimeException("This unit is already initialized!");
this.type = type;
this.team = team;
}
@@ -111,11 +111,6 @@ public abstract class BaseUnit extends Unit{
target = null;
}
}
public void shoot(AmmoType type, float rotation){
CallEntity.onUnitShoot(this, type, rotation);
}
public void targetClosestAllyFlag(BlockFlag flag){
if(target != null) return;
@@ -154,9 +149,24 @@ public abstract class BaseUnit extends Unit{
return null;
}
@Override
public Timer getTimer() {
return timer;
}
@Override
public int getShootTimer(boolean left) {
return left ? timerShootLeft : timerShootRight;
}
@Override
public Weapon getWeapon() {
return type.weapon;
}
@Override
public TextureRegion getIconRegion() {
return Draw.region(type.name);
return type.iconRegion;
}
@Override
@@ -195,12 +205,12 @@ public abstract class BaseUnit extends Unit{
@Override
public boolean acceptsAmmo(Item item) {
return type.ammo.containsKey(item) && inventory.canAcceptAmmo(type.ammo.get(item));
return getWeapon().getAmmoType(item) != null && inventory.canAcceptAmmo(getWeapon().getAmmoType(item));
}
@Override
public void addAmmo(Item item) {
inventory.addAmmo(type.ammo.get(item));
inventory.addAmmo(getWeapon().getAmmoType(item));
}
@Override
@@ -340,19 +350,6 @@ public abstract class BaseUnit extends Unit{
super.onDeath();
}
@Remote(called = Loc.server, in = In.entities)
public static void onUnitShoot(BaseUnit unit, AmmoType type, float rotation){
if(unit == null) return;
Bullet.create(type.bullet, unit,
unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation);
Effects.effect(type.shootEffect, unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation, unit);
Effects.effect(type.smokeEffect, unit.x + Angles.trnsx(rotation, unit.type.shootTranslation),
unit.y + Angles.trnsy(rotation, unit.type.shootTranslation), rotation, unit);
}
@Remote(called = Loc.server, in = In.entities)
public static void onUnitDeath(BaseUnit unit){
if(unit == null) return;

View File

@@ -5,9 +5,9 @@ import io.anuke.mindustry.entities.Predict;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.traits.CarriableTrait;
import io.anuke.mindustry.entities.traits.CarryTrait;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Trail;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.world.Tile;
@@ -29,10 +29,6 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
protected Trail trail = new Trail(8);
protected CarriableTrait carrying;
public FlyingUnit(UnitType type, Team team) {
super(type, team);
}
//instantiation only
public FlyingUnit(){
@@ -60,6 +56,8 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
updateRotation();
trail.update(x + Angles.trnsx(rotation + 180f, 6f) + Mathf.range(wobblyness),
y + Angles.trnsy(rotation + 180f, 6f) + Mathf.range(wobblyness));
wobble();
}
@Override
@@ -114,15 +112,15 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
return 60;
}
@Override
public void removed() {
dropCarry();
}
protected void wobble(){
if(Net.client()) return;
@Override
public void onDeath() {
super.onDeath();
dropCarry();
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
if (velocity.len() <= 0.2f) {
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f);
}
}
protected void updateRotation(){
@@ -237,14 +235,14 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
}else{
attack(150f);
if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f)
if ((Mathf.angNear(angleTo(target), rotation, 15f) || !inventory.getAmmo().bullet.keepVelocity) //bombers don't care about rotation
&& distanceTo(target) < inventory.getAmmo().getRange()) {
AmmoType ammo = inventory.getAmmo();
inventory.useAmmo();
Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.bullet.speed);
shoot(ammo, Angles.moveToward(rotation, angleTo(to.x, to.y), maxAim));
getWeapon().update(FlyingUnit.this, to.x, to.y);
}
}
}

View File

@@ -8,6 +8,8 @@ import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Upgrade;
import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.meta.BlockFlag;
@@ -18,21 +20,26 @@ import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import static io.anuke.mindustry.Vars.world;
public abstract class GroundUnit extends BaseUnit {
protected static Translator vec = new Translator();
protected static float maxAim = 30f;
protected static final int timerReloadAlt = timerIndex++;
protected float walkTime;
protected float baseRotation;
protected Weapon weapon;
public GroundUnit(UnitType type, Team team) {
super(type, team);
}
public GroundUnit(){
@Override
public void init(UnitType type, Team team) {
super.init(type, team);
this.weapon = type.weapon;
}
@Override
@@ -64,6 +71,11 @@ public abstract class GroundUnit extends BaseUnit {
}
}
@Override
public Weapon getWeapon() {
return weapon;
}
@Override
public void draw() {
Draw.alpha(hitTime / hitDuration);
@@ -79,7 +91,7 @@ public abstract class GroundUnit extends BaseUnit {
}
for (int i : Mathf.signs) {
Draw.rect(type.name + "-leg",
Draw.rect(type.legRegion,
x + Angles.trnsx(baseRotation, ft * i),
y + Angles.trnsy(baseRotation, ft * i),
12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
@@ -91,9 +103,17 @@ public abstract class GroundUnit extends BaseUnit {
Draw.tint(Color.WHITE);
}
Draw.rect(type.name + "-base", x, y, baseRotation- 90);
Draw.rect(type.baseRegion, x, y, baseRotation- 90);
Draw.rect(type.name, x, y, rotation -90);
Draw.rect(type.region, x, y, rotation -90);
for (int i : Mathf.signs) {
float tra = rotation - 90, trY = - weapon.getRecoil(this, i > 0) + type.weaponOffsetY;
float w = i > 0 ? -12 : 12;
Draw.rect(weapon.equipRegion,
x + Angles.trnsx(tra, type.weaponOffsetX * i, trY),
y + Angles.trnsy(tra, type.weaponOffsetX * i, trY), w, 12, rotation - 90);
}
Draw.alpha(1f);
}
@@ -114,6 +134,34 @@ public abstract class GroundUnit extends BaseUnit {
}
}
@Override
public void write(DataOutput data) throws IOException {
super.write(data);
data.writeByte(weapon.id);
}
@Override
public void read(DataInput data, long time) throws IOException {
super.read(data, time);
weapon = Upgrade.getByID(data.readByte());
}
@Override
public void writeSave(DataOutput stream) throws IOException {
stream.writeByte(weapon.id);
super.writeSave(stream);
}
@Override
public void readSave(DataInput stream) throws IOException{
weapon = Upgrade.getByID(weapon.id);
super.readSave(stream);
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
protected void moveToCore(){
Tile tile = world.tileWorld(x, y);
if(tile == null) return;
@@ -191,15 +239,13 @@ public abstract class GroundUnit extends BaseUnit {
rotate(angleTo(target));
}
if (timer.get(timerReload, type.reload) && Mathf.angNear(angleTo(target), rotation, 13f)
&& distanceTo(target) < inventory.getAmmo().getRange()) {
if (Mathf.angNear(angleTo(target), rotation, 13f) && distanceTo(target) < inventory.getAmmo().getRange()) {
AmmoType ammo = inventory.getAmmo();
inventory.useAmmo();
rotate(angleTo(target));
Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.bullet.speed);
shoot(ammo, Angles.moveToward(rotation, angleTo(to.x, to.y), maxAim));
getWeapon().update(GroundUnit.this, to.x, to.y);
}
}else{
moveToCore();

View File

@@ -1,16 +1,22 @@
package io.anuke.mindustry.entities.units;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.entities.traits.TypeTrait;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.type.Weapon;
import io.anuke.ucore.function.Supplier;
import io.anuke.ucore.graphics.Draw;
public class UnitType {
//TODO merge unit type with mech
public class UnitType implements UnlockableContent{
private static byte lastid = 0;
private static Array<UnitType> types = new Array<>();
protected final UnitCreator creator;
protected final Supplier<? extends BaseUnit> constructor;
public final String name;
public final byte id;
@@ -21,7 +27,6 @@ public class UnitType {
public float speed = 0.4f;
public float range = 160;
public float rotatespeed = 0.1f;
public float shootTranslation = 4f;
public float baseRotateSpeed = 0.1f;
public float mass = 1f;
public boolean isFlying;
@@ -34,35 +39,58 @@ public class UnitType {
public int ammoCapacity = 100;
public int itemCapacity = 30;
public int mineLevel = 2;
public ObjectMap<Item, AmmoType> ammo = new ObjectMap<>();
public Weapon weapon = Weapons.blaster;
public float weaponOffsetX, weaponOffsetY;
public UnitType(String name, UnitCreator creator){
public TextureRegion iconRegion, legRegion, baseRegion, region;
public <T extends BaseUnit> UnitType(String name, Class<T> type, Supplier<T> mainConstructor){
this.id = lastid++;
this.name = name;
this.creator = creator;
this.constructor = mainConstructor;
types.add(this);
TypeTrait.registerType(type, mainConstructor);
}
public BaseUnit create(Team team){
return creator.create(team);
}
@Override
public void load() {
iconRegion = Draw.region("unit-icon-" + name);
region = Draw.region(name);
protected void setAmmo(AmmoType... types){
for(AmmoType type : types){
ammo.put(type.item, type);
if(!isFlying) {
legRegion = Draw.region(name + "-leg");
baseRegion = Draw.region(name + "-base");
}
}
public interface UnitCreator{
BaseUnit create(Team team);
@Override
public String getContentTypeName() {
return "unit-type";
}
@Override
public String getContentName() {
return name;
}
@Override
public Array<? extends Content> getAll() {
return types;
}
public BaseUnit create(Team team){
BaseUnit unit = constructor.get();
unit.init(this, team);
return unit;
}
public static UnitType getByID(byte id){
return types.get(id);
}
public static Array<UnitType> getAllTypes(){
public static Array<UnitType> all(){
return types;
}
}

View File

@@ -12,9 +12,7 @@ import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.FlyingUnit;
import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item;
@@ -41,8 +39,6 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*;
public class Drone extends FlyingUnit implements BuilderTrait {
public static int typeID = -1;
protected static ObjectSet<Item> toMine;
protected static float healSpeed = 0.1f;
protected static float discoverRange = 120f;
@@ -71,19 +67,14 @@ public class Drone extends FlyingUnit implements BuilderTrait {
}
}
});
initialized = true;
}
{
initEvents();
}
public Drone(UnitType type, Team team) {
super(type, team);
}
public Drone(){
}
private void notifyPlaced(BuildEntity entity){
float timeToBuild = entity.recipe.cost;
float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0);
@@ -94,11 +85,6 @@ public class Drone extends FlyingUnit implements BuilderTrait {
}
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public float getBuildPower(Tile tile) {
return 0.3f;
@@ -231,7 +217,9 @@ public class Drone extends FlyingUnit implements BuilderTrait {
build = new UnitState(){
public void entered() {
target = null;
if(!(target instanceof BuildEntity)){
target = null;
}
}
public void update() {
@@ -310,6 +298,12 @@ public class Drone extends FlyingUnit implements BuilderTrait {
findItem();
}
//core full
if(targetItem != null && entity.tile.block().acceptStack(targetItem, 1, entity.tile, Drone.this) == 0){
setState(repair);
return;
}
//if inventory is full, drop it off.
if(inventory.isFull()){
setState(drop);
@@ -395,10 +389,12 @@ public class Drone extends FlyingUnit implements BuilderTrait {
TileEntity tile = (TileEntity)target;
if(distanceTo(target) < type.range
&& tile.tile.block().acceptStack(inventory.getItem().item, inventory.getItem().amount, tile.tile, Drone.this) == inventory.getItem().amount){
CallEntity.transferItemTo(inventory.getItem().item, inventory.getItem().amount, x, y, tile.tile);
inventory.clearItem();
if(distanceTo(target) < type.range){
if(tile.tile.block().acceptStack(inventory.getItem().item, inventory.getItem().amount, tile.tile, Drone.this) == inventory.getItem().amount) {
CallEntity.transferItemTo(inventory.getItem().item, inventory.getItem().amount, x, y, tile.tile);
inventory.clearItem();
}
setState(repair);
}

View File

@@ -0,0 +1,7 @@
package io.anuke.mindustry.entities.units.types;
import io.anuke.mindustry.entities.units.FlyingUnit;
public class Monsoon extends FlyingUnit {
}

View File

@@ -1,22 +1,7 @@
package io.anuke.mindustry.entities.units.types;
import io.anuke.mindustry.entities.units.GroundUnit;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.Team;
public class Scout extends GroundUnit {
public static int typeID = -1;
public Scout(UnitType type, Team team) {
super(type, team);
}
public Scout(){
}
@Override
public int getTypeID() {
return typeID;
}
}

View File

@@ -0,0 +1,7 @@
package io.anuke.mindustry.entities.units.types;
import io.anuke.mindustry.entities.units.GroundUnit;
public class Titan extends GroundUnit{
}

View File

@@ -1,55 +1,7 @@
package io.anuke.mindustry.entities.units.types;
import io.anuke.mindustry.entities.units.FlyingUnit;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
public class Vtol extends FlyingUnit {
public static int typeID = -1;
public Vtol(UnitType type, Team team) {
super(type, team);
}
public Vtol(){
}
@Override
public int getTypeID() {
return typeID;
}
@Override
public void draw() {
Draw.alpha(hitTime / hitDuration);
Draw.rect("vtol", x, y, rotation - 90);
for(int i : Mathf.signs){
Draw.rect("vtol-booster-1", x, y, 12*i, 12, rotation - 90);
Draw.rect("vtol-booster-2", x, y, 12*i, 12, rotation - 90);
}
Draw.alpha(1f);
}
@Override
public void update() {
super.update();
if(Net.client()) return;
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
if (velocity.len() <= 0.2f) {
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 8f);
}
}
}

View File

@@ -10,6 +10,7 @@ import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.entities.traits.CarriableTrait;
import io.anuke.mindustry.entities.traits.CarryTrait;
import io.anuke.mindustry.entities.traits.ShooterTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.net.Packets.AdminAction;
@@ -57,6 +58,19 @@ public class TypeIO {
return (Unit)Entities.getGroup(gid).getByID(id);
}
@WriteClass(ShooterTrait.class)
public static void writeShooter(ByteBuffer buffer, ShooterTrait trait){
buffer.put((byte)trait.getGroup().getID());
buffer.putInt(trait.getID());
}
@ReadClass(ShooterTrait.class)
public static ShooterTrait readShooter(ByteBuffer buffer){
byte gid = buffer.get();
int id = buffer.getInt();
return (ShooterTrait) Entities.getGroup(gid).getByID(id);
}
@WriteClass(Bullet.class)
public static void writeBullet(ByteBuffer buffer, Bullet bullet){
buffer.putInt(bullet.getID());
@@ -90,6 +104,9 @@ public class TypeIO {
@WriteClass(CarryTrait.class)
public static void writeCarry(ByteBuffer buffer, CarryTrait unit){
if(unit == null){
buffer.put((byte)-1);
}
buffer.put((byte)unit.getGroup().getID());
buffer.putInt(unit.getID());
}
@@ -97,6 +114,9 @@ public class TypeIO {
@ReadClass(CarryTrait.class)
public static CarryTrait readCarry(ByteBuffer buffer){
byte gid = buffer.get();
if(gid == -1){
return null;
}
int id = buffer.getInt();
return (CarryTrait)Entities.getGroup(gid).getByID(id);
}

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.mindustry.content.Weapons;
import io.anuke.ucore.graphics.Draw;
//TODO merge unit type with mech
public class Mech extends Upgrade {
public boolean flying;
@@ -44,6 +45,6 @@ public class Mech extends Upgrade {
}
region = Draw.region(name);
iconRegion = Draw.optional("mech-icon-"+ name);
iconRegion = Draw.region("mech-icon-"+ name);
}
}

View File

@@ -6,6 +6,8 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.world.Block;
import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Log;
import static io.anuke.mindustry.Vars.debug;
import static io.anuke.mindustry.Vars.headless;
@@ -50,6 +52,15 @@ public class Recipe implements UnlockableContent{
return this;
}
@Override
public void init() {
if(!Bundles.has("block." + result.name + ".name")) {
Log.err("WARNING: Recipe block '{0}' does not have a formal name defined.", result.name);
}else if(result.fullDescription == null){
Log.err("WARNING: Recipe block '{0}' does not have a description defined.", result.name);
}
}
@Override
public String getContentName() {
return result.name;

View File

@@ -7,8 +7,8 @@ import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.traits.ShooterTrait;
import io.anuke.mindustry.gen.CallEntity;
import io.anuke.mindustry.net.In;
import io.anuke.mindustry.net.Net;
@@ -38,8 +38,10 @@ public class Weapon extends Upgrade {
protected float shake = 0f;
/**visual weapon knockback.*/
protected float recoil = 1.5f;
/**shoot barrel length*/
/**shoot barrel y offset*/
protected float length = 3f;
/**shoot barrel x offset.*/
protected float width = 4f;
/**fraction of velocity that is random*/
protected float velocityRnd = 0f;
/**whether to shoot the weapons in different arms one after another, rather than all at once*/
@@ -59,43 +61,58 @@ public class Weapon extends Upgrade {
region = Draw.region(name);
}
public void update(Player p, boolean left, float pointerX, float pointerY){
int t = left ? Player.timerShootLeft : Player.timerShootRight;
int t2 = !left ? Player.timerShootLeft : Player.timerShootRight;
if(p.inventory.hasAmmo() && p.timer.get(t, reload)){
public void update(ShooterTrait shooter, float pointerX, float pointerY){
update(shooter, true, pointerX, pointerY);
update(shooter, false, pointerX, pointerY);
}
private void update(ShooterTrait shooter, boolean left, float pointerX, float pointerY){
if(shooter.getInventory().hasAmmo() && shooter.getTimer().get(shooter.getShootTimer(left), reload)){
if(roundrobin){
p.timer.reset(t2, reload/2f);
shooter.getTimer().reset(shooter.getShootTimer(!left), reload/2f);
}
tr.set(pointerX, pointerY).sub(p.x, p.y);
tr.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY());
if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist);
float cx = tr.x + p.x, cy = tr.y + p.y;
float cx = tr.x + shooter.getX(), cy = tr.y + shooter.getY();
float ang = tr.angle();
tr.trns(ang - 90, 4f * Mathf.sign(left), length + 1f);
tr.trns(ang - 90, width * Mathf.sign(left), length);
shoot(p, p.x + tr.x, p.y + tr.y, Angles.angle(p.x + tr.x, p.y + tr.y, cx, cy), left);
shoot(shooter, shooter.getX() + tr.x, shooter.getY() + tr.y, Angles.angle(shooter.getX() + tr.x, shooter.getY() + tr.y, cx, cy), left);
}
}
public float getRecoil(Player player, boolean left){
return (1f-Mathf.clamp(player.timer.getTime(left ? Player.timerShootLeft : Player.timerShootRight)/reload))*recoil;
public float getRecoil(ShooterTrait player, boolean left){
return (1f-Mathf.clamp(player.getTimer().getTime(player.getShootTimer(left))/reload))*recoil;
}
public float getRecoil() {
return recoil;
}
public float getReload(){
return reload;
}
public void shoot(Player p, float x, float y, float angle, boolean left){
public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){
if(Net.client()){
//call it directly, don't invoke on server
shootDirect(p, this, x, y, angle, left);
shootDirect(p, x, y, angle, left);
}else{
CallEntity.onShootWeapon(p, this, x, y, angle, left);
if(p instanceof Player){ //players need special weapon handling logic
CallEntity.onPlayerShootWeapon((Player)p, x, y, angle, left);
}else{
CallEntity.onGenericShootWeapon(p, x, y, angle, left);
}
}
p.inventory.useAmmo();
p.getInventory().useAmmo();
}
public Iterable<Item> getAcceptedItems(){
return ammoMap.keys();
}
public AmmoType getAmmoType(Item item){
@@ -108,39 +125,46 @@ public class Weapon extends Upgrade {
}
}
void bullet(Unit owner, float x, float y, float angle){
void bullet(ShooterTrait owner, float x, float y, float angle){
tr.trns(angle, 3f);
Bullet.create(owner.inventory.getAmmo().bullet, owner, owner.getTeam(), x + tr.x, y + tr.y, angle, (1f-velocityRnd) + Mathf.random(velocityRnd));
Bullet.create(owner.getInventory().getAmmo().bullet, owner, owner.getTeam(), x + tr.x, y + tr.y, angle, (1f-velocityRnd) + Mathf.random(velocityRnd));
}
@Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true)
public static void onShootWeapon(Player player, Weapon weapon, float x, float y, float rotation, boolean left){
public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){
//clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals
//messing with the firerate or any other stats does not affect the server (take that, script kiddies!)
if(Net.client() && player == Vars.players[0]){
return;
}
shootDirect(player, weapon, x, y, rotation, left);
shootDirect(player, x, y, rotation, left);
}
public static void shootDirect(Player player, Weapon weapon, float x, float y, float rotation, boolean left){
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(player, x, y, f + Mathf.range(weapon.inaccuracy)));
@Remote(targets = Loc.server, called = Loc.both, in = In.entities, unreliable = true)
public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){
shootDirect(shooter, x, y, rotation, left);
}
AmmoType type = player.inventory.getAmmo();
public static void shootDirect(ShooterTrait shooter, float x, float y, float rotation, boolean left){
Weapon weapon = shooter.getWeapon();
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy)));
AmmoType type = shooter.getInventory().getAmmo();
weapon.tr.trns(rotation + 180f, type.recoil);
player.getVelocity().add(weapon.tr);
shooter.getVelocity().add(weapon.tr);
weapon.tr.trns(rotation, 3f);
Effects.shake(weapon.shake, weapon.shake, x, y);
Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left));
Effects.effect(type.shootEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, player);
Effects.effect(type.smokeEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, player);
Effects.effect(type.shootEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter);
Effects.effect(type.smokeEffect, x + weapon.tr.x, y + weapon.tr.y, rotation, shooter);
//reset timer for remote players
player.timer.get(left ? Player.timerShootLeft : Player.timerShootRight, weapon.reload);
shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload);
}
}

View File

@@ -2,20 +2,21 @@ package io.anuke.mindustry.ui.fragments;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import io.anuke.mindustry.content.AmmoTypes;
import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.builders.button;
import io.anuke.ucore.scene.builders.label;
import io.anuke.ucore.scene.builders.table;
import io.anuke.ucore.scene.style.TextureRegionDrawable;
import io.anuke.ucore.scene.ui.Label;
import io.anuke.ucore.scene.ui.ScrollPane;
import io.anuke.ucore.scene.ui.layout.Table;
@@ -71,18 +72,21 @@ public class DebugFragment implements Fragment {
row();
new button("death", () -> player.damage(99999, false));
row();
new button("spawnf", () -> {
BaseUnit unit = UnitTypes.vtol.create(player.getTeam());
unit.set(player.x, player.y);
unit.add();
});
row();
new button("spawng", () ->{
BaseUnit unit = UnitTypes.scout.create(player.getTeam());
unit.set(player.x, player.y);
unit.inventory.addAmmo(AmmoTypes.bulletLead);
unit.setWave();
unit.add();
new button("spawn", () -> {
FloatingDialog dialog = new FloatingDialog("debug spawn");
for(UnitType type : UnitType.all()){
dialog.content().addImageButton("white", 40, () -> {
dialog.hide();
BaseUnit unit = type.create(player.getTeam());
unit.inventory.addAmmo(type.weapon.getAmmoType(type.weapon.getAcceptedItems().iterator().next()));
unit.setWave();
unit.set(player.x, player.y);
unit.add();
}).get().getStyle().imageUp = new TextureRegionDrawable(type.iconRegion);
}
dialog.addCloseButton();
dialog.setFillParent(false);
dialog.show();
});
row();
}}.end();

View File

@@ -98,8 +98,6 @@ public class Build {
//just in case
if(tile == null) return;
threads.run(() -> Events.fire(BlockBuildEvent.class, team, tile));
Block result = recipe.result;
Block previous = tile.block();
@@ -144,6 +142,8 @@ public class Build {
}
}
}
threads.runDelay(() -> Events.fire(BlockBuildEvent.class, team, tile));
}
/**Returns whether a tile can be placed at this location by this team.*/

View File

@@ -5,7 +5,6 @@ import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.bullet.BulletType;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Wall;
@@ -69,7 +68,7 @@ public class DeflectorWall extends Wall {
bullet.getVelocity().y *= -1;
}
bullet.updateVelocity(BulletType.getByID(bullet.getTypeID()).drag);
bullet.updateVelocity(0f);
bullet.resetOwner(entity, Team.none);
bullet.scaleTime(1f);
bullet.supressCollision();