Ammo resupply point implementation
@ -792,6 +792,7 @@ rules.buildspeedmultiplier = Build Speed Multiplier
|
||||
rules.deconstructrefundmultiplier = Deconstruct Refund Multiplier
|
||||
rules.waitForWaveToEnd = Waves Wait for Enemies
|
||||
rules.dropzoneradius = Drop Zone Radius:[lightgray] (tiles)
|
||||
rules.unitammo = Units Require Ammo
|
||||
rules.title.waves = Waves
|
||||
rules.title.resourcesbuilding = Resources & Building
|
||||
rules.title.enemy = Enemies
|
||||
|
Before Width: | Height: | Size: 645 KiB After Width: | Height: | Size: 652 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 130 KiB |
@ -79,7 +79,7 @@ public class Blocks implements ContentList{
|
||||
//units
|
||||
groundFactory, airFactory, navalFactory,
|
||||
additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor,
|
||||
repairPoint,
|
||||
repairPoint, resupplyPoint,
|
||||
|
||||
//campaign
|
||||
launchPad, launchPadLarge, coreSilo, dataProcessor,
|
||||
@ -1754,6 +1754,15 @@ public class Blocks implements ContentList{
|
||||
powerUse = 1f;
|
||||
}};
|
||||
|
||||
resupplyPoint = new ResupplyPoint("resupply-point"){{
|
||||
requirements(Category.units, BuildVisibility.ammoOnly, ItemStack.with(Items.lead, 20, Items.copper, 15, Items.silicon, 15));
|
||||
|
||||
size = 2;
|
||||
range = 80f;
|
||||
|
||||
consumes.item(Items.copper, 1);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region sandbox
|
||||
|
||||
|
@ -98,6 +98,9 @@ public class Logic implements ApplicationListener{
|
||||
SectorDamage.apply(state.rules.sector.getTurnsPassed());
|
||||
state.rules.sector.setTurnsPassed(0);
|
||||
}
|
||||
|
||||
//enable infinite ammo for wave team by default
|
||||
state.rules.waveTeam.rules().infiniteAmmo = true;
|
||||
});
|
||||
|
||||
//TODO dying takes up a turn (?)
|
||||
|
@ -97,7 +97,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
|
||||
mount.targetRotation = angleTo(mount.aimX, mount.aimY);
|
||||
}
|
||||
|
||||
if(mount.shoot && (ammo > 0 || !state.rules.unitAmmo)){
|
||||
if(mount.shoot && (ammo > 0 || !state.rules.unitAmmo || team().rules().infiniteAmmo)){
|
||||
float rotation = this.rotation - 90;
|
||||
|
||||
//shoot if applicable
|
||||
@ -118,10 +118,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc{
|
||||
|
||||
if(mount.weapon.mirror) mount.side = !mount.side;
|
||||
mount.reload = weapon.reload;
|
||||
}
|
||||
|
||||
ammo --;
|
||||
if(ammo < 0) ammo = 0;
|
||||
ammo --;
|
||||
if(ammo < 0) ammo = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ public class Rules{
|
||||
public boolean cheat;
|
||||
/** If true, resources are not consumed when building. */
|
||||
public boolean infiniteResources;
|
||||
/** If true, this team has infinite unit ammo. */
|
||||
public boolean infiniteAmmo;
|
||||
}
|
||||
|
||||
/** Copies this ruleset exactly. Not efficient at all, do not use often. */
|
||||
|
@ -52,7 +52,7 @@ public class UnitType extends UnlockableContent{
|
||||
public boolean flipBackLegs = true;
|
||||
|
||||
public int itemCapacity = 30;
|
||||
public int ammoCapacity = 100;
|
||||
public int ammoCapacity = 220;
|
||||
public int drillTier = -1;
|
||||
public float buildSpeed = 1f, mineSpeed = 1f;
|
||||
|
||||
|
@ -155,6 +155,7 @@ public class CustomRulesDialog extends BaseDialog{
|
||||
main.row();
|
||||
|
||||
title("$rules.title.unit");
|
||||
check("$rules.unitammo", b -> rules.unitAmmo = b, () -> rules.unitAmmo);
|
||||
number("$rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier);
|
||||
number("$rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
|
||||
number("$rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
|
||||
|
@ -163,10 +163,17 @@ public interface Autotiler{
|
||||
|
||||
/** @return whether this tile is looking at the other tile, or the other tile is looking at this one.
|
||||
* If the other tile does not rotate, it is always considered to be facing this one. */
|
||||
default boolean lookingAt(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
default boolean lookingAtEither(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
||||
|| (!otherblock.rotatedOutput(otherx, othery) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
|
||||
}
|
||||
|
||||
/** @return whether this tile is looking at the other tile. */
|
||||
default boolean lookingAt(Tile tile, int rotation, int otherx, int othery, Block otherblock){
|
||||
Tile facing = Edges.getFacingEdge(otherblock, otherx, othery, tile);
|
||||
return facing != null &&
|
||||
Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, facing.x, facing.y);
|
||||
}
|
||||
|
||||
boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock);
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ public class Conveyor extends Block implements Autotiler{
|
||||
|
||||
@Override
|
||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
return (otherblock.outputsItems() || lookingAt(tile, rotation, otherx, othery, otherblock))
|
||||
&& lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,7 +55,7 @@ public class StackConveyor extends Block implements Autotiler{
|
||||
if(tile.entity instanceof StackConveyorEntity){
|
||||
int state = ((StackConveyorEntity)tile.entity).state;
|
||||
if(state == stateLoad){ //standard conveyor mode
|
||||
return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
return otherblock.outputsItems() && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
}else if(state == stateUnload){ //router mode
|
||||
return (otherblock.hasItems || otherblock.outputsItems() || otherblock.acceptsItems) &&
|
||||
(notLookingAt(tile, rotation, otherx, othery, otherrot, otherblock) ||
|
||||
|
@ -64,7 +64,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
|
||||
@Override
|
||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return otherblock.hasLiquids && otherblock.outputsLiquid && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
return otherblock.hasLiquids && otherblock.outputsLiquid && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -43,14 +43,14 @@ public class LiquidConverter extends GenericCrafter{
|
||||
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid);
|
||||
|
||||
if(cons.valid()){
|
||||
float use = Math.min(cl.amount * delta(), liquidCapacity - liquids.get(outputLiquid.liquid)) * efficiency();
|
||||
float use = Math.min(cl.amount * edelta(), liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
|
||||
useContent(outputLiquid.liquid);
|
||||
progress += use / cl.amount / craftTime;
|
||||
progress += use / cl.amount;
|
||||
liquids.add(outputLiquid.liquid, use);
|
||||
if(progress >= 1f){
|
||||
if(progress >= craftTime){
|
||||
consume();
|
||||
progress = 0f;
|
||||
progress %= craftTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.units.*;
|
||||
import mindustry.world.meta.*;
|
||||
import mindustry.world.modules.*;
|
||||
|
||||
@ -25,6 +26,13 @@ import static mindustry.Vars.*;
|
||||
public class CoreBlock extends StorageBlock{
|
||||
public UnitType unitType = UnitTypes.alpha;
|
||||
|
||||
public final int timerResupply = timers++;
|
||||
|
||||
public int ammoAmount = 5;
|
||||
public float resupplyRate = 10f;
|
||||
public float resupplyRange = 60f;
|
||||
public Item resupplyItem = Items.copper;
|
||||
|
||||
public CoreBlock(String name){
|
||||
super(name);
|
||||
|
||||
@ -101,6 +109,15 @@ public class CoreBlock extends StorageBlock{
|
||||
Call.onPlayerSpawn(tile, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
|
||||
//resupply nearby units
|
||||
if(items.has(resupplyItem) && timer(timerResupply, resupplyRate) && ResupplyPoint.resupply(this, resupplyRange, ammoAmount, resupplyItem.color)){
|
||||
items.remove(resupplyItem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(){
|
||||
Drawf.light(team, x, y, 30f * size, Pal.accent, 0.5f + Mathf.absin(20f, 0.1f));
|
||||
|
65
core/src/mindustry/world/blocks/units/ResupplyPoint.java
Normal file
@ -0,0 +1,65 @@
|
||||
package mindustry.world.blocks.units;
|
||||
|
||||
import arc.graphics.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class ResupplyPoint extends Block{
|
||||
public final int timerResupply = timers++;
|
||||
|
||||
public int ammoAmount = 10;
|
||||
public float resupplyRate = 5f;
|
||||
public float range = 60f;
|
||||
public Color ammoColor = Items.copper.color;
|
||||
|
||||
public ResupplyPoint(String name){
|
||||
super(name);
|
||||
solid = update = true;
|
||||
hasItems = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean outputsItems(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
Drawf.dashCircle(x * tilesize + offset(), y * tilesize + offset(), range, Pal.placing);
|
||||
}
|
||||
|
||||
public class ResupplyPointEntity extends TileEntity{
|
||||
|
||||
@Override
|
||||
public void drawSelect(){
|
||||
Drawf.dashCircle(x, y, range, team.color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(consValid() && timer(timerResupply, resupplyRate / timeScale) && resupply(this, range, ammoAmount, ammoColor)){
|
||||
consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Tries to resupply nearby units.
|
||||
* @return whether resupplying was successful. If unit ammo is disabled, always returns false. */
|
||||
public static boolean resupply(TileEntity tile, float range, int ammoAmount, Color ammoColor){
|
||||
if(!state.rules.unitAmmo) return false;
|
||||
|
||||
Unitc unit = Units.closest(tile.team, tile.x, tile.y, range, u -> u.ammo() <= u.type().ammoCapacity - ammoAmount);
|
||||
if(unit != null){
|
||||
Fx.itemTransfer.at(tile.x, tile.y, ammoAmount / 2f, ammoColor, unit);
|
||||
unit.ammo(Math.min(unit.ammo() + ammoAmount, unit.type().ammoCapacity));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@ public enum BuildVisibility{
|
||||
debugOnly(() -> false),
|
||||
sandboxOnly(() -> Vars.state.rules.infiniteResources),
|
||||
campaignOnly(() -> Vars.state.isCampaign()),
|
||||
lightingOnly(() -> Vars.state.rules.lighting);
|
||||
lightingOnly(() -> Vars.state.rules.lighting),
|
||||
ammoOnly(() -> Vars.state.rules.unitAmmo);
|
||||
|
||||
private final Boolp visible;
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=06c938d6dced0d9bf9f8ec98d4767b38f633f8fa
|
||||
archash=f76b0c94953c07ef2ac40858b3b615a34911bdf7
|
||||
|