Campaign mechanics

This commit is contained in:
Anuken
2020-07-06 21:53:34 -04:00
parent a6523630bf
commit 56ffe5aea8
22 changed files with 196 additions and 54 deletions
@@ -0,0 +1 @@
{version:2,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
@@ -0,0 +1 @@
{version:3,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
@@ -0,0 +1 @@
{version:2,fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
@@ -0,0 +1 @@
{version:3,fields:[{name:color,type:arc.graphics.Color,size:-1},{name:data,type:java.lang.Object,size:-1},{name:effect,type:mindustry.entities.Effect,size:-1},{name:lifetime,type:float,size:4},{name:offsetX,type:float,size:4},{name:offsetY,type:float,size:4},{name:parent,type:mindustry.gen.Posc,size:-1},{name:rotation,type:float,size:4},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 B

+3 -3
View File
@@ -78,8 +78,8 @@ public class Vars implements Loadable{
public static final float miningRange = 70f; public static final float miningRange = 70f;
/** range for building */ /** range for building */
public static final float buildingRange = 220f; public static final float buildingRange = 220f;
/** duration of time between events in ticks */ /** duration of time between turns in ticks */
public static final float eventRate = 5 * Time.toMinutes; public static final float turnDuration = 20 * Time.toMinutes;
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */ /** min armor fraction damage; e.g. 0.05 = at least 5% damage */
public static final float minArmorDamage = 0.05f; public static final float minArmorDamage = 0.05f;
/** launch animation duration */ /** launch animation duration */
@@ -287,7 +287,7 @@ public class Vars implements Loadable{
logBuffer.add(result); logBuffer.add(result);
}else if(!headless){ }else if(!headless){
if(!OS.isWindows){ if(!OS.isWindows){
for(String code : ColorCodes.codes.values()){ for(String code : ColorCodes.values){
result = result.replace(code, ""); result = result.replace(code, "");
} }
} }
+1 -1
View File
@@ -534,7 +534,7 @@ public class UnitTypes implements ContentList{
isCounted = false; isCounted = false;
flying = true; flying = true;
mineSpeed = 2f; mineSpeed = 12f;
mineTier = 1; mineTier = 1;
buildSpeed = 0.5f; buildSpeed = 0.5f;
drag = 0.05f; drag = 0.05f;
+1 -1
View File
@@ -507,7 +507,7 @@ public class Control implements ApplicationListener, Loadable{
platform.updateRPC(); platform.updateRPC();
} }
if(Core.input.keyTap(Binding.pause) && !scene.hasDialog() && !scene.hasKeyboard() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){ if(Core.input.keyTap(Binding.pause) && !state.isOutOfTime() && !scene.hasDialog() && !scene.hasKeyboard() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){
state.set(state.is(State.playing) ? State.paused : State.playing); state.set(state.is(State.playing) ? State.paused : State.playing);
} }
+5
View File
@@ -47,6 +47,11 @@ public class GameState{
return rules.sector != null; return rules.sector != null;
} }
/** @return whether the player is in a campaign and they are out of sector time */
public boolean isOutOfTime(){
return isCampaign() && isGame() && getSector().getTimeSpent() >= turnDuration;
}
public boolean hasSector(){ public boolean hasSector(){
return rules.sector != null; return rules.sector != null;
} }
+7 -2
View File
@@ -120,7 +120,7 @@ public class Logic implements ApplicationListener{
} }
} }
state.rules.sector.setLastSecond(universe.seconds()); state.rules.sector.setSecondsPassed(0);
} }
//enable infinite ammo for wave team by default //enable infinite ammo for wave team by default
@@ -281,7 +281,7 @@ public class Logic implements ApplicationListener{
sector.save.save(); sector.save.save();
//run a turn, since launching takes up a turn //run a turn, since launching takes up a turn
universe.runEvents(); universe.runTurn();
//TODO apply extra damage to sector //TODO apply extra damage to sector
//sector.setTurnsPassed(sector.getTurnsPassed() + 3); //sector.setTurnsPassed(sector.getTurnsPassed() + 3);
@@ -316,6 +316,11 @@ public class Logic implements ApplicationListener{
state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted); state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted);
} }
//force pausing when the player is out of sector time
if(state.isOutOfTime()){
state.set(State.paused);
}
if(!state.isPaused()){ if(!state.isPaused()){
state.secinfo.update(); state.secinfo.update();
+9
View File
@@ -467,6 +467,15 @@ public class UI implements ApplicationListener, Loadable{
dialog.show(); dialog.show();
} }
public void announce(String text){
Table t = new Table();
t.background(Styles.black3).margin(8f)
.add(text).style(Styles.outlineLabel);
t.update(() -> t.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Align.center));
t.actions(Actions.fadeOut(3, Interp.pow4In));
Core.scene.add(t);
}
public void showOkText(String title, String text, Runnable confirmed){ public void showOkText(String title, String text, Runnable confirmed){
BaseDialog dialog = new BaseDialog(title); BaseDialog dialog = new BaseDialog(title);
dialog.cont.add(text).width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center); dialog.cont.add(text).width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
+1
View File
@@ -45,6 +45,7 @@ public class EventType{
public static class PlayEvent{} public static class PlayEvent{}
public static class ResetEvent{} public static class ResetEvent{}
public static class WaveEvent{} public static class WaveEvent{}
public static class TurnEvent{}
/** Called when the player places a line, mobile or desktop.*/ /** Called when the player places a line, mobile or desktop.*/
public static class LineConfirmEvent{} public static class LineConfirmEvent{}
/** Called when a turret recieves ammo, but only when the tutorial is active! */ /** Called when a turret recieves ammo, but only when the tutorial is active! */
+13
View File
@@ -17,6 +17,7 @@ public class SectorInfo{
private static final int valueWindow = 60; private static final int valueWindow = 60;
/** refresh period of export in ticks */ /** refresh period of export in ticks */
private static final float refreshPeriod = 60; private static final float refreshPeriod = 60;
/** Core input statistics. */ /** Core input statistics. */
public ObjectMap<Item, ExportStat> production = new ObjectMap<>(); public ObjectMap<Item, ExportStat> production = new ObjectMap<>();
/** Export statistics. */ /** Export statistics. */
@@ -31,6 +32,8 @@ public class SectorInfo{
public boolean hasCore = true; public boolean hasCore = true;
/** Sector that was launched from. */ /** Sector that was launched from. */
public @Nullable Sector origin; public @Nullable Sector origin;
/** Time spent at this sector. Do not use unless you know what you're doing. */
public transient float internalTimeSpent;
/** Counter refresh state. */ /** Counter refresh state. */
private transient Interval time = new Interval(); private transient Interval time = new Interval();
@@ -73,11 +76,21 @@ public class SectorInfo{
hasCore = entity != null; hasCore = entity != null;
bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block; bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block;
storageCapacity = entity != null ? entity.storageCapacity : 0; storageCapacity = entity != null ? entity.storageCapacity : 0;
//update sector's internal time spent counter1
state.rules.sector.setTimeSpent(internalTimeSpent);
} }
/** Update averages of various stats. /** Update averages of various stats.
* Called every frame. */ * Called every frame. */
public void update(){ public void update(){
internalTimeSpent += Time.delta();
//time spent exceeds turn duration!
if(internalTimeSpent >= turnDuration && internalTimeSpent - Time.delta() < turnDuration){
universe.displayTimeEnd();
}
//create last stored core items //create last stored core items
if(lastCoreItems == null){ if(lastCoreItems == null){
lastCoreItems = new int[content.items().size]; lastCoreItems = new int[content.items().size];
+40 -16
View File
@@ -5,6 +5,8 @@ import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.core.GameState.*;
import mindustry.game.EventType.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.blocks.storage.*; import mindustry.world.blocks.storage.*;
@@ -14,8 +16,7 @@ import static mindustry.Vars.*;
public class Universe{ public class Universe{
private long seconds; private long seconds;
private float secondCounter; private float secondCounter;
private int event; private int turn;
private float eventCounter;
private Schematic lastLoadout; private Schematic lastLoadout;
private Seq<ItemStack> lastLaunchResources = new Seq<>(); private Seq<ItemStack> lastLaunchResources = new Seq<>();
@@ -30,6 +31,10 @@ public class Universe{
updatePlanet(Planets.sun); updatePlanet(Planets.sun);
} }
public int turn(){
return turn;
}
private void updatePlanet(Planet planet){ private void updatePlanet(Planet planet){
planet.position.setZero(); planet.position.setZero();
planet.addParentOffset(planet.position); planet.addParentOffset(planet.position);
@@ -41,6 +46,14 @@ public class Universe{
} }
} }
public void displayTimeEnd(){
if(!headless){
state.set(State.paused);
ui.announce("Next turn incoming.");
}
}
/** Update planet rotations, global time and relevant state. */ /** Update planet rotations, global time and relevant state. */
public void update(){ public void update(){
secondCounter += Time.delta() / 60f; secondCounter += Time.delta() / 60f;
@@ -55,13 +68,6 @@ public class Universe{
} }
} }
//update event counter - happens only in-game
eventCounter += Time.delta();
if(eventCounter >= eventRate){
runEvents();
}
if(state.hasSector()){ if(state.hasSector()){
//update sector light //update sector light
float light = state.getSector().getLight(); float light = state.getSector().getLight();
@@ -110,11 +116,31 @@ public class Universe{
} }
/** Runs possible events. Resets event counter. */ /** Runs possible events. Resets event counter. */
public void runEvents(){ public void runTurn(){
event++; turn++;
eventCounter = 0;
int newSecondsPassed = (int)(turnDuration / 60);
//update relevant sectors
for(Planet planet : content.planets()){
for(Sector sector : planet.sectors){
if(sector.hasSave()){
int spent = (int)(sector.getTimeSpent() / 60);
int actuallyPassed = Math.max(newSecondsPassed - spent, 0);
//increment seconds passed for this sector by the time that just passed with this turn
if(!sector.isBeingPlayed()){
sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
}
//reset time spent to 0
sector.setTimeSpent(0f);
}
}
}
//TODO events //TODO events
Events.fire(new TurnEvent());
} }
public float secondsMod(float mod, float scale){ public float secondsMod(float mod, float scale){
@@ -131,14 +157,12 @@ public class Universe{
private void save(){ private void save(){
Core.settings.put("utime", seconds); Core.settings.put("utime", seconds);
Core.settings.put("event", event); Core.settings.put("turn", turn);
Core.settings.put("eventtime", eventCounter);
} }
private void load(){ private void load(){
seconds = Core.settings.getLong("utime"); seconds = Core.settings.getLong("utime");
event = Core.settings.getInt("event"); turn = Core.settings.getInt("turn");
eventCounter = Core.settings.getFloat("eventtime");
} }
} }
+5
View File
@@ -113,6 +113,11 @@ public abstract class SaveVersion extends SaveFileReader{
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
lastReadBuild = map.getInt("build", -1); lastReadBuild = map.getInt("build", -1);
//load time spent on sector into state
if(state.rules.sector != null){
state.secinfo.internalTimeSpent = state.rules.sector.getStoredTimeSpent();
}
if(!headless){ if(!headless){
Tmp.v1.tryFromString(map.get("viewpos")); Tmp.v1.tryFromString(map.get("viewpos"));
Core.camera.position.set(Tmp.v1); Core.camera.position.set(Tmp.v1);
+33 -3
View File
@@ -131,12 +131,42 @@ public class Sector{
return Core.settings.getInt(key("spawn-position"), Point2.pack(world.width() / 2, world.height() / 2)); return Core.settings.getInt(key("spawn-position"), Point2.pack(world.width() / 2, world.height() / 2));
} }
public void setLastSecond(long number){ /** @return time spent in this sector this turn in ticks. */
put("last-second", number); public float getTimeSpent(){
//return currently counting time spent if being played on
if(isBeingPlayed()) return state.secinfo.internalTimeSpent;
//else return the stored value
return getStoredTimeSpent();
}
public void setTimeSpent(float time){
put("time-spent", time);
//update counting time
if(isBeingPlayed()){
state.secinfo.internalTimeSpent = time;
}
}
public String displayTimeRemaining(){
float amount = Vars.turnDuration - getTimeSpent();
int seconds = (int)(amount / 60);
int sf = seconds % 60;
return (seconds / 60) + ":" + (sf < 10 ? "0" : "") + sf;
}
/** @return the stored amount of time spent in this sector this turn in ticks. */
public float getStoredTimeSpent(){
return Core.settings.getFloat(key("time-spent"));
}
public void setSecondsPassed(long number){
put("seconds-passed", number);
} }
public long getSecondsPassed(){ public long getSecondsPassed(){
return universe.seconds() - Core.settings.getLong(key("last-second")); return Core.settings.getLong(key("seconds-passed"));
} }
private String key(String key){ private String key(String key){
+2 -1
View File
@@ -23,7 +23,7 @@ import static mindustry.gen.Tex.*;
@StyleDefaults @StyleDefaults
public class Styles{ public class Styles{
public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver; public static Drawable black, black9, black8, black6, black3, black5, none, flatDown, flatOver;
public static ButtonStyle defaultb, waveb; public static ButtonStyle defaultb, waveb;
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt; public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt;
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
@@ -40,6 +40,7 @@ public class Styles{
black9 = whiteui.tint(0f, 0f, 0f, 0.9f); black9 = whiteui.tint(0f, 0f, 0f, 0.9f);
black8 = whiteui.tint(0f, 0f, 0f, 0.8f); black8 = whiteui.tint(0f, 0f, 0f, 0.8f);
black6 = whiteui.tint(0f, 0f, 0f, 0.6f); black6 = whiteui.tint(0f, 0f, 0f, 0.6f);
black5 = whiteui.tint(0f, 0f, 0f, 0.5f);
black3 = whiteui.tint(0f, 0f, 0f, 0.3f); black3 = whiteui.tint(0f, 0f, 0f, 0.3f);
none = whiteui.tint(0f, 0f, 0f, 0f); none = whiteui.tint(0f, 0f, 0f, 0f);
flatDown = createFlatDown(); flatDown = createFlatDown();
@@ -34,6 +34,12 @@ public class PausedDialog extends BaseDialog{
}); });
if(!mobile){ if(!mobile){
//TODO localize
cont.label(() -> state.getSector() == null ? "" :
"[lightgray]Next turn in [accent]" + state.getSector().displayTimeRemaining())
.visible(() -> state.getSector() != null).colspan(2);
cont.row();
float dw = 220f; float dw = 220f;
cont.defaults().width(dw).height(55).pad(5f); cont.defaults().width(dw).height(55).pad(5f);
@@ -45,7 +51,10 @@ public class PausedDialog extends BaseDialog{
//}else{ //}else{
// cont.button("$database", Icon.book, ui.database::show); // cont.button("$database", Icon.book, ui.database::show);
//} //}
cont.button("placeholder", Icon.warning, () -> ui.showInfo("go away")); //TODO remove
cont.button("launch core", Icon.warning, () -> ui.planet.show(state.getSector(), player.team().core()))
.disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements))
.visible(() -> state.isCampaign());
cont.button("$settings", Icon.settings, ui.settings::show); cont.button("$settings", Icon.settings, ui.settings::show);
if(!state.rules.tutorial){ if(!state.rules.tutorial){
+29 -11
View File
@@ -7,6 +7,7 @@ import arc.graphics.gl.*;
import arc.input.*; import arc.input.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*; import arc.scene.event.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
@@ -197,19 +198,36 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
cont.clear(); cont.clear();
titleTable.remove(); titleTable.remove();
//add listener to the background rect, so it doesn't get unnecessary touch input
cont.rect((x, y, w, h) -> planets.render(this)).grow().get().addListener(new ElementGestureListener(){
@Override
public void tap(InputEvent event, float x, float y, int count, KeyCode button){
if(hovered != null && (mode == launch ? canLaunch(hovered) && hovered != launchSector : hovered.unlocked())){
selected = hovered;
}
if(selected != null){ cont.stack(
updateSelected(); new Element(){
} {
//add listener to the background rect, so it doesn't get unnecessary touch input
addListener(new ElementGestureListener(){
@Override
public void tap(InputEvent event, float x, float y, int count, KeyCode button){
if(hovered != null && (mode == launch ? canLaunch(hovered) && hovered != launchSector : hovered.unlocked())){
selected = hovered;
}
if(selected != null){
updateSelected();
}
}
});
} }
});
@Override
public void draw(){
planets.render(PlanetDialog.this);
}
},
new Table(t -> {
//TODO localize
t.top();
t.label(() -> "Turn " + universe.turn()).style(Styles.outlineLabel).color(Pal.accent);
})).grow();
} }
@Override @Override
@@ -47,6 +47,7 @@ public class HudFragment extends Fragment{
//TODO details and stuff //TODO details and stuff
Events.on(SectorCaptureEvent.class, e ->{ Events.on(SectorCaptureEvent.class, e ->{
//TODO localize
showToast("Sector[accent] captured[]!"); showToast("Sector[accent] captured[]!");
}); });
@@ -55,6 +56,16 @@ public class HudFragment extends Fragment{
coreItems.resetUsed(); coreItems.resetUsed();
}); });
Events.on(TurnEvent.class, e -> {
ui.announce("[accent][[ Turn " + universe.turn() + " ]");
});
//paused table
parent.fill(t -> {
t.top().visible(() -> state.isPaused() && !state.isOutOfTime()).touchable(Touchable.disabled);
t.table(Styles.black5, top -> top.add("$paused").style(Styles.outlineLabel).pad(8f)).growX();
});
//TODO tear this all down //TODO tear this all down
//menu at top left //menu at top left
parent.fill(cont -> { parent.fill(cont -> {
@@ -254,6 +265,27 @@ public class HudFragment extends Fragment{
.update(label -> label.getColor().set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled); .update(label -> label.getColor().set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
}); });
//paused table for when the player is out of time
parent.fill(t -> {
t.top().visible(() -> state.isOutOfTime());
t.table(Styles.black5, top -> {
//TODO localize when done
top.add("Out of sector time.").style(Styles.outlineLabel).color(Pal.accent).update(l -> l.color.a = Mathf.absin(Time.globalTime(), 7f, 1f)).colspan(2);
top.row();
top.defaults().pad(2).size(150f, 54f);
top.button("Next Turn", () -> {
universe.runTurn();
state.set(State.playing);
});
top.button("Back to Planet", () -> {
ui.paused.runExitSave();
ui.planet.show();
});
}).margin(8).growX();
});
//tutorial text //tutorial text
parent.fill(t -> { parent.fill(t -> {
Runnable resize = () -> { Runnable resize = () -> {
@@ -276,12 +308,6 @@ public class HudFragment extends Fragment{
Events.on(ResizeEvent.class, e -> resize.run()); Events.on(ResizeEvent.class, e -> resize.run());
}); });
//paused table
parent.fill(t -> {
t.top().visible(() -> state.isPaused()).touchable(Touchable.disabled);
t.table(Tex.buttonTrans, top -> top.add("$paused").pad(5f));
});
//'saving' indicator //'saving' indicator
parent.fill(t -> { parent.fill(t -> {
t.bottom().visible(() -> control.saves.isSaving()); t.bottom().visible(() -> control.saves.isSaving());
@@ -335,14 +361,6 @@ public class HudFragment extends Fragment{
}).visible(() -> state.isCampaign() && content.items().contains(i -> state.secinfo.getExport(i) > 0)); }).visible(() -> state.isCampaign() && content.items().contains(i -> state.secinfo.getExport(i) > 0));
}); });
//TODO move, select loadout, consume resources
parent.fill(t -> {
t.bottom().visible(() -> state.isCampaign() && player.team().core() != null);
t.button("test launch", Icon.warning, () -> ui.planet.show(state.getSector(), player.team().core()))
.width(150f).disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements)); //disable core when missing resources for launch
});
blockfrag.build(parent); blockfrag.build(parent);
} }
+1 -1
View File
@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=52dc318f51cfca6d9a0f3097760c0fb615977330 archash=6ed1b560047eaaf9ae83176526de51e5a49cadc3