Too many things to list
This commit is contained in:
@@ -818,6 +818,7 @@ ability.shieldregenfield = Shield Regen Field
|
|||||||
ability.movelightning = Movement Lightning
|
ability.movelightning = Movement Lightning
|
||||||
ability.energyfield = Energy Field: [accent]{0}[] damage ~ [accent]{1}[] blocks / [accent]{2}[] targets
|
ability.energyfield = Energy Field: [accent]{0}[] damage ~ [accent]{1}[] blocks / [accent]{2}[] targets
|
||||||
|
|
||||||
|
bar.onlycoredeposit = Only Core Depositing Allowed
|
||||||
bar.drilltierreq = Better Drill Required
|
bar.drilltierreq = Better Drill Required
|
||||||
bar.noresources = Missing Resources
|
bar.noresources = Missing Resources
|
||||||
bar.corereq = Core Base Required
|
bar.corereq = Core Base Required
|
||||||
|
|||||||
@@ -545,3 +545,4 @@
|
|||||||
63147=blast-door|block-blast-door-ui
|
63147=blast-door|block-blast-door-ui
|
||||||
63146=alphaaaa|alphaaaa
|
63146=alphaaaa|alphaaaa
|
||||||
63145=malis|team-malis
|
63145=malis|team-malis
|
||||||
|
63144=canvas|block-canvas-ui
|
||||||
|
|||||||
Binary file not shown.
@@ -152,6 +152,7 @@ public class Blocks{
|
|||||||
|
|
||||||
//logic
|
//logic
|
||||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank,
|
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank,
|
||||||
|
canvas,
|
||||||
worldProcessor, worldCell,
|
worldProcessor, worldCell,
|
||||||
|
|
||||||
//campaign
|
//campaign
|
||||||
@@ -1588,7 +1589,6 @@ public class Blocks{
|
|||||||
requirements(Category.defense, with(Items.beryllium, 6));
|
requirements(Category.defense, with(Items.beryllium, 6));
|
||||||
health = 130 * wallHealthMultiplier;
|
health = 130 * wallHealthMultiplier;
|
||||||
armor = 2f;
|
armor = 2f;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
berylliumWallLarge = new Wall("beryllium-wall-large"){{
|
berylliumWallLarge = new Wall("beryllium-wall-large"){{
|
||||||
@@ -1596,14 +1596,12 @@ public class Blocks{
|
|||||||
health = 130 * wallHealthMultiplier * 4;
|
health = 130 * wallHealthMultiplier * 4;
|
||||||
armor = 2f;
|
armor = 2f;
|
||||||
size = 2;
|
size = 2;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
tungstenWall = new Wall("tungsten-wall"){{
|
tungstenWall = new Wall("tungsten-wall"){{
|
||||||
requirements(Category.defense, with(Items.tungsten, 6));
|
requirements(Category.defense, with(Items.tungsten, 6));
|
||||||
health = 180 * wallHealthMultiplier;
|
health = 180 * wallHealthMultiplier;
|
||||||
armor = 14f;
|
armor = 14f;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
tungstenWallLarge = new Wall("tungsten-wall-large"){{
|
tungstenWallLarge = new Wall("tungsten-wall-large"){{
|
||||||
@@ -1611,7 +1609,6 @@ public class Blocks{
|
|||||||
health = 180 * wallHealthMultiplier * 4;
|
health = 180 * wallHealthMultiplier * 4;
|
||||||
armor = 14f;
|
armor = 14f;
|
||||||
size = 2;
|
size = 2;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
blastDoor = new AutoDoor("blast-door"){{
|
blastDoor = new AutoDoor("blast-door"){{
|
||||||
@@ -1619,14 +1616,12 @@ public class Blocks{
|
|||||||
health = 175 * wallHealthMultiplier * 4;
|
health = 175 * wallHealthMultiplier * 4;
|
||||||
armor = 14f;
|
armor = 14f;
|
||||||
size = 2;
|
size = 2;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
carbideWall = new Wall("carbide-wall"){{
|
carbideWall = new Wall("carbide-wall"){{
|
||||||
requirements(Category.defense, with(Items.thorium, 6, Items.carbide, 6));
|
requirements(Category.defense, with(Items.thorium, 6, Items.carbide, 6));
|
||||||
health = 240 * wallHealthMultiplier;
|
health = 240 * wallHealthMultiplier;
|
||||||
armor = 16f;
|
armor = 16f;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
carbideWallLarge = new Wall("carbide-wall-large"){{
|
carbideWallLarge = new Wall("carbide-wall-large"){{
|
||||||
@@ -1634,7 +1629,6 @@ public class Blocks{
|
|||||||
health = 240 * wallHealthMultiplier * 4;
|
health = 240 * wallHealthMultiplier * 4;
|
||||||
armor = 16f;
|
armor = 16f;
|
||||||
size = 2;
|
size = 2;
|
||||||
buildCostMultiplier = 4f;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
mender = new MendProjector("mender"){{
|
mender = new MendProjector("mender"){{
|
||||||
@@ -2987,7 +2981,7 @@ public class Blocks{
|
|||||||
|
|
||||||
//TODO these may work in space, but what's the point?
|
//TODO these may work in space, but what's the point?
|
||||||
lancer = new PowerTurret("lancer"){{
|
lancer = new PowerTurret("lancer"){{
|
||||||
requirements(Category.turret, with(Items.copper, 70, Items.lead, 70, Items.silicon, 70));
|
requirements(Category.turret, with(Items.copper, 60, Items.lead, 70, Items.silicon, 60, Items.titanium, 30));
|
||||||
range = 165f;
|
range = 165f;
|
||||||
|
|
||||||
shoot.firstShotDelay = 40f;
|
shoot.firstShotDelay = 40f;
|
||||||
@@ -3003,6 +2997,7 @@ public class Blocks{
|
|||||||
scaledHealth = 280;
|
scaledHealth = 280;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
moveWhileCharging = false;
|
moveWhileCharging = false;
|
||||||
|
accurateDelay = false;
|
||||||
shootSound = Sounds.laser;
|
shootSound = Sounds.laser;
|
||||||
coolant = consume(new ConsumeCoolant(0.2f));
|
coolant = consume(new ConsumeCoolant(0.2f));
|
||||||
|
|
||||||
@@ -3683,7 +3678,7 @@ public class Blocks{
|
|||||||
coolantMultiplier = 6f;
|
coolantMultiplier = 6f;
|
||||||
|
|
||||||
shootShake = 1f;
|
shootShake = 1f;
|
||||||
ammoPerShot = 4;
|
ammoPerShot = 2;
|
||||||
drawer = new DrawTurret("reinforced-");
|
drawer = new DrawTurret("reinforced-");
|
||||||
shootY = -2;
|
shootY = -2;
|
||||||
outlineColor = Pal.darkOutline;
|
outlineColor = Pal.darkOutline;
|
||||||
@@ -4484,6 +4479,15 @@ public class Blocks{
|
|||||||
size = 6;
|
size = 6;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
canvas = new CanvasBlock("canvas"){{
|
||||||
|
requirements(Category.logic, with(Items.silicon, 40));
|
||||||
|
|
||||||
|
canvasSize = 12;
|
||||||
|
padding = 7f / 4f * 2f;
|
||||||
|
|
||||||
|
size = 2;
|
||||||
|
}};
|
||||||
|
|
||||||
worldProcessor = new LogicBlock("world-processor"){{
|
worldProcessor = new LogicBlock("world-processor"){{
|
||||||
requirements(Category.logic, BuildVisibility.editorOnly, with());
|
requirements(Category.logic, BuildVisibility.editorOnly, with());
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ public class ErekirTechTree{
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
node(radar, Seq.with(new Research(beamNode), new Research(turbineCondenser), new Research(fabricator)), () -> {
|
node(radar, Seq.with(new Research(beamNode), new Research(turbineCondenser), new Research(fabricator), new OnSector(SectorPresets.two)), () -> {
|
||||||
node(breach, Seq.with(new Research(siliconArcFurnace), new OnSector(two)), () -> {
|
node(breach, Seq.with(new Research(siliconArcFurnace), new OnSector(two)), () -> {
|
||||||
node(berylliumWall, () -> {
|
node(berylliumWall, () -> {
|
||||||
node(berylliumWallLarge, () -> {
|
node(berylliumWallLarge, () -> {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public class Planets{
|
|||||||
r.fog = true;
|
r.fog = true;
|
||||||
r.staticFog = true; //TODO decide, is this a good idea?
|
r.staticFog = true; //TODO decide, is this a good idea?
|
||||||
r.lighting = false;
|
r.lighting = false;
|
||||||
|
r.onlyDepositCore = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
unlockedOnLand.add(Blocks.coreBastion);
|
unlockedOnLand.add(Blocks.coreBastion);
|
||||||
|
|||||||
@@ -3450,6 +3450,7 @@ public class UnitTypes{
|
|||||||
|
|
||||||
fogRadius = 0f;
|
fogRadius = 0f;
|
||||||
targetable = false;
|
targetable = false;
|
||||||
|
hittable = false;
|
||||||
|
|
||||||
setEnginesMirror(
|
setEnginesMirror(
|
||||||
new UnitEngine(21 / 4f, 19 / 4f, 2.2f, 45f),
|
new UnitEngine(21 / 4f, 19 / 4f, 2.2f, 45f),
|
||||||
@@ -3509,6 +3510,7 @@ public class UnitTypes{
|
|||||||
|
|
||||||
fogRadius = 0f;
|
fogRadius = 0f;
|
||||||
targetable = false;
|
targetable = false;
|
||||||
|
hittable = false;
|
||||||
|
|
||||||
engineOffset = 7.2f;
|
engineOffset = 7.2f;
|
||||||
engineSize = 3.1f;
|
engineSize = 3.1f;
|
||||||
@@ -3583,6 +3585,7 @@ public class UnitTypes{
|
|||||||
|
|
||||||
fogRadius = 0f;
|
fogRadius = 0f;
|
||||||
targetable = false;
|
targetable = false;
|
||||||
|
hittable = false;
|
||||||
|
|
||||||
engineOffset = 7.5f;
|
engineOffset = 7.5f;
|
||||||
engineSize = 3.4f;
|
engineSize = 3.4f;
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ public class Logic implements ApplicationListener{
|
|||||||
//makes cores go derelict in RTS mode, helps clean things up
|
//makes cores go derelict in RTS mode, helps clean things up
|
||||||
if(e.tile.build instanceof CoreBuild core && core.team.isAI() && core.team.rules().rtsAi){
|
if(e.tile.build instanceof CoreBuild core && core.team.isAI() && core.team.rules().rtsAi){
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
core.team.data().makeDerelict(core.x, core.y, state.rules.enemyCoreBuildRadius);
|
core.team.data().timeDestroy(core.x, core.y, state.rules.enemyCoreBuildRadius);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ public class Damage{
|
|||||||
});
|
});
|
||||||
|
|
||||||
Units.nearbyEnemies(b.team, rect, u -> {
|
Units.nearbyEnemies(b.team, rect, u -> {
|
||||||
if(u.checkTarget(b.type.collidesAir, b.type.collidesGround)){
|
if(u.checkTarget(b.type.collidesAir, b.type.collidesGround) && u.type.hittable){
|
||||||
distances.add(u.dst(b));
|
distances.add(u.dst(b));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -272,6 +272,7 @@ public class Damage{
|
|||||||
float x2 = vec.x + x, y2 = vec.y + y;
|
float x2 = vec.x + x, y2 = vec.y + y;
|
||||||
|
|
||||||
Cons<Unit> cons = e -> {
|
Cons<Unit> cons = e -> {
|
||||||
|
if(!e.type.hittable) return;
|
||||||
//the peirce cap works for units, but really terribly, I'm just disabling it for now.
|
//the peirce cap works for units, but really terribly, I'm just disabling it for now.
|
||||||
//if(pierceCap > 0 && pierceCount > pierceCap) return;
|
//if(pierceCap > 0 && pierceCount > pierceCap) return;
|
||||||
|
|
||||||
@@ -373,7 +374,7 @@ public class Damage{
|
|||||||
/** Damages all entities and blocks in a radius that are enemies of the team. */
|
/** 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, Boolf<Unit> predicate, Cons<Unit> acceptor){
|
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unit> predicate, Cons<Unit> acceptor){
|
||||||
Cons<Unit> cons = entity -> {
|
Cons<Unit> cons = entity -> {
|
||||||
if(!predicate.get(entity)) return;
|
if(!predicate.get(entity) || !entity.type.hittable) return;
|
||||||
|
|
||||||
entity.hitbox(hitrect);
|
entity.hitbox(hitrect);
|
||||||
if(!hitrect.overlaps(rect)){
|
if(!hitrect.overlaps(rect)){
|
||||||
@@ -437,7 +438,7 @@ public class Damage{
|
|||||||
/** Damages all entities and blocks in a radius that are enemies of the team. */
|
/** 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, boolean complete, boolean air, boolean ground, boolean scaled, Bullet source){
|
public static void damage(Team team, float x, float y, float radius, float damage, boolean complete, boolean air, boolean ground, boolean scaled, Bullet source){
|
||||||
Cons<Unit> cons = entity -> {
|
Cons<Unit> cons = entity -> {
|
||||||
if(entity.team == team || !entity.within(x, y, radius + (scaled ? entity.hitSize / 2f : 0f)) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){
|
if(entity.team == team || !entity.type.hittable || !entity.within(x, y, radius + (scaled ? entity.hitSize / 2f : 0f)) || (entity.isFlying() && !air) || (entity.isGrounded() && !ground)){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class EntityCollisions{
|
|||||||
float vbx = b.getX() - b.lastX();
|
float vbx = b.getX() - b.lastX();
|
||||||
float vby = b.getY() - b.lastY();
|
float vby = b.getY() - b.lastY();
|
||||||
|
|
||||||
if(a != b && a.collides(b)){
|
if(a != b && a.collides(b) && b.collides(a)){
|
||||||
l1.set(a.getX(), a.getY());
|
l1.set(a.getX(), a.getY());
|
||||||
boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay,
|
boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay,
|
||||||
r2.x, r2.y, r2.width, r2.height, vbx, vby, l1);
|
r2.x, r2.y, r2.width, r2.height, vbx, vby, l1);
|
||||||
|
|||||||
@@ -257,6 +257,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
|||||||
return type.isCounted;
|
return type.isCounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Replace
|
||||||
|
public boolean collides(Hitboxc other){
|
||||||
|
return type.hittable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int itemCapacity(){
|
public int itemCapacity(){
|
||||||
return type.itemCapacity;
|
return type.itemCapacity;
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ public class Rules{
|
|||||||
public boolean placeRangeCheck = false;
|
public boolean placeRangeCheck = false;
|
||||||
/** If true, dead teams in PvP automatically have their blocks & units converted to derelict upon death. */
|
/** If true, dead teams in PvP automatically have their blocks & units converted to derelict upon death. */
|
||||||
public boolean cleanupDeadTeams = true;
|
public boolean cleanupDeadTeams = true;
|
||||||
|
/** If true, items can only be deposited in the core. */
|
||||||
|
public boolean onlyDepositCore = false;
|
||||||
/** Radius around enemy wave drop zones.*/
|
/** Radius around enemy wave drop zones.*/
|
||||||
public float dropZoneRadius = 300f;
|
public float dropZoneRadius = 300f;
|
||||||
/** Time between waves in ticks. */
|
/** Time between waves in ticks. */
|
||||||
|
|||||||
@@ -305,6 +305,20 @@ public class Teams{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Make all buildings within this range explode. */
|
||||||
|
public void timeDestroy(float x, float y, float range){
|
||||||
|
var builds = new Seq<Building>();
|
||||||
|
if(buildings != null){
|
||||||
|
buildings.intersect(x - range, y - range, range * 2f, range * 2f, builds);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var build : builds){
|
||||||
|
if(build.within(x, y, range)){
|
||||||
|
Time.run(Mathf.random(0f, 60f * 6f), build::kill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void scheduleDerelict(Building build){
|
private void scheduleDerelict(Building build){
|
||||||
//TODO this may cause a lot of packet spam, optimize?
|
//TODO this may cause a lot of packet spam, optimize?
|
||||||
Call.setTeam(build, Team.derelict);
|
Call.setTeam(build, Team.derelict);
|
||||||
|
|||||||
@@ -238,14 +238,19 @@ public class OverlayRenderer{
|
|||||||
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time, 5f, 1f));
|
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time, 5f, 1f));
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|
||||||
Building tile = world.buildWorld(v.x, v.y);
|
Building build = world.buildWorld(v.x, v.y);
|
||||||
if(input.canDropItem() && tile != null && tile.interactable(player.team()) && tile.acceptStack(player.unit().item(), player.unit().stack.amount, player.unit()) > 0 && player.within(tile, itemTransferRange)){
|
if(input.canDropItem() && build != null && build.interactable(player.team()) && build.acceptStack(player.unit().item(), player.unit().stack.amount, player.unit()) > 0 && player.within(build, itemTransferRange)){
|
||||||
|
boolean invalid = (state.rules.onlyDepositCore && !(build instanceof CoreBuild));
|
||||||
|
|
||||||
Lines.stroke(3f, Pal.gray);
|
Lines.stroke(3f, Pal.gray);
|
||||||
Lines.square(tile.x, tile.y, tile.block.size * tilesize / 2f + 3 + Mathf.absin(Time.time, 5f, 1f));
|
Lines.square(build.x, build.y, build.block.size * tilesize / 2f + 3 + Mathf.absin(Time.time, 5f, 1f));
|
||||||
Lines.stroke(1f, Pal.place);
|
Lines.stroke(1f, invalid ? Pal.remove : Pal.place);
|
||||||
Lines.square(tile.x, tile.y, tile.block.size * tilesize / 2f + 2 + Mathf.absin(Time.time, 5f, 1f));
|
Lines.square(build.x, build.y, build.block.size * tilesize / 2f + 2 + Mathf.absin(Time.time, 5f, 1f));
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|
||||||
|
if(invalid){
|
||||||
|
build.block.drawPlaceText(Core.bundle.get("bar.onlycoredeposit"), build.tileX(), build.tileY(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import mindustry.world.blocks.*;
|
|||||||
import mindustry.world.blocks.distribution.*;
|
import mindustry.world.blocks.distribution.*;
|
||||||
import mindustry.world.blocks.payloads.*;
|
import mindustry.world.blocks.payloads.*;
|
||||||
import mindustry.world.blocks.storage.*;
|
import mindustry.world.blocks.storage.*;
|
||||||
|
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||||
import mindustry.world.meta.*;
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -270,7 +271,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
|
|
||||||
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
||||||
public static void transferInventory(Player player, Building build){
|
public static void transferInventory(Player player, Building build){
|
||||||
if(player == null || build == null || !player.within(build, itemTransferRange) || build.items == null || player.dead()) return;
|
if(player == null || build == null || !player.within(build, itemTransferRange) || build.items == null || player.dead() || (state.rules.onlyDepositCore && !(build instanceof CoreBuild))) return;
|
||||||
|
|
||||||
if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, build) ||
|
if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, build) ||
|
||||||
!netServer.admins.allowAction(player, ActionType.depositItem, build.tile, action -> {
|
!netServer.admins.allowAction(player, ActionType.depositItem, build.tile, action -> {
|
||||||
@@ -1390,8 +1391,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
|
|
||||||
ItemStack stack = player.unit().stack;
|
ItemStack stack = player.unit().stack;
|
||||||
|
|
||||||
if(build != null && build.acceptStack(stack.item, stack.amount, player.unit()) > 0 && build.interactable(player.team()) && build.block.hasItems && player.unit().stack().amount > 0 && build.interactable(player.team())){
|
if(build != null && build.acceptStack(stack.item, stack.amount, player.unit()) > 0 && build.interactable(player.team()) &&
|
||||||
|
build.block.hasItems && player.unit().stack().amount > 0 && build.interactable(player.team())){
|
||||||
|
if(!(state.rules.onlyDepositCore && !(build instanceof CoreBuild))){
|
||||||
Call.transferInventory(player, build);
|
Call.transferInventory(player, build);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
Call.dropItem(player.angleTo(x, y));
|
Call.dropItem(player.angleTo(x, y));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ public class UnitType extends UnlockableContent{
|
|||||||
public float targetPriority = 0f;
|
public float targetPriority = 0f;
|
||||||
/** If false, this unit is not targeted by anything. */
|
/** If false, this unit is not targeted by anything. */
|
||||||
public boolean targetable = true;
|
public boolean targetable = true;
|
||||||
|
/** If true, this unit can be hit with bullets/splash damage. */
|
||||||
|
public boolean hittable = true;
|
||||||
public boolean drawBuildBeam = true;
|
public boolean drawBuildBeam = true;
|
||||||
public boolean rotateToBuilding = true;
|
public boolean rotateToBuilding = true;
|
||||||
public float commandRadius = 150f;
|
public float commandRadius = 150f;
|
||||||
|
|||||||
250
core/src/mindustry/world/blocks/logic/CanvasBlock.java
Normal file
250
core/src/mindustry/world/blocks/logic/CanvasBlock.java
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
package mindustry.world.blocks.logic;
|
||||||
|
|
||||||
|
import arc.graphics.*;
|
||||||
|
import arc.graphics.g2d.*;
|
||||||
|
import arc.input.*;
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.math.geom.*;
|
||||||
|
import arc.scene.*;
|
||||||
|
import arc.scene.event.*;
|
||||||
|
import arc.scene.ui.*;
|
||||||
|
import arc.scene.ui.layout.*;
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import arc.util.io.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.ui.*;
|
||||||
|
import mindustry.world.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class CanvasBlock extends Block{
|
||||||
|
public float padding = 0f;
|
||||||
|
public int canvasSize = 8;
|
||||||
|
public int[] palette = {0x000000ff, 0x55415f_ff, 0x646964_ff, 0xd77355_ff, 0x508cd7_ff, 0x64b964_ff, 0xe6c86e_ff, 0xdcf5ff_ff};
|
||||||
|
public int bitsPerPixel;
|
||||||
|
public IntIntMap colorToIndex = new IntIntMap();
|
||||||
|
|
||||||
|
public CanvasBlock(String name){
|
||||||
|
super(name);
|
||||||
|
|
||||||
|
configurable = true;
|
||||||
|
destructible = true;
|
||||||
|
solid = true;
|
||||||
|
|
||||||
|
config(byte[].class, (CanvasBuild build, byte[] bytes) -> {
|
||||||
|
if(build.data.length == bytes.length){
|
||||||
|
build.data = bytes;
|
||||||
|
build.updateTexture();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(){
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
for(int i = 0; i < palette.length; i++){
|
||||||
|
colorToIndex.put(palette[i], i);
|
||||||
|
}
|
||||||
|
bitsPerPixel = Mathf.log2(Mathf.nextPowerOfTwo(palette.length));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CanvasBuild extends Building{
|
||||||
|
public @Nullable Texture texture;
|
||||||
|
public byte[] data = new byte[Mathf.ceil(canvasSize * canvasSize * bitsPerPixel / 8f)];
|
||||||
|
|
||||||
|
public void updateTexture(){
|
||||||
|
Pixmap pix = makePixmap();
|
||||||
|
if(texture != null){
|
||||||
|
texture.draw(pix);
|
||||||
|
}else{
|
||||||
|
texture = new Texture(pix);
|
||||||
|
}
|
||||||
|
pix.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pixmap makePixmap(){
|
||||||
|
Pixmap pix = new Pixmap(canvasSize, canvasSize);
|
||||||
|
int bpp = bitsPerPixel;
|
||||||
|
int pixels = canvasSize * canvasSize;
|
||||||
|
for(int i = 0; i < pixels; i++){
|
||||||
|
int bitOffset = i * bpp;
|
||||||
|
int pal = getByte(bitOffset);
|
||||||
|
pix.set(i % canvasSize, i / canvasSize, palette[pal]);
|
||||||
|
}
|
||||||
|
return pix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] packPixmap(Pixmap pixmap){
|
||||||
|
byte[] bytes = new byte[data.length];
|
||||||
|
int pixels = canvasSize * canvasSize;
|
||||||
|
for(int i = 0; i < pixels; i++){
|
||||||
|
int color = pixmap.get(i % canvasSize, i / canvasSize);
|
||||||
|
int palIndex = colorToIndex.get(color);
|
||||||
|
setByte(bytes, i * bitsPerPixel, palIndex);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getByte(int bitOffset){
|
||||||
|
int result = 0, bpp = bitsPerPixel;
|
||||||
|
for(int i = 0; i < bpp; i++){
|
||||||
|
int word = i + bitOffset >>> 3;
|
||||||
|
result |= (((data[word] & (1 << (i + bitOffset & 7))) == 0 ? 0 : 1) << i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setByte(byte[] bytes, int bitOffset, int value){
|
||||||
|
int bpp = bitsPerPixel;
|
||||||
|
for(int i = 0; i < bpp; i++){
|
||||||
|
int word = i + bitOffset >>> 3;
|
||||||
|
|
||||||
|
if(((value >>> i) & 1) == 0){
|
||||||
|
bytes[word] &= ~(1 << (i + bitOffset & 7));
|
||||||
|
}else{
|
||||||
|
bytes[word] |= (1 << (i + bitOffset & 7));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(){
|
||||||
|
super.draw();
|
||||||
|
|
||||||
|
if(texture == null){
|
||||||
|
updateTexture();
|
||||||
|
}
|
||||||
|
Tmp.tr1.set(texture);
|
||||||
|
Draw.rect(Tmp.tr1, x, y, size * tilesize - padding, size * tilesize - padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(){
|
||||||
|
super.remove();
|
||||||
|
if(texture != null){
|
||||||
|
texture.dispose();
|
||||||
|
texture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void buildConfiguration(Table table){
|
||||||
|
table.button(Icon.pencil, Styles.clearTransi, () -> {
|
||||||
|
Dialog dialog = new Dialog();
|
||||||
|
|
||||||
|
Pixmap pix = makePixmap();
|
||||||
|
Texture texture = new Texture(pix);
|
||||||
|
int[] curColor = {palette[0]};
|
||||||
|
boolean[] modified = {false};
|
||||||
|
|
||||||
|
dialog.cont.table(Tex.pane, body -> {
|
||||||
|
body.stack(new Element(){
|
||||||
|
int lastX, lastY;
|
||||||
|
|
||||||
|
{
|
||||||
|
addListener(new InputListener(){
|
||||||
|
int convertX(float ex){
|
||||||
|
return (int)((ex - x) / width * canvasSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
int convertY(float ey){
|
||||||
|
return pix.height - 1 - (int)((ey - y) / height * canvasSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean touchDown(InputEvent event, float ex, float ey, int pointer, KeyCode button){
|
||||||
|
int cx = convertX(ex), cy = convertY(ey);
|
||||||
|
draw(cx, cy);
|
||||||
|
lastX = cx;
|
||||||
|
lastY = cy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void touchDragged(InputEvent event, float ex, float ey, int pointer){
|
||||||
|
int cx = convertX(ex), cy = convertY(ey);
|
||||||
|
Bresenham2.line(lastX, lastY, cx, cy, (x, y) -> draw(x, y));
|
||||||
|
lastX = cx;
|
||||||
|
lastY = cy;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw(int x, int y){
|
||||||
|
if(pix.get(x, y) != curColor[0]){
|
||||||
|
pix.set(x, y, curColor[0]);
|
||||||
|
Pixmaps.drawPixel(texture, x, y, curColor[0]);
|
||||||
|
modified[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(){
|
||||||
|
Tmp.tr1.set(texture);
|
||||||
|
Draw.alpha(parentAlpha);
|
||||||
|
Draw.rect(Tmp.tr1, x + width/2f, y + height/2f, width, height);
|
||||||
|
}
|
||||||
|
}, new GridImage(canvasSize, canvasSize){{
|
||||||
|
touchable = Touchable.disabled;
|
||||||
|
}}).size(500f);
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.cont.row();
|
||||||
|
|
||||||
|
dialog.cont.table(Tex.button, p -> {
|
||||||
|
for(int i = 0; i < palette.length; i++){
|
||||||
|
int fi = i;
|
||||||
|
|
||||||
|
var button = p.button(Tex.whiteui, Styles.clearTogglei, 30, () -> {
|
||||||
|
curColor[0] = palette[fi];
|
||||||
|
}).size(44).checked(b -> curColor[0] == palette[fi]).get();
|
||||||
|
button.getStyle().imageUpColor = new Color(palette[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.closeOnBack();
|
||||||
|
|
||||||
|
dialog.buttons.defaults().size(150f, 64f);
|
||||||
|
dialog.buttons.button("@cancel", Icon.cancel, dialog::hide);
|
||||||
|
dialog.buttons.button("@ok", Icon.ok, () -> {
|
||||||
|
if(modified[0]){
|
||||||
|
configure(packPixmap(pix));
|
||||||
|
pix.dispose();
|
||||||
|
texture.dispose();
|
||||||
|
}
|
||||||
|
dialog.hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog.show();
|
||||||
|
}).size(40f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] config(){
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(Writes write){
|
||||||
|
super.write(write);
|
||||||
|
|
||||||
|
//for future canvas resizing events
|
||||||
|
write.i(data.length);
|
||||||
|
write.b(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(Reads read, byte revision){
|
||||||
|
super.read(read, revision);
|
||||||
|
|
||||||
|
int len = read.i();
|
||||||
|
if(data.length == len){
|
||||||
|
read.b(data);
|
||||||
|
}else{
|
||||||
|
read.skip(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,7 +87,7 @@ public class MessageBlock extends Block{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildConfiguration(Table table){
|
public void buildConfiguration(Table table){
|
||||||
table.button(Icon.pencil, () -> {
|
table.button(Icon.pencil, Styles.clearTransi, () -> {
|
||||||
if(mobile){
|
if(mobile){
|
||||||
Core.input.getTextInput(new TextInput(){{
|
Core.input.getTextInput(new TextInput(){{
|
||||||
text = message.toString();
|
text = message.toString();
|
||||||
|
|||||||
Reference in New Issue
Block a user