New hint tutorial system (unfinished!)
This commit is contained in:
@@ -46,7 +46,7 @@ public class AssetsProcess extends BaseProcessor{
|
|||||||
String name = Strings.kebabToCamel(split[1]).replace("Medium", "").replace("Icon", "");
|
String name = Strings.kebabToCamel(split[1]).replace("Medium", "").replace("Icon", "");
|
||||||
if(SourceVersion.isKeyword(name) || name.equals("char")) name += "i";
|
if(SourceVersion.isKeyword(name) || name.equals("char")) name += "i";
|
||||||
|
|
||||||
ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("(char)" + key).build());
|
ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).addJavadoc(String.format("\\u%04x", Integer.parseInt(key))).initializer("'" + ((char)Integer.parseInt(key)) + "'").build());
|
||||||
});
|
});
|
||||||
|
|
||||||
ictype.addField(FieldSpec.builder(ParameterizedTypeName.get(ObjectMap.class, String.class, TextureRegionDrawable.class),
|
ictype.addField(FieldSpec.builder(ParameterizedTypeName.get(ObjectMap.class, String.class, TextureRegionDrawable.class),
|
||||||
@@ -64,7 +64,7 @@ public class AssetsProcess extends BaseProcessor{
|
|||||||
|
|
||||||
int code = val.getInt("code", 0);
|
int code = val.getInt("code", 0);
|
||||||
iconcAll.append((char)code);
|
iconcAll.append((char)code);
|
||||||
ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("(char)" + code).build());
|
ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).addJavadoc(String.format("\\u%04x", code)).initializer("'" + ((char)code) + "'").build());
|
||||||
ichinit.addStatement("codes.put($S, $L)", name, code);
|
ichinit.addStatement("codes.put($S, $L)", name, code);
|
||||||
|
|
||||||
ictype.addField(TextureRegionDrawable.class, name + "Small", Modifier.PUBLIC, Modifier.STATIC);
|
ictype.addField(TextureRegionDrawable.class, name + "Small", Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
|||||||
@@ -497,6 +497,7 @@ requirement.produce = Produce {0}
|
|||||||
requirement.capture = Capture {0}
|
requirement.capture = Capture {0}
|
||||||
launch.text = Launch
|
launch.text = Launch
|
||||||
research.multiplayer = Only the host can research items.
|
research.multiplayer = Only the host can research items.
|
||||||
|
map.multiplayer = Only the host can view sectors.
|
||||||
uncover = Uncover
|
uncover = Uncover
|
||||||
configure = Configure Loadout
|
configure = Configure Loadout
|
||||||
|
|
||||||
@@ -1235,6 +1236,30 @@ team.derelict.name = derelict
|
|||||||
team.green.name = green
|
team.green.name = green
|
||||||
team.purple.name = purple
|
team.purple.name = purple
|
||||||
|
|
||||||
|
# DO NOT TRANSLATE ANY OF THESE YET! THEY ARE UNFINISHED!
|
||||||
|
hint.skip = Skip
|
||||||
|
hint.desktopMove = Use [accent][[WASD][] to move.
|
||||||
|
hint.zoom = [accent]Scroll[] to zoom in or out.
|
||||||
|
hint.mine = Move near the \uf8c4 copper ore and [accent]tap[] it to start mining.
|
||||||
|
hint.desktopShoot = [accent][[Left-click][] to shoot.
|
||||||
|
hint.depositItems = To transfer items, drag from your ship to the core.
|
||||||
|
hint.respawn = To respawn as a ship, press [accent][[V][].
|
||||||
|
hint.respawn.mobile = You have switched control a unit/structure. To respawn as a ship, tap the avatar in the top left.
|
||||||
|
hint.desktopPause = Press [accent][[Space][] to pause and unpause the game.
|
||||||
|
hint.placeDrill = Select the \ue85e [accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and click on a copper patch to place it.
|
||||||
|
hint.placeDrill.mobile = Select the \ue85e[accent]Drill[] tab in the menu at the bottom right, then select a \uf870 [accent]Drill[] and tap on a copper patch to place it.\n\nPress the [accent]checkmark[] at the bottom left to confirm.
|
||||||
|
hint.placeConveyor = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nClick and drag to place multiple conveyors.\n[accent]Scroll[] to rotate.
|
||||||
|
hint.placeConveyor.mobile = Conveyors move items from drills into other blocks. Select a \uf896 [accent]Conveyor[] from the \ue814 [accent]Distribution[] tab.\n\nHold down your finger for a second and drag to place multiple conveyors.
|
||||||
|
hint.placeTurret = Place \uf861 [accent]Turrets[] to defend your base from enemies.\n\nTurrets require ammo - in this case, \uf838copper.\nUse conveyors and drills to supply them.
|
||||||
|
hint.breaking = [accent]Right-click[] and drag to break blocks.
|
||||||
|
hint.breaking.mobile = Activate the \ue817 hammer in the bottom left and tap to break blocks.\nHold down your finger for a second and drag to break in a selection.
|
||||||
|
hint.research = Use the \ue875 [accent]Research[] button to research new technology.
|
||||||
|
hint.research.mobile = Use the \ue875 [accent]Research[] button in the \ue88c [accent]Menu[] to research new technology.
|
||||||
|
hint.unitControl = Hold [accent][[L-ctrl][] and [accent]click[] to control friendly units or turrets.
|
||||||
|
hint.unitControl.mobile = [accent][Double-tap[] to control friendly units or turrets.
|
||||||
|
hint.launch = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the bottom left.
|
||||||
|
hint.launch.mobile = Once you collect enough resources, you can [accent]Launch[] by selecting nearby sectors from the \ue827 [accent]Map[] in the \ue88c [accent]Menu[].
|
||||||
|
|
||||||
tutorial.next = [lightgray]<Tap to continue>
|
tutorial.next = [lightgray]<Tap to continue>
|
||||||
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse[accent] [[WASD][] to move.\n[accent]Scroll[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse[accent] [[WASD][] to move.\n[accent]Scroll[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class Vars implements Loadable{
|
|||||||
/** duration of time between turns in ticks */
|
/** duration of time between turns in ticks */
|
||||||
public static final float turnDuration = 2 * Time.toMinutes;
|
public static final float turnDuration = 2 * Time.toMinutes;
|
||||||
/** chance of an invasion per turn, 1 = 100% */
|
/** chance of an invasion per turn, 1 = 100% */
|
||||||
public static final float baseInvasionChance = 1f / 30f;
|
public static final float baseInvasionChance = 1f / 45f;
|
||||||
/** how many turns have to pass before invasions start */
|
/** how many turns have to pass before invasions start */
|
||||||
public static final int invasionGracePeriod = 20;
|
public static final int invasionGracePeriod = 20;
|
||||||
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ public class BuilderAI extends AIController{
|
|||||||
@Override
|
@Override
|
||||||
public void updateMovement(){
|
public void updateMovement(){
|
||||||
|
|
||||||
if(unit.moving()){
|
|
||||||
unit.lookAt(unit.vel.angle());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target != null && shouldShoot()){
|
if(target != null && shouldShoot()){
|
||||||
unit.lookAt(target);
|
unit.lookAt(target);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2059,6 +2059,7 @@ public class Blocks implements ContentList{
|
|||||||
size = 7;
|
size = 7;
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
consumes.power(10f);
|
consumes.power(10f);
|
||||||
|
buildCostMultiplier = 0.5f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion campaign
|
//endregion campaign
|
||||||
|
|||||||
@@ -1250,6 +1250,7 @@ public class UnitTypes implements ContentList{
|
|||||||
defaultController = RepairAI::new;
|
defaultController = RepairAI::new;
|
||||||
|
|
||||||
mineTier = 3;
|
mineTier = 3;
|
||||||
|
mineSpeed = 4f;
|
||||||
health = 500;
|
health = 500;
|
||||||
armor = 5f;
|
armor = 5f;
|
||||||
speed = 2.5f;
|
speed = 2.5f;
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import static mindustry.Vars.*;
|
|||||||
public class Control implements ApplicationListener, Loadable{
|
public class Control implements ApplicationListener, Loadable{
|
||||||
public Saves saves;
|
public Saves saves;
|
||||||
public SoundControl sound;
|
public SoundControl sound;
|
||||||
public Tutorial tutorial;
|
|
||||||
public InputHandler input;
|
public InputHandler input;
|
||||||
|
|
||||||
private Interval timer = new Interval(2);
|
private Interval timer = new Interval(2);
|
||||||
@@ -53,7 +52,6 @@ public class Control implements ApplicationListener, Loadable{
|
|||||||
|
|
||||||
public Control(){
|
public Control(){
|
||||||
saves = new Saves();
|
saves = new Saves();
|
||||||
tutorial = new Tutorial();
|
|
||||||
sound = new SoundControl();
|
sound = new SoundControl();
|
||||||
|
|
||||||
Events.on(StateChangeEvent.class, event -> {
|
Events.on(StateChangeEvent.class, event -> {
|
||||||
@@ -87,7 +85,6 @@ public class Control implements ApplicationListener, Loadable{
|
|||||||
|
|
||||||
Events.on(ResetEvent.class, event -> {
|
Events.on(ResetEvent.class, event -> {
|
||||||
player.reset();
|
player.reset();
|
||||||
tutorial.reset();
|
|
||||||
|
|
||||||
hiscore = false;
|
hiscore = false;
|
||||||
saves.resetSave();
|
saves.resetSave();
|
||||||
@@ -408,13 +405,6 @@ public class Control implements ApplicationListener, Loadable{
|
|||||||
public void init(){
|
public void init(){
|
||||||
platform.updateRPC();
|
platform.updateRPC();
|
||||||
|
|
||||||
//just a regular reminder
|
|
||||||
if(!OS.prop("user.name").equals("anuke") && !OS.hasEnv("iknowwhatimdoing")){
|
|
||||||
app.post(() -> app.post(() -> {
|
|
||||||
ui.showStartupInfo("@indev.popup");
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
//display UI scale changed dialog
|
//display UI scale changed dialog
|
||||||
if(Core.settings.getBool("uiscalechanged", false)){
|
if(Core.settings.getBool("uiscalechanged", false)){
|
||||||
Core.app.post(() -> Core.app.post(() -> {
|
Core.app.post(() -> Core.app.post(() -> {
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ public class Logic implements ApplicationListener{
|
|||||||
Events.fire(new SectorCaptureEvent(state.rules.sector));
|
Events.fire(new SectorCaptureEvent(state.rules.sector));
|
||||||
|
|
||||||
//save, just in case
|
//save, just in case
|
||||||
if(!headless){
|
if(!headless && !net.client()){
|
||||||
control.saves.saveSector(state.rules.sector);
|
control.saves.saveSector(state.rules.sector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
private static final Vec2 vector = new Vec2();
|
private static final Vec2 vector = new Vec2();
|
||||||
private static final Rect viewport = new Rect();
|
private static final Rect viewport = new Rect();
|
||||||
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
||||||
private static final float correctDist = 16f;
|
private static final float correctDist = tilesize * 8f;
|
||||||
|
|
||||||
public final Administration admins = new Administration();
|
public final Administration admins = new Administration();
|
||||||
public final CommandHandler clientCommands = new CommandHandler("/");
|
public final CommandHandler clientCommands = new CommandHandler("/");
|
||||||
@@ -638,12 +638,12 @@ public class NetServer implements ApplicationListener{
|
|||||||
Unit unit = player.unit();
|
Unit unit = player.unit();
|
||||||
|
|
||||||
long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime);
|
long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime);
|
||||||
float maxSpeed = ((player.unit().type.canBoost && player.unit().isFlying()) ? player.unit().type.boostMultiplier : 1f) * player.unit().speed();
|
float maxSpeed = unit.realSpeed();
|
||||||
if(unit.isGrounded()){
|
if(unit.isGrounded()){
|
||||||
maxSpeed *= unit.floorSpeedMultiplier();
|
maxSpeed *= unit.floorSpeedMultiplier();
|
||||||
}
|
}
|
||||||
|
|
||||||
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.2f;
|
||||||
|
|
||||||
//ignore the position if the player thinks they're dead, or the unit is wrong
|
//ignore the position if the player thinks they're dead, or the unit is wrong
|
||||||
boolean ignorePosition = dead || unit.id != unitID;
|
boolean ignorePosition = dead || unit.id != unitID;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
public MinimapFragment minimapfrag;
|
public MinimapFragment minimapfrag;
|
||||||
public PlayerListFragment listfrag;
|
public PlayerListFragment listfrag;
|
||||||
public LoadingFragment loadfrag;
|
public LoadingFragment loadfrag;
|
||||||
|
public HintsFragment hints;
|
||||||
|
|
||||||
public WidgetGroup menuGroup, hudGroup;
|
public WidgetGroup menuGroup, hudGroup;
|
||||||
|
|
||||||
@@ -150,6 +151,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
|
|
||||||
menufrag = new MenuFragment();
|
menufrag = new MenuFragment();
|
||||||
hudfrag = new HudFragment();
|
hudfrag = new HudFragment();
|
||||||
|
hints = new HintsFragment();
|
||||||
chatfrag = new ChatFragment();
|
chatfrag = new ChatFragment();
|
||||||
minimapfrag = new MinimapFragment();
|
minimapfrag = new MinimapFragment();
|
||||||
listfrag = new PlayerListFragment();
|
listfrag = new PlayerListFragment();
|
||||||
@@ -520,7 +522,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
|
|
||||||
//TODO move?
|
//TODO move?
|
||||||
|
|
||||||
public static String formatAmount(long number){
|
public static String formatAmount(int number){
|
||||||
if(number >= 1_000_000_000){
|
if(number >= 1_000_000_000){
|
||||||
return Strings.fixed(number / 1_000_000_000f, 1) + "[gray]" + Core.bundle.get("unit.billions") + "[]";
|
return Strings.fixed(number / 1_000_000_000f, 1) + "[gray]" + Core.bundle.get("unit.billions") + "[]";
|
||||||
}else if(number >= 1_000_000){
|
}else if(number >= 1_000_000){
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
public void dumpLiquid(Liquid liquid){
|
public void dumpLiquid(Liquid liquid){
|
||||||
int dump = this.cdump;
|
int dump = this.cdump;
|
||||||
|
|
||||||
if(!net.client() && state.isCampaign()) liquid.unlock();
|
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
@@ -620,7 +620,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||||||
*/
|
*/
|
||||||
public void offload(Item item){
|
public void offload(Item item){
|
||||||
int dump = this.cdump;
|
int dump = this.cdump;
|
||||||
if(!net.client() && state.isCampaign()) item.unlock();
|
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) item.unlock();
|
||||||
|
|
||||||
for(int i = 0; i < proximity.size; i++){
|
for(int i = 0; i < proximity.size; i++){
|
||||||
incrementDump(proximity.size);
|
incrementDump(proximity.size);
|
||||||
|
|||||||
@@ -1,308 +0,0 @@
|
|||||||
package mindustry.game;
|
|
||||||
|
|
||||||
import arc.*;
|
|
||||||
import arc.func.*;
|
|
||||||
import arc.graphics.g2d.*;
|
|
||||||
import arc.math.*;
|
|
||||||
import arc.scene.*;
|
|
||||||
import arc.scene.ui.*;
|
|
||||||
import arc.scene.ui.layout.*;
|
|
||||||
import arc.struct.*;
|
|
||||||
import arc.util.*;
|
|
||||||
import mindustry.content.*;
|
|
||||||
import mindustry.game.EventType.*;
|
|
||||||
import mindustry.gen.*;
|
|
||||||
import mindustry.graphics.*;
|
|
||||||
import mindustry.type.*;
|
|
||||||
import mindustry.world.*;
|
|
||||||
|
|
||||||
import static mindustry.Vars.*;
|
|
||||||
|
|
||||||
/** Handles tutorial state. */
|
|
||||||
public class Tutorial{
|
|
||||||
private static final int mineCopper = 18;
|
|
||||||
private static final int blocksToBreak = 3, blockOffset = -6;
|
|
||||||
|
|
||||||
ObjectSet<String> events = new ObjectSet<>();
|
|
||||||
ObjectIntMap<Block> blocksPlaced = new ObjectIntMap<>();
|
|
||||||
int sentence;
|
|
||||||
public TutorialStage stage = TutorialStage.values()[0];
|
|
||||||
|
|
||||||
public Tutorial(){
|
|
||||||
Events.on(BlockBuildEndEvent.class, event -> {
|
|
||||||
if(!event.breaking){
|
|
||||||
blocksPlaced.increment(event.tile.block(), 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Events.on(LineConfirmEvent.class, event -> events.add("lineconfirm"));
|
|
||||||
Events.on(TurretAmmoDeliverEvent.class, event -> events.add("ammo"));
|
|
||||||
Events.on(CoreItemDeliverEvent.class, event -> events.add("coreitem"));
|
|
||||||
Events.on(BlockInfoEvent.class, event -> events.add("blockinfo"));
|
|
||||||
Events.on(DepositEvent.class, event -> events.add("deposit"));
|
|
||||||
Events.on(WithdrawEvent.class, event -> events.add("withdraw"));
|
|
||||||
|
|
||||||
Events.on(ClientLoadEvent.class, e -> {
|
|
||||||
for(TutorialStage stage : TutorialStage.values()){
|
|
||||||
stage.load();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/** update tutorial state, transition if needed */
|
|
||||||
public void update(){
|
|
||||||
if(stage.done.get() && !canNext()){
|
|
||||||
next();
|
|
||||||
}else{
|
|
||||||
stage.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** draw UI overlay */
|
|
||||||
public void draw(){
|
|
||||||
if(!Core.scene.hasDialog()){
|
|
||||||
stage.draw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resets tutorial state. */
|
|
||||||
public void reset(){
|
|
||||||
stage = TutorialStage.values()[0];
|
|
||||||
stage.begin();
|
|
||||||
blocksPlaced.clear();
|
|
||||||
events.clear();
|
|
||||||
sentence = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Goes on to the next tutorial step. */
|
|
||||||
public void next(){
|
|
||||||
stage = TutorialStage.values()[Mathf.clamp(stage.ordinal() + 1, 0, TutorialStage.values().length)];
|
|
||||||
stage.begin();
|
|
||||||
blocksPlaced.clear();
|
|
||||||
events.clear();
|
|
||||||
sentence = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canNext(){
|
|
||||||
return sentence + 1 < stage.sentences.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void nextSentence(){
|
|
||||||
if(canNext()){
|
|
||||||
sentence ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canPrev(){
|
|
||||||
return sentence > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void prevSentence(){
|
|
||||||
if(canPrev()){
|
|
||||||
sentence --;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TutorialStage{
|
|
||||||
intro(
|
|
||||||
line -> Core.bundle.format(line, item(Items.copper), mineCopper),
|
|
||||||
() -> item(Items.copper) >= mineCopper
|
|
||||||
),
|
|
||||||
drill(() -> placed(Blocks.mechanicalDrill, 1)){
|
|
||||||
void draw(){
|
|
||||||
outline("category-production");
|
|
||||||
outline("block-mechanical-drill");
|
|
||||||
outline("confirmplace");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
blockinfo(() -> event("blockinfo")){
|
|
||||||
void draw(){
|
|
||||||
outline("category-production");
|
|
||||||
outline("block-mechanical-drill");
|
|
||||||
outline("blockinfo");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
conveyor(() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
|
|
||||||
void draw(){
|
|
||||||
outline("category-distribution");
|
|
||||||
outline("block-conveyor");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
turret(() -> placed(Blocks.duo, 1)){
|
|
||||||
void draw(){
|
|
||||||
outline("category-turret");
|
|
||||||
outline("block-duo");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
drillturret(() -> event("ammo")),
|
|
||||||
pause(() -> state.isPaused()){
|
|
||||||
void draw(){
|
|
||||||
if(mobile){
|
|
||||||
outline("pause");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
unpause(() -> !state.isPaused()){
|
|
||||||
void draw(){
|
|
||||||
if(mobile){
|
|
||||||
outline("pause");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
breaking(TutorialStage::blocksBroken){
|
|
||||||
void begin(){
|
|
||||||
placeBlocks();
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(){
|
|
||||||
if(mobile){
|
|
||||||
outline("breakmode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
withdraw(() -> event("withdraw")){
|
|
||||||
void begin(){
|
|
||||||
state.teams.playerCores().first().items.add(Items.copper, 10);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deposit(() -> event("deposit")),
|
|
||||||
waves(() -> state.wave > 2 && state.enemies <= 0 && !spawner.isSpawning()){
|
|
||||||
void begin(){
|
|
||||||
state.rules.waveTimer = true;
|
|
||||||
logic.runWave();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(){
|
|
||||||
if(state.wave > 2){
|
|
||||||
state.rules.waveTimer = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
launch(() -> false){
|
|
||||||
void begin(){
|
|
||||||
state.rules.waveTimer = false;
|
|
||||||
state.wave = 5;
|
|
||||||
|
|
||||||
//end tutorial, never show it again
|
|
||||||
Events.fire(Trigger.tutorialComplete);
|
|
||||||
Core.settings.put("playedtutorial", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw(){
|
|
||||||
outline("waves");
|
|
||||||
}
|
|
||||||
},;
|
|
||||||
|
|
||||||
protected String line = "";
|
|
||||||
protected final Func<String, String> text;
|
|
||||||
protected Seq<String> sentences;
|
|
||||||
protected final Boolp done;
|
|
||||||
|
|
||||||
TutorialStage(Func<String, String> text, Boolp done){
|
|
||||||
this.text = text;
|
|
||||||
this.done = done;
|
|
||||||
}
|
|
||||||
|
|
||||||
TutorialStage(Boolp done){
|
|
||||||
this(line -> line, done);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** displayed tutorial stage text.*/
|
|
||||||
public String text(){
|
|
||||||
if(sentences == null){
|
|
||||||
load();
|
|
||||||
}
|
|
||||||
String line = sentences.get(control.tutorial.sentence);
|
|
||||||
return line.contains("{") ? text.get(line) : line;
|
|
||||||
}
|
|
||||||
|
|
||||||
void load(){
|
|
||||||
this.line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
|
||||||
this.sentences = Seq.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** called every frame when this stage is active.*/
|
|
||||||
void update(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** called when a stage begins.*/
|
|
||||||
void begin(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** called when a stage needs to draw itself, usually over highlighted UI elements. */
|
|
||||||
void draw(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//utility
|
|
||||||
|
|
||||||
static void placeBlocks(){
|
|
||||||
Building core = state.teams.playerCores().first();
|
|
||||||
for(int i = 0; i < blocksToBreak; i++){
|
|
||||||
world.tile(core.tile().x + blockOffset, core.tile().y + i).remove();
|
|
||||||
world.tile(core.tile().x + blockOffset, core.tile().y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean blocksBroken(){
|
|
||||||
Building core = state.teams.playerCores().first();
|
|
||||||
|
|
||||||
for(int i = 0; i < blocksToBreak; i++){
|
|
||||||
if(world.tile(core.tile.x + blockOffset, core.tile.y + i).block() == Blocks.scrapWall){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean event(String name){
|
|
||||||
return control.tutorial.events.contains(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean placed(Block block, int amount){
|
|
||||||
return placed(block) >= amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int placed(Block block){
|
|
||||||
return control.tutorial.blocksPlaced.get(block, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int item(Item item){
|
|
||||||
return state.rules.defaultTeam.data().noCores() ? 0 : state.rules.defaultTeam.core().items.get(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean toggled(String name){
|
|
||||||
Element element = Core.scene.findVisible(name);
|
|
||||||
if(element instanceof Button){
|
|
||||||
return ((Button)element).isChecked();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void outline(String name){
|
|
||||||
Element element = Core.scene.findVisible(name);
|
|
||||||
if(element != null && !toggled(name)){
|
|
||||||
element.localToStageCoordinates(Tmp.v1.setZero());
|
|
||||||
float sin = Mathf.sin(11f, Scl.scl(4f));
|
|
||||||
Lines.stroke(Scl.scl(7f), Pal.place);
|
|
||||||
Lines.rect(Tmp.v1.x - sin, Tmp.v1.y - sin, element.getWidth() + sin*2, element.getHeight() + sin*2);
|
|
||||||
|
|
||||||
float size = Math.max(element.getWidth(), element.getHeight()) + Mathf.absin(11f/2f, Scl.scl(18f));
|
|
||||||
float angle = Angles.angle(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Tmp.v1.x + element.getWidth()/2f, Tmp.v1.y + element.getHeight()/2f);
|
|
||||||
Tmp.v2.trns(angle + 180f, size*1.4f);
|
|
||||||
float fs = Scl.scl(40f);
|
|
||||||
float fs2 = Scl.scl(56f);
|
|
||||||
|
|
||||||
Draw.color(Pal.gray);
|
|
||||||
Drawf.tri(Tmp.v1.x + element.getWidth()/2f + Tmp.v2.x, Tmp.v1.y + element.getHeight()/2f + Tmp.v2.y, fs2, fs2, angle);
|
|
||||||
Draw.color(Pal.place);
|
|
||||||
Tmp.v2.setLength(Tmp.v2.len() - Scl.scl(4));
|
|
||||||
Drawf.tri(Tmp.v1.x + element.getWidth()/2f + Tmp.v2.x, Tmp.v1.y + element.getHeight()/2f + Tmp.v2.y, fs, fs, angle);
|
|
||||||
Draw.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,7 @@ public class Universe{
|
|||||||
|
|
||||||
//update base coverage on capture
|
//update base coverage on capture
|
||||||
Events.on(SectorCaptureEvent.class, e -> {
|
Events.on(SectorCaptureEvent.class, e -> {
|
||||||
if(state.isCampaign()){
|
if(!net.client() && state.isCampaign()){
|
||||||
state.getSector().planet.updateBaseCoverage();
|
state.getSector().planet.updateBaseCoverage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildUI(Group group){
|
public void buildUI(Group group){
|
||||||
|
//respawn hints
|
||||||
group.fill(t -> {
|
group.fill(t -> {
|
||||||
t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty()));
|
t.visible(() -> Core.settings.getBool("hints") && ui.hudfrag.shown && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty()));
|
||||||
t.bottom();
|
t.bottom();
|
||||||
@@ -56,6 +57,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
}).margin(6f);
|
}).margin(6f);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//building hints
|
||||||
group.fill(t -> {
|
group.fill(t -> {
|
||||||
t.bottom();
|
t.bottom();
|
||||||
t.visible(() -> {
|
t.visible(() -> {
|
||||||
@@ -74,6 +76,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
}).margin(10f);
|
}).margin(10f);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//schematic controls
|
||||||
group.fill(t -> {
|
group.fill(t -> {
|
||||||
t.visible(() -> ui.hudfrag.shown && lastSchematic != null && !selectRequests.isEmpty());
|
t.visible(() -> ui.hudfrag.shown && lastSchematic != null && !selectRequests.isEmpty());
|
||||||
t.bottom();
|
t.bottom();
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import mindustry.world.draw.*;
|
|||||||
import mindustry.world.meta.*;
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class ContentParser{
|
public class ContentParser{
|
||||||
@@ -267,7 +268,13 @@ public class ContentParser{
|
|||||||
UnitType unit;
|
UnitType unit;
|
||||||
if(locate(ContentType.unit, name) == null){
|
if(locate(ContentType.unit, name) == null){
|
||||||
unit = new UnitType(mod + "-" + name);
|
unit = new UnitType(mod + "-" + name);
|
||||||
unit.constructor = Reflect.cons(resolve(Strings.capitalize(getType(value)), "mindustry.gen"));
|
var typeVal = value.get("type");
|
||||||
|
|
||||||
|
if(typeVal != null && !typeVal.isString()){
|
||||||
|
throw new RuntimeException("Unit '" + name + "' has an incorrect type. Types must be strings.");
|
||||||
|
}
|
||||||
|
|
||||||
|
unit.constructor = unitType(typeVal);
|
||||||
}else{
|
}else{
|
||||||
unit = locate(ContentType.unit, name);
|
unit = locate(ContentType.unit, name);
|
||||||
}
|
}
|
||||||
@@ -337,6 +344,18 @@ public class ContentParser{
|
|||||||
//ContentType.sector, parser(ContentType.sector, SectorPreset::new)
|
//ContentType.sector, parser(ContentType.sector, SectorPreset::new)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private Prov<Unit> unitType(JsonValue value){
|
||||||
|
if(value == null) return UnitEntity::create;
|
||||||
|
return switch(value.asString()){
|
||||||
|
case "flying" -> UnitEntity::create;
|
||||||
|
case "mech" -> MechUnit::create;
|
||||||
|
case "legs" -> LegsUnit::create;
|
||||||
|
case "naval" -> UnitWaterMove::create;
|
||||||
|
case "payload" -> PayloadUnit::create;
|
||||||
|
default -> throw new RuntimeException("Invalid unit type: '" + value + "'. Must be 'flying/mech/legs/naval/payload'.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private String getString(JsonValue value, String key){
|
private String getString(JsonValue value, String key){
|
||||||
if(value.has(key)){
|
if(value.has(key)){
|
||||||
return value.getString(key);
|
return value.getString(key);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package mindustry.ui;
|
|||||||
import arc.graphics.g2d.*;
|
import arc.graphics.g2d.*;
|
||||||
import arc.scene.ui.*;
|
import arc.scene.ui.*;
|
||||||
import arc.scene.ui.layout.*;
|
import arc.scene.ui.layout.*;
|
||||||
|
import mindustry.core.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
|
|
||||||
public class ItemImage extends Stack{
|
public class ItemImage extends Stack{
|
||||||
@@ -16,7 +17,7 @@ public class ItemImage extends Stack{
|
|||||||
|
|
||||||
add(new Table(t -> {
|
add(new Table(t -> {
|
||||||
t.left().bottom();
|
t.left().bottom();
|
||||||
t.add(amount + "");
|
t.add(amount > 1000 ? UI.formatAmount(amount) : amount + "");
|
||||||
t.pack();
|
t.pack();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ public class ItemImage extends Stack{
|
|||||||
if(stack.amount != 0){
|
if(stack.amount != 0){
|
||||||
add(new Table(t -> {
|
add(new Table(t -> {
|
||||||
t.left().bottom();
|
t.left().bottom();
|
||||||
t.add(stack.amount + "").style(Styles.outlineLabel);
|
t.add(stack.amount > 1000 ? UI.formatAmount(stack.amount) : stack.amount + "").style(Styles.outlineLabel);
|
||||||
t.pack();
|
t.pack();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public class Styles{
|
|||||||
//TODO all these names are inconsistent and not descriptive
|
//TODO all these names are inconsistent and not descriptive
|
||||||
public static Drawable black, black9, black8, black6, black3, black5, 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, fullTogglet, logict;
|
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, nonet, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt, fullTogglet, logict;
|
||||||
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, logici, geni, colori, accenti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, logici, geni, colori, accenti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
||||||
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
||||||
public static KeybindDialogStyle defaultKeybindDialog;
|
public static KeybindDialogStyle defaultKeybindDialog;
|
||||||
@@ -86,6 +86,13 @@ public class Styles{
|
|||||||
up = buttonOver;
|
up = buttonOver;
|
||||||
over = buttonDown;
|
over = buttonDown;
|
||||||
}};
|
}};
|
||||||
|
nonet = new TextButtonStyle(){{
|
||||||
|
font = Fonts.outline;
|
||||||
|
fontColor = Color.lightGray;
|
||||||
|
overFontColor = Pal.accent;
|
||||||
|
disabledFontColor = Color.gray;
|
||||||
|
up = none;
|
||||||
|
}};
|
||||||
cleart = new TextButtonStyle(){{
|
cleart = new TextButtonStyle(){{
|
||||||
over = flatOver;
|
over = flatOver;
|
||||||
font = Fonts.def;
|
font = Fonts.def;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
|||||||
selected = s;
|
selected = s;
|
||||||
update.run();
|
update.run();
|
||||||
rebuildItems.run();
|
rebuildItems.run();
|
||||||
}).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f);
|
}).group(group).pad(4).checked(s == selected).size(200f);
|
||||||
|
|
||||||
if(++i % cols == 0){
|
if(++i % cols == 0){
|
||||||
t.row();
|
t.row();
|
||||||
|
|||||||
@@ -134,6 +134,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
|||||||
/** show with no limitations, just as a map. */
|
/** show with no limitations, just as a map. */
|
||||||
@Override
|
@Override
|
||||||
public Dialog show(){
|
public Dialog show(){
|
||||||
|
if(net.client()){
|
||||||
|
ui.showInfo("@map.multiplayer");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
mode = look;
|
mode = look;
|
||||||
selected = hovered = launchSector = null;
|
selected = hovered = launchSector = null;
|
||||||
launching = false;
|
launching = false;
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public class ResearchDialog extends BaseDialog{
|
|||||||
public Dialog show(){
|
public Dialog show(){
|
||||||
if(net.client()){
|
if(net.client()){
|
||||||
ui.showInfo("@research.multiplayer");
|
ui.showInfo("@research.multiplayer");
|
||||||
return null;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.show();
|
return super.show();
|
||||||
|
|||||||
259
core/src/mindustry/ui/fragments/HintsFragment.java
Normal file
259
core/src/mindustry/ui/fragments/HintsFragment.java
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
package mindustry.ui.fragments;
|
||||||
|
|
||||||
|
import arc.*;
|
||||||
|
import arc.func.*;
|
||||||
|
import arc.input.*;
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.scene.*;
|
||||||
|
import arc.scene.actions.*;
|
||||||
|
import arc.scene.event.*;
|
||||||
|
import arc.scene.ui.layout.*;
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.*;
|
||||||
|
import mindustry.content.*;
|
||||||
|
import mindustry.game.EventType.*;
|
||||||
|
import mindustry.input.*;
|
||||||
|
import mindustry.ui.*;
|
||||||
|
import mindustry.world.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class HintsFragment extends Fragment{
|
||||||
|
private static final Boolp isTutorial = () -> Vars.state.rules.sector == SectorPresets.groundZero.sector;
|
||||||
|
private static final float foutTime = 0.6f;
|
||||||
|
|
||||||
|
/** All hints to be displayed in the game. */
|
||||||
|
public Seq<Hint> incomplete = Seq.with(DefaultHint.values());
|
||||||
|
@Nullable
|
||||||
|
public Hint current;
|
||||||
|
|
||||||
|
Group group = new WidgetGroup();
|
||||||
|
ObjectSet<String> events = new ObjectSet<>();
|
||||||
|
ObjectSet<Block> placedBlocks = new ObjectSet<>();
|
||||||
|
int checkIdx = 0;
|
||||||
|
Table last;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(Group parent){
|
||||||
|
group.setFillParent(true);
|
||||||
|
group.touchable = Touchable.childrenOnly;
|
||||||
|
group.visibility = () -> Core.settings.getBool("hints", true);
|
||||||
|
group.update(() -> {
|
||||||
|
if(current != null){
|
||||||
|
//current got completed
|
||||||
|
if(current.complete()){
|
||||||
|
complete();
|
||||||
|
}else if(!current.show()){ //current became hidden
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
}else if(incomplete.size > 0){
|
||||||
|
//check one hint each frame to see if it should be shown.
|
||||||
|
checkIdx = (checkIdx + 1) % incomplete.size;
|
||||||
|
Hint hint = incomplete.get(checkIdx);
|
||||||
|
if(hint.show() && !hint.finished() & !hint.complete()){
|
||||||
|
display(hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
parent.addChild(group);
|
||||||
|
|
||||||
|
checkNext();
|
||||||
|
|
||||||
|
Events.on(BlockBuildEndEvent.class, event -> {
|
||||||
|
if(!event.breaking && event.tile.team() == Vars.state.rules.defaultTeam){
|
||||||
|
placedBlocks.add(event.tile.block());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.breaking){
|
||||||
|
events.add("break");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.on(UnitControlEvent.class, e -> {
|
||||||
|
if(e.player == player){
|
||||||
|
events.add("unitcontrol");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.on(WorldLoadEvent.class, e -> Core.app.post(() -> {
|
||||||
|
checkNext();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkNext(){
|
||||||
|
if(current != null) return;
|
||||||
|
|
||||||
|
incomplete.removeAll(h -> h == current || !h.valid() || h.finished() || (h.show() && h.complete()));
|
||||||
|
incomplete.sort(Hint::order);
|
||||||
|
|
||||||
|
Hint first = incomplete.find(Hint::show);
|
||||||
|
if(first != null){
|
||||||
|
incomplete.remove(first);
|
||||||
|
display(first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(Hint hint){
|
||||||
|
if(current != null) return;
|
||||||
|
|
||||||
|
group.fill(t -> {
|
||||||
|
last = t;
|
||||||
|
t.left();
|
||||||
|
t.table(Styles.black5, cont -> {
|
||||||
|
cont.actions(Actions.alpha(0f), Actions.alpha(1f, 1f, Interp.smooth));
|
||||||
|
cont.margin(6f).add(hint.text()).width(Vars.mobile ? 300f : 400f).left().labelAlign(Align.left).wrap();
|
||||||
|
});
|
||||||
|
t.row();
|
||||||
|
t.button("@hint.skip", Styles.nonet, () -> {
|
||||||
|
if(current != null){
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
}).size(100f, 40f).left();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.current = hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Completes and hides the current hint. */
|
||||||
|
void complete(){
|
||||||
|
if(current == null) return;
|
||||||
|
|
||||||
|
current.finish();
|
||||||
|
incomplete.remove(current);
|
||||||
|
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hides the current hint, but does not complete it. */
|
||||||
|
void hide(){
|
||||||
|
//hide previous child if found
|
||||||
|
if(last != null){
|
||||||
|
last.actions(Actions.parallel(Actions.alpha(0f, foutTime, Interp.smooth), Actions.translateBy(0f, Scl.scl(-200f), foutTime, Interp.smooth)), Actions.remove());
|
||||||
|
}
|
||||||
|
//check for next hint to display immediately
|
||||||
|
current = null;
|
||||||
|
last = null;
|
||||||
|
checkNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shown(){
|
||||||
|
return current != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DefaultHint implements Hint{
|
||||||
|
desktopMove(visibleDesktop, () -> Core.input.axis(Binding.move_x) != 0 || Core.input.axis(Binding.move_y) != 0),
|
||||||
|
zoom(visibleDesktop, () -> Core.input.axis(KeyCode.scroll) != 0),
|
||||||
|
mine(isTutorial, () -> player.unit().mining()),
|
||||||
|
placeDrill(isTutorial, () -> ui.hints.placedBlocks.contains(Blocks.mechanicalDrill)),
|
||||||
|
placeConveyor(isTutorial, () -> ui.hints.placedBlocks.contains(Blocks.conveyor)),
|
||||||
|
placeTurret(isTutorial, () -> ui.hints.placedBlocks.contains(Blocks.duo)),
|
||||||
|
breaking(isTutorial, () -> ui.hints.events.contains("break")),
|
||||||
|
desktopShoot(visibleDesktop, () -> Vars.state.enemies > 0, () -> player.shooting),
|
||||||
|
depositItems(() -> player.unit().hasItem(), () -> !player.unit().hasItem()),
|
||||||
|
desktopPause(visibleDesktop, () -> isTutorial.get() && !Vars.net.active(), () -> Core.input.keyTap(Binding.pause)),
|
||||||
|
research(isTutorial, () -> ui.research.isShown()),
|
||||||
|
unitControl(() -> state.rules.defaultTeam.data().units.size > 1 && !net.active(), () -> !player.dead() && !player.unit().spawnedByCore),
|
||||||
|
respawn(visibleMobile, () -> !player.dead() && !player.unit().spawnedByCore, () -> !player.dead() && player.unit().spawnedByCore),
|
||||||
|
launch(() -> isTutorial.get() && state.rules.sector.isCaptured(), () -> ui.planet.isShown()),
|
||||||
|
;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String text;
|
||||||
|
int visibility = visibleAll;
|
||||||
|
Hint[] dependencies = {};
|
||||||
|
boolean finished, cached;
|
||||||
|
Boolp complete, shown = () -> true;
|
||||||
|
|
||||||
|
DefaultHint(Boolp complete){
|
||||||
|
this.complete = complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultHint(int visiblity, Boolp complete){
|
||||||
|
this(complete);
|
||||||
|
this.visibility = visiblity;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultHint(Boolp shown, Boolp complete){
|
||||||
|
this(complete);
|
||||||
|
this.shown = shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultHint(int visiblity, Boolp shown, Boolp complete){
|
||||||
|
this(complete);
|
||||||
|
this.shown = shown;
|
||||||
|
this.visibility = visiblity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean finished(){
|
||||||
|
if(!cached){
|
||||||
|
cached = true;
|
||||||
|
finished = Core.settings.getBool(name() + "-hint-done", false);
|
||||||
|
}
|
||||||
|
return finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish(){
|
||||||
|
Core.settings.put(name() + "-hint-done", finished = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String text(){
|
||||||
|
if(text == null){
|
||||||
|
text = Vars.mobile && Core.bundle.has("hint." + name() + ".mobile") ? Core.bundle.get("hint." + name() + ".mobile") : Core.bundle.get("hint." + name());
|
||||||
|
if(!Vars.mobile) text = text.replace("tap", "click").replace("Tap", "Click");
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean complete(){
|
||||||
|
return complete.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean show(){
|
||||||
|
return shown.get() && (dependencies.length == 0 || !Structs.contains(dependencies, d -> !d.finished()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int order(){
|
||||||
|
return ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean valid(){
|
||||||
|
return (Vars.mobile && (visibility & visibleMobile) != 0) || (!Vars.mobile && (visibility & visibleDesktop) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hint interface for defining any sort of message appearing at the left. */
|
||||||
|
public interface Hint{
|
||||||
|
int visibleDesktop = 1, visibleMobile = 2, visibleAll = visibleDesktop | visibleMobile;
|
||||||
|
|
||||||
|
/** Hint name for preference storage. */
|
||||||
|
String name();
|
||||||
|
/** Displayed text. */
|
||||||
|
String text();
|
||||||
|
/** @return true if hint objective is complete */
|
||||||
|
boolean complete();
|
||||||
|
/** @return whether the hint is ready to be shown */
|
||||||
|
boolean show();
|
||||||
|
/** @return order integer, determines priority */
|
||||||
|
int order();
|
||||||
|
/** @return whether this hint should be processed, used for platform splits */
|
||||||
|
boolean valid();
|
||||||
|
|
||||||
|
/** finishes the hint - it should not be shown again */
|
||||||
|
default void finish(){
|
||||||
|
Core.settings.put(name() + "-hint-done", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return whether the hint is finished - if true, it should not be shown again */
|
||||||
|
default boolean finished(){
|
||||||
|
return Core.settings.getBool(name() + "-hint-done", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,7 +108,8 @@ public class HudFragment extends Fragment{
|
|||||||
t.top().right();
|
t.top().right();
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO tear this all down
|
ui.hints.build(parent);
|
||||||
|
|
||||||
//menu at top left
|
//menu at top left
|
||||||
parent.fill(cont -> {
|
parent.fill(cont -> {
|
||||||
cont.name = "overlaymarker";
|
cont.name = "overlaymarker";
|
||||||
@@ -319,29 +320,6 @@ public class HudFragment extends Fragment{
|
|||||||
.update(label -> label.color.set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
.update(label -> label.color.set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO tutorial text
|
|
||||||
parent.fill(t -> {
|
|
||||||
t.name = "tutorial";
|
|
||||||
Runnable resize = () -> {
|
|
||||||
t.clearChildren();
|
|
||||||
t.top().right().visible(() -> false);
|
|
||||||
t.stack(new Button(){{
|
|
||||||
marginLeft(48f);
|
|
||||||
labelWrap(() -> control.tutorial.stage.text() + (control.tutorial.canNext() ? "\n\n" + Core.bundle.get("tutorial.next") : "")).width(!Core.graphics.isPortrait() ? 400f : 160f).pad(2f);
|
|
||||||
clicked(() -> control.tutorial.nextSentence());
|
|
||||||
setDisabled(() -> !control.tutorial.canNext());
|
|
||||||
}},
|
|
||||||
new Table(f -> {
|
|
||||||
f.left().button(Icon.left, Styles.emptyi, () -> {
|
|
||||||
control.tutorial.prevSentence();
|
|
||||||
}).width(44f).growY().visible(() -> control.tutorial.canPrev());
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
resize.run();
|
|
||||||
Events.on(ResizeEvent.class, e -> resize.run());
|
|
||||||
});
|
|
||||||
|
|
||||||
//'saving' indicator
|
//'saving' indicator
|
||||||
parent.fill(t -> {
|
parent.fill(t -> {
|
||||||
t.name = "saving";
|
t.name = "saving";
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=178412d54b62da44b56f7fde3b2fb9b81c5b0418
|
archash=7a74424ff0d0399a21023c9c702243b1b18126ed
|
||||||
|
|||||||
Reference in New Issue
Block a user