diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index a75b0758ea..5f96f00764 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -312,6 +312,28 @@ public class BlockIndexer{ return null; } + /** Find the closest ore block relative to a position. */ + public Tile findClosestOre(Unit unit, Item item){ + if(!(unit instanceof Minerc miner)) return null; + + TileArray arr = getOrePositions(item); + + arr.tiles.sort(t -> t.dst2(unit.x, unit.y)); + + for(Tile tile : arr.tiles){ + for(int x = Math.max(0, tile.x - quadrantSize / 2); x < tile.x + quadrantSize / 2 && x < world.width(); x++){ + for(int y = Math.max(0, tile.y - quadrantSize / 2); y < tile.y + quadrantSize / 2 && y < world.height(); y++){ + Tile res = world.tile(x, y); + if(res.drop() == item && miner.validMine(res, false)){ + return res; + } + } + } + } + + return null; + } + /** @return extra unit cap of a team. This is added onto the base value. */ public int getExtraUnits(Team team){ return unitCaps[team.id]; @@ -457,8 +479,8 @@ public class BlockIndexer{ } public static class TileArray implements Iterable{ - private Seq tiles = new Seq<>(false, 16); - private IntSet contained = new IntSet(); + Seq tiles = new Seq<>(false, 16); + IntSet contained = new IntSet(); public void add(Tile tile){ if(contained.add(tile.pos())){ diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java index 64763ac238..da86af9f59 100644 --- a/core/src/mindustry/ai/types/LogicAI.java +++ b/core/src/mindustry/ai/types/LogicAI.java @@ -44,8 +44,8 @@ public class LogicAI extends AIController{ @Override protected void updateMovement(){ - if(itemTimer > 0) itemTimer -= Time.delta; - if(payTimer > 0) payTimer -= Time.delta; + if(itemTimer >= 0) itemTimer -= Time.delta; + if(payTimer >= 0) payTimer -= Time.delta; if(targetTimer > 0f){ targetTimer -= Time.delta; diff --git a/core/src/mindustry/ai/types/MinerAI.java b/core/src/mindustry/ai/types/MinerAI.java index aa7d1403c5..1fae62c251 100644 --- a/core/src/mindustry/ai/types/MinerAI.java +++ b/core/src/mindustry/ai/types/MinerAI.java @@ -39,8 +39,8 @@ public class MinerAI extends AIController{ if(unit.stack.amount >= unit.type.itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){ mining = false; }else{ - if(retarget() && targetItem != null){ - ore = indexer.findClosestOre(unit.x, unit.y, targetItem); + if(timer.get(timerTarget, 60) && targetItem != null){ + ore = indexer.findClosestOre(unit, targetItem); } if(ore != null){ diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java index e516bab740..5b85810141 100644 --- a/core/src/mindustry/content/SectorPresets.java +++ b/core/src/mindustry/content/SectorPresets.java @@ -17,6 +17,7 @@ public class SectorPresets implements ContentList{ groundZero = new SectorPreset("groundZero", serpulo, 15){{ alwaysUnlocked = true; + addStartingItems = true; captureWave = 10; difficulty = 1; }}; diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 4e01a36734..8a892a3627 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -264,7 +264,6 @@ public class Control implements ApplicationListener, Loadable{ slot.load(); slot.setAutosave(true); state.rules.sector = sector; - state.secinfo = state.rules.sector.info; //if there is no base, simulate a new game and place the right loadout at the spawn position if(state.rules.defaultTeam.cores().isEmpty()){ @@ -282,6 +281,9 @@ public class Control implements ApplicationListener, Loadable{ //reset wave so things are more fair state.wave = 1; + //reset win wave?? + state.rules.winWave = sector.preset != null ? sector.preset.captureWave : 40; + //kill all units, since they should be dead anwyay Groups.unit.clear(); Groups.fire.clear(); @@ -312,8 +314,8 @@ public class Control implements ApplicationListener, Loadable{ world.loadSector(sector); state.rules.sector = sector; //assign origin when launching - state.secinfo.origin = origin; - state.secinfo.destination = origin; + sector.info.origin = origin; + sector.info.destination = origin; logic.play(); control.saves.saveSector(sector); Events.fire(Trigger.newGame); diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index 41f14074c8..219e4acfb9 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -26,8 +26,6 @@ public class GameState{ public GameStats stats = new GameStats(); /** Global attributes of the environment, calculated by weather. */ public Attributes envAttrs = new Attributes(); - /** Sector information. Only valid in the campaign. */ - public SectorInfo secinfo = new SectorInfo(); /** Team data. Gets reset every new game. */ public Teams teams = new Teams(); /** Number of enemies in the game; only used clientside in servers. */ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index b8d736126b..f033c1e650 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -55,15 +55,14 @@ public class Logic implements ApplicationListener{ } }); - Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack)); - //when loading a 'damaged' sector, propagate the damage Events.on(SaveLoadEvent.class, e -> { if(state.isCampaign()){ - state.secinfo.write(); + SectorInfo info = state.rules.sector.info; + info.write(); //how much wave time has passed - int wavesPassed = state.secinfo.wavesPassed; + int wavesPassed = info.wavesPassed; //wave has passed, remove all enemies, they are assumed to be dead if(wavesPassed > 0){ @@ -84,10 +83,10 @@ public class Logic implements ApplicationListener{ } //reset values - state.secinfo.damage = 0f; - state.secinfo.wavesPassed = 0; - state.secinfo.hasCore = true; - state.secinfo.secondsPassed = 0; + info.damage = 0f; + info.wavesPassed = 0; + info.hasCore = true; + info.secondsPassed = 0; state.rules.sector.saveInfo(); } @@ -273,7 +272,7 @@ public class Logic implements ApplicationListener{ state.teams.updateTeamStats(); if(state.isCampaign()){ - state.secinfo.update(); + state.rules.sector.info.update(); } if(state.isCampaign()){ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 60beec266b..3640307c2b 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -331,6 +331,7 @@ public class World{ state.rules.weather.add(new WeatherEntry(Weathers.sporestorm)); } + Log.info("saving resources as @ -> @ / @", sector.info.resources, content.asArray(), sector.info.hashCode()); sector.info.resources = content.asArray(); sector.info.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id))); sector.saveInfo(); diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java index 764e6ed4d3..e9c4208e1e 100644 --- a/core/src/mindustry/entities/comp/MinerComp.java +++ b/core/src/mindustry/entities/comp/MinerComp.java @@ -32,12 +32,16 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ } boolean mining(){ - return mineTile != null && !(((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding()); + return mineTile != null && !(((Object)this) instanceof Builderc b && b.activelyBuilding()); + } + + public boolean validMine(Tile tile, boolean checkDst){ + return !(tile == null || tile.block() != Blocks.air || (!within(tile.worldx(), tile.worldy(), miningRange) && checkDst) + || tile.drop() == null || !canMine(tile.drop())) && state.teams.canMine(self(), tile); } public boolean validMine(Tile tile){ - return !(tile == null || tile.block() != Blocks.air || !within(tile.worldx(), tile.worldy(), miningRange) - || tile.drop() == null || !canMine(tile.drop())); + return validMine(tile, true); } @Override @@ -58,6 +62,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ mineTile = null; mineTimer = 0f; }else if(mining()){ + state.teams.registerMined(mineTile, self()); Item item = mineTile.drop(); lookAt(angleTo(mineTile.worldx(), mineTile.worldy())); mineTimer += Time.delta *type.mineSpeed; @@ -84,8 +89,6 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{ mineTimer = 0f; } } - - } } diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index ca005fe25d..5df9db4a60 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -160,7 +160,7 @@ public class AIController implements UnitController{ } protected boolean retarget(){ - return timer.get(timerTarget, 30); + return timer.get(timerTarget, 40); } protected Teamc findTarget(float x, float y, float range, boolean air, boolean ground){ diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java index 3b2b4df3dd..3ef6946424 100644 --- a/core/src/mindustry/game/SectorInfo.java +++ b/core/src/mindustry/game/SectorInfo.java @@ -156,7 +156,6 @@ public class SectorInfo{ damage = 0; if(state.rules.sector != null){ - state.rules.sector.info = this; state.rules.sector.saveInfo(); } diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 6a2972f074..fd2d3f441c 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -11,6 +11,7 @@ import mindustry.content.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.type.*; +import mindustry.world.*; import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.storage.CoreBlock.*; @@ -26,6 +27,8 @@ public class Teams{ public Seq active = new Seq<>(); /** Teams with block or unit presence. */ public Seq present = new Seq<>(TeamData.class); + /** Ores currently being mined. */ + private IntMap mined = new IntMap<>(); public Teams(){ active.add(get(Team.crux)); @@ -142,7 +145,20 @@ public class Teams{ } } + /** @return whether this ore is taken. */ + public boolean canMine(Unit unit, Tile tile){ + if(tile == null) return false; + Unit u = mined.get(tile.pos()); + return u == unit || u == null; + } + + public void registerMined(Tile tile, Unit unit){ + if(tile == null || unit == null) return; + mined.put(tile.pos(), unit); + } + public void updateTeamStats(){ + mined.clear(); present.clear(); for(Team team : Team.all){ diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 8d2c376e94..5db56db2fe 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -945,10 +945,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ boolean canMine(Tile tile){ return !Core.scene.hasMouse() - && tile.drop() != null && player.miner().canMine(tile.drop()) + && tile.drop() != null + && player.miner().validMine(tile) && !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null) && player.unit().acceptsItem(tile.drop()) - && tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= miningRange; + && tile.block() == Blocks.air; } /** Returns the tile at the specified MOUSE coordinates. */ diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index b76a5156e8..a1e26c9b57 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -72,7 +72,7 @@ public abstract class SaveVersion extends SaveFileReader{ public void writeMeta(DataOutput stream, StringMap tags) throws IOException{ //prepare campaign data for writing if(state.isCampaign()){ - state.secinfo.prepare(); + state.rules.sector.info.prepare(); state.rules.sector.saveInfo(); } @@ -110,11 +110,6 @@ public abstract class SaveVersion extends SaveFileReader{ if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); lastReadBuild = map.getInt("build", -1); - //load in sector info - if(state.rules.sector != null){ - state.secinfo = state.rules.sector.info; - } - if(!headless){ Tmp.v1.tryFromString(map.get("viewpos")); Core.camera.position.set(Tmp.v1); diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index 88725da53b..c631103314 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -246,7 +246,7 @@ public class LExecutor{ switch(locate){ case ore -> { if(exec.obj(ore) instanceof Item item){ - res = indexer.findClosestOre(unit.x, unit.y, item); + res = indexer.findClosestOre(unit, item); } } case building -> { @@ -466,9 +466,8 @@ public class LExecutor{ if(ai.itemTimer > 0) return; Building build = exec.building(p1); - int amount = exec.numi(p2); - int dropped = Math.min(unit.stack.amount, amount); - if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange)){ + int dropped = Math.min(unit.stack.amount, exec.numi(p2)); + if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ int accepted = build.acceptStack(unit.item(), dropped, unit); if(accepted > 0){ Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build); @@ -482,7 +481,7 @@ public class LExecutor{ Building build = exec.building(p1); int amount = exec.numi(p3); - if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){ + if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){ int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item))); if(taken > 0){ diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java index eaa42a8293..d4329515e0 100644 --- a/core/src/mindustry/maps/SectorDamage.java +++ b/core/src/mindustry/maps/SectorDamage.java @@ -82,13 +82,13 @@ public class SectorDamage{ /** Applies wave damage based on sector parameters. */ public static void applyCalculatedDamage(){ //calculate base damage fraction - float damage = getDamage(state.secinfo); + float damage = getDamage(state.rules.sector.info); //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier) float scaled = Mathf.pow(damage, 1.5f); //apply damage to units - float unitDamage = damage * state.secinfo.sumHealth; + float unitDamage = damage * state.rules.sector.info.sumHealth; Tile spawn = spawner.getFirstSpawn(); //damage only units near the spawn point @@ -114,7 +114,7 @@ public class SectorDamage{ } } - if(state.secinfo.wavesPassed > 0){ + if(state.rules.sector.info.wavesPassed > 0){ //simply remove each block in the spawner range if a wave passed for(Tile spawner : spawner.getSpawns()){ spawner.circle((int)(state.rules.dropZoneRadius / tilesize), tile -> { diff --git a/core/src/mindustry/maps/generators/FileMapGenerator.java b/core/src/mindustry/maps/generators/FileMapGenerator.java index dab00370ed..ebebd03877 100644 --- a/core/src/mindustry/maps/generators/FileMapGenerator.java +++ b/core/src/mindustry/maps/generators/FileMapGenerator.java @@ -14,9 +14,11 @@ import static mindustry.Vars.*; public class FileMapGenerator implements WorldGenerator{ public final Map map; + public final SectorPreset preset; - public FileMapGenerator(String mapName){ + public FileMapGenerator(String mapName, SectorPreset preset){ this.map = maps != null ? maps.loadInternalMap(mapName) : null; + this.preset = preset; } @Override @@ -56,6 +58,10 @@ public class FileMapGenerator implements WorldGenerator{ if(tile.isCenter() && tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam && !anyCores){ Schematics.placeLaunchLoadout(tile.x, tile.y); anyCores = true; + + if(preset.addStartingItems){ + tile.build.items.add(state.rules.loadout); + } } } diff --git a/core/src/mindustry/type/SectorPreset.java b/core/src/mindustry/type/SectorPreset.java index 0e9b90fb30..05574610fd 100644 --- a/core/src/mindustry/type/SectorPreset.java +++ b/core/src/mindustry/type/SectorPreset.java @@ -17,10 +17,11 @@ public class SectorPreset extends UnlockableContent{ public Cons rules = rules -> rules.winWave = captureWave; /** Difficulty, 0-10. */ public float difficulty; + public boolean addStartingItems = false; public SectorPreset(String name, Planet planet, int sector){ super(name); - this.generator = new FileMapGenerator(name); + this.generator = new FileMapGenerator(name, this); this.planet = planet; sector %= planet.sectors.size; this.sector = planet.sectors.get(sector); diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 9ba80ba2a7..ad1d4ec538 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -49,6 +49,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ shouldPause = true; + addCloseListener(); + buttons.defaults().size(200f, 56f).pad(2); buttons.button("@back", Icon.left, this::hide); buttons.button("@techtree", Icon.tree, () -> ui.research.show()); @@ -380,6 +382,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ stable.row(); } + Log.info("sector resources = @ / @", sector.info.resources, sector.info.hashCode()); + if(sector.save != null && sector.info.resources.any()){ stable.add("@sectors.resources").row(); stable.table(t -> { diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index d51c83881d..a74d3691c1 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -368,9 +368,9 @@ public class HudFragment extends Fragment{ c.clearChildren(); for(Item item : content.items()){ - if(state.secinfo.getExport(item) >= 1){ + if(state.rules.sector != null && state.rules.sector.info.getExport(item) >= 1){ c.image(item.icon(Cicon.small)); - c.label(() -> (int)state.secinfo.getExport(item) + " /s").color(Color.lightGray); + c.label(() -> (int)state.rules.sector.info.getExport(item) + " /s").color(Color.lightGray); c.row(); } } @@ -379,7 +379,7 @@ public class HudFragment extends Fragment{ c.update(() -> { boolean wrong = false; for(Item item : content.items()){ - boolean has = state.secinfo.getExport(item) >= 1; + boolean has = state.rules.sector != null && state.rules.sector.info.getExport(item) >= 1; if(used.get(item.id) != has){ used.set(item.id, has); wrong = true; @@ -389,7 +389,7 @@ public class HudFragment extends Fragment{ rebuild.run(); } }); - }).visible(() -> state.isCampaign() && content.items().contains(i -> state.secinfo.getExport(i) > 0)); + }).visible(() -> state.isCampaign() && content.items().contains(i -> state.rules.sector != null && state.rules.sector.info.getExport(i) > 0)); }); blockfrag.build(parent); diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 98409e6d18..70e6bb653b 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -126,7 +126,6 @@ public class Build{ for(int dy = 0; dy < type.size; dy++){ int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y; - Tile check = world.tile(wx, wy); if( @@ -136,6 +135,10 @@ public class Build{ !check.interactable(team) || //cannot interact !check.floor().placeableOn || //solid wall !((type.canReplace(check.block()) || //can replace type + //controversial change: allow rebuilding damaged blocks + //this could be buggy and abusable, so I'm not enabling it yet + //note that this requires a change in BuilderComp as well + //(type == check.block() && check.centerX() == x && check.centerY() == y && check.build != null && check.build.health < check.build.maxHealth - 0.0001f) || (check.block instanceof ConstructBlock && check.bc().cblock == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement (type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found diff --git a/core/src/mindustry/world/blocks/campaign/LaunchPad.java b/core/src/mindustry/world/blocks/campaign/LaunchPad.java index ff069acc48..5a05768f26 100644 --- a/core/src/mindustry/world/blocks/campaign/LaunchPad.java +++ b/core/src/mindustry/world/blocks/campaign/LaunchPad.java @@ -119,7 +119,7 @@ public class LaunchPad extends Block{ table.row(); table.label(() -> { - Sector dest = state.secinfo.getRealDestination(); + Sector dest = state.rules.sector == null ? null : state.rules.sector.info.getRealDestination(); return Core.bundle.format("launch.destination", dest == null ? Core.bundle.get("sectors.nonelaunch") : @@ -135,7 +135,11 @@ public class LaunchPad extends Block{ } table.button(Icon.upOpen, Styles.clearTransi, () -> { - ui.planet.showSelect(state.rules.sector, other -> state.secinfo.destination = other); + ui.planet.showSelect(state.rules.sector, other -> { + if(state.isCampaign()){ + state.rules.sector.info.destination = other; + } + }); deselect(); }).size(40f); } @@ -208,7 +212,7 @@ public class LaunchPad extends Block{ public void remove(){ if(!state.isCampaign()) return; - Sector destsec = state.secinfo.getRealDestination(); + Sector destsec = state.rules.sector.info.getRealDestination(); //actually launch the items upon removal if(team() == state.rules.defaultTeam){ @@ -219,7 +223,7 @@ public class LaunchPad extends Block{ dest.add(stack); //update export - state.secinfo.handleItemExport(stack); + state.rules.sector.info.handleItemExport(stack); Events.fire(new LaunchItemEvent(stack)); } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 039c7cc3cf..9ed4285070 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -339,15 +339,15 @@ public class CoreBlock extends StorageBlock{ public void itemTaken(Item item){ if(state.isCampaign() && team == state.rules.defaultTeam){ //update item taken amount - state.secinfo.handleCoreItem(item, -1); + state.rules.sector.info.handleCoreItem(item, -1); } } @Override public void handleItem(Building source, Item item){ if(net.server() || !net.active()){ - if(team == state.rules.defaultTeam){ - state.secinfo.handleCoreItem(item, 1); + if(team == state.rules.defaultTeam && state.isCampaign()){ + state.rules.sector.info.handleCoreItem(item, 1); } if(items.get(item) >= getMaximumAccepted(item)){