A somewhat complete tutorial
This commit is contained in:
@@ -275,6 +275,8 @@ public class Control implements ApplicationListener{
|
||||
control.saves.zoneSave();
|
||||
logic.play();
|
||||
state.rules.waveTimer = false;
|
||||
state.rules.waveSpacing = 60f * 30;
|
||||
state.rules.buildCostMultiplier = 0.3f;
|
||||
state.rules.tutorial = true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class UI implements ApplicationListener{
|
||||
Core.input.addProcessor(Core.scene);
|
||||
|
||||
Dialog.setShowAction(() -> sequence(alpha(0f), fadeIn(0.1f)));
|
||||
Dialog.setHideAction(() -> sequence(fadeOut(0.2f)));
|
||||
Dialog.setHideAction(() -> sequence(fadeOut(0.1f)));
|
||||
|
||||
Tooltips.getInstance().animations = false;
|
||||
|
||||
|
||||
@@ -54,7 +54,17 @@ public class EventType{
|
||||
}
|
||||
|
||||
/** Called when a turret recieves ammo, but only when the tutorial is active! */
|
||||
public static class AmmoDeliverEvent{
|
||||
public static class TurretAmmoDeliverEvent{
|
||||
|
||||
}
|
||||
|
||||
/** Called when a core recieves ammo, but only when the tutorial is active! */
|
||||
public static class CoreItemDeliverEvent{
|
||||
|
||||
}
|
||||
|
||||
/** Called when the player opens info for a specific block.*/
|
||||
public static class BlockInfoEvent{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,16 +9,18 @@ import io.anuke.arc.scene.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/** Handles tutorial state. */
|
||||
public class Tutorial{
|
||||
private static final int mineCopper = 16;
|
||||
private static final int mineCopper = 18;
|
||||
private static final int blocksToBreak = 3, blockOffset = 5;
|
||||
|
||||
private ObjectSet<String> events = new ObjectSet<>();
|
||||
private ObjectIntMap<Block> blocksPlaced = new ObjectIntMap<>();
|
||||
@@ -32,7 +34,9 @@ public class Tutorial{
|
||||
});
|
||||
|
||||
Events.on(LineConfirmEvent.class, event -> events.add("lineconfirm"));
|
||||
Events.on(AmmoDeliverEvent.class, event -> events.add("ammo"));
|
||||
Events.on(TurretAmmoDeliverEvent.class, event -> events.add("ammo"));
|
||||
Events.on(CoreItemDeliverEvent.class, event -> events.add("coreitem"));
|
||||
Events.on(BlockInfoEvent.class, event -> events.add("blockinfo"));
|
||||
}
|
||||
|
||||
/** update tutorial state, transition if needed */
|
||||
@@ -52,6 +56,7 @@ public class Tutorial{
|
||||
/** Resets tutorial state. */
|
||||
public void reset(){
|
||||
stage = TutorialStage.values()[0];
|
||||
stage.begin();
|
||||
blocksPlaced.clear();
|
||||
events.clear();
|
||||
}
|
||||
@@ -59,6 +64,7 @@ public class Tutorial{
|
||||
/** 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();
|
||||
}
|
||||
@@ -74,9 +80,16 @@ public class Tutorial{
|
||||
outline("block-mechanical-drill");
|
||||
}
|
||||
},
|
||||
blockinfo(() -> event("blockinfo")){
|
||||
void draw(){
|
||||
outline("category-production");
|
||||
outline("block-mechanical-drill");
|
||||
outline("blockinfo");
|
||||
}
|
||||
},
|
||||
conveyor(
|
||||
line -> Core.bundle.format(line, placed(Blocks.conveyor), 3),
|
||||
() -> placed(Blocks.conveyor, 3) && event("lineconfirm")){
|
||||
line -> Core.bundle.format(line, Math.min(placed(Blocks.conveyor), 2), 2),
|
||||
() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
|
||||
void draw(){
|
||||
outline("category-distribution");
|
||||
outline("block-conveyor");
|
||||
@@ -84,29 +97,57 @@ public class Tutorial{
|
||||
},
|
||||
turret(() -> placed(Blocks.duo, 1)){
|
||||
void draw(){
|
||||
outline("category-turrets");
|
||||
outline("category-turret");
|
||||
outline("block-duo");
|
||||
}
|
||||
},
|
||||
drillturret(() -> event("ammo")){
|
||||
drillturret(() -> event("ammo")),
|
||||
pause(() -> state.isPaused()){
|
||||
void draw(){
|
||||
outline("category-production");
|
||||
outline("block-mechanical-drill");
|
||||
if(mobile){
|
||||
outline("pause");
|
||||
}
|
||||
}
|
||||
},
|
||||
waves(() -> Vars.state.wave > 2 && Vars.state.enemies() <= 0){
|
||||
breaking(TutorialStage::blocksBroken){
|
||||
void begin(){
|
||||
Vars.state.rules.waveTimer = true;
|
||||
placeBlocks();
|
||||
}
|
||||
|
||||
void draw(){
|
||||
if(mobile){
|
||||
outline("breakmode");
|
||||
}
|
||||
}
|
||||
},
|
||||
waves(() -> state.wave > 2 && state.enemies() <= 0){
|
||||
void begin(){
|
||||
state.rules.waveTimer = true;
|
||||
logic.runWave();
|
||||
}
|
||||
|
||||
void update(){
|
||||
if(Vars.state.wave > 2){
|
||||
Vars.state.rules.waveTimer = false;
|
||||
if(state.wave > 2){
|
||||
state.rules.waveTimer = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
launch(() -> false){
|
||||
void begin(){
|
||||
state.rules.waveTimer = false;
|
||||
state.wave = 5;
|
||||
|
||||
protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && Vars.mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
||||
//end tutorial, never show it again
|
||||
Core.settings.put("tutorial", true);
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
void draw(){
|
||||
outline("waves");
|
||||
}
|
||||
},;
|
||||
|
||||
protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
||||
protected final Function<String, String> text;
|
||||
protected final BooleanProvider done;
|
||||
|
||||
@@ -142,8 +183,27 @@ public class Tutorial{
|
||||
|
||||
//utility
|
||||
|
||||
static void placeBlocks(){
|
||||
Tile core = state.teams.get(defaultTeam).cores.first();
|
||||
for(int i = 0; i < blocksToBreak; i++){
|
||||
world.removeBlock(world.ltile(core.x + blockOffset, core.y + i));
|
||||
world.tile(core.x + blockOffset, core.y + i).setBlock(Blocks.scrapWall);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean blocksBroken(){
|
||||
Tile core = state.teams.get(defaultTeam).cores.first();
|
||||
|
||||
for(int i = 0; i < blocksToBreak; i++){
|
||||
if(world.tile(core.x + blockOffset, core.y + i).block() == Blocks.scrapWall){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean event(String name){
|
||||
return Vars.control.tutorial.events.contains(name);
|
||||
return control.tutorial.events.contains(name);
|
||||
}
|
||||
|
||||
static boolean placed(Block block, int amount){
|
||||
@@ -151,11 +211,11 @@ public class Tutorial{
|
||||
}
|
||||
|
||||
static int placed(Block block){
|
||||
return Vars.control.tutorial.blocksPlaced.get(block, 0);
|
||||
return control.tutorial.blocksPlaced.get(block, 0);
|
||||
}
|
||||
|
||||
static int item(Item item){
|
||||
return Vars.state.teams.get(Vars.defaultTeam).cores.isEmpty() ? 0 : Vars.state.teams.get(Vars.defaultTeam).cores.first().entity.items.get(item);
|
||||
return state.teams.get(defaultTeam).cores.isEmpty() ? 0 : state.teams.get(defaultTeam).cores.first().entity.items.get(item);
|
||||
}
|
||||
|
||||
static boolean toggled(String name){
|
||||
@@ -173,6 +233,17 @@ public class Tutorial{
|
||||
float sin = Mathf.sin(11f, UnitScl.dp.scl(4f));
|
||||
Lines.stroke(UnitScl.dp.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, UnitScl.dp.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 = UnitScl.dp.scl(40f);
|
||||
float fs2 = UnitScl.dp.scl(50f);
|
||||
|
||||
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);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
table.addImageButton("icon-break-small", "clear-toggle-partial", iconsizesmall, () -> {
|
||||
mode = mode == breaking ? block == null ? none : placing : breaking;
|
||||
lastBlock = block;
|
||||
}).update(l -> l.setChecked(mode == breaking));
|
||||
}).update(l -> l.setChecked(mode == breaking)).name("breakmode");
|
||||
|
||||
//diagonal swap button
|
||||
table.addImageButton("icon-diagonal-small", "clear-toggle-partial", iconsizesmall, () -> {
|
||||
@@ -736,11 +736,6 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
return true;
|
||||
}
|
||||
|
||||
float clerp(float value, float min, float max){
|
||||
final float alpha = 0.07f;
|
||||
return value < min ? Mathf.lerpDelta(value, min, alpha) : value > max ? Mathf.lerpDelta(value, max, alpha) : value;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
private class PlaceRequest{
|
||||
|
||||
@@ -48,25 +48,21 @@ public class PausedDialog extends FloatingDialog{
|
||||
}
|
||||
cont.addButton("$settings", ui.settings::show);
|
||||
|
||||
if(!world.isZone() && !state.isEditor()){
|
||||
if(!state.rules.tutorial){
|
||||
if(!world.isZone() && !state.isEditor()){
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
}
|
||||
|
||||
cont.row();
|
||||
cont.addButton("$savegame", save::show);
|
||||
cont.addButton("$loadgame", load::show).disabled(b -> Net.active());
|
||||
|
||||
cont.addButton("$hostserver", ui.host::show).disabled(b -> Net.active()).colspan(2).width(dw * 2 + 20f);
|
||||
}
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.addButton("$hostserver", ui.host::show).disabled(b -> Net.active()).colspan(2).width(dw * 2 + 20f);
|
||||
cont.row();
|
||||
|
||||
cont.addButton("$quit", () -> {
|
||||
ui.showConfirm("$confirm", "$quit.confirm", () -> {
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
}).colspan(2).width(dw + 10f);
|
||||
cont.addButton("$quit", this::showQuitConfirm).colspan(2).width(dw + 10f);
|
||||
|
||||
}else{
|
||||
cont.defaults().size(120f).pad(5);
|
||||
@@ -87,17 +83,23 @@ public class PausedDialog extends FloatingDialog{
|
||||
|
||||
cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> Net.active());
|
||||
|
||||
cont.addRowImageTextButton("$quit", "icon-quit", isize, () -> {
|
||||
ui.showConfirm("$confirm", "$quit.confirm", () -> {
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
});
|
||||
cont.addRowImageTextButton("$quit", "icon-quit", isize, this::showQuitConfirm);
|
||||
}
|
||||
}
|
||||
|
||||
void showQuitConfirm(){
|
||||
ui.showConfirm("$confirm", state.rules.tutorial ? "$quit.confirm.tutorial" : "$quit.confirm", () -> {
|
||||
if(state.rules.tutorial){
|
||||
Core.settings.put("tutorial", true);
|
||||
Core.settings.save();
|
||||
}
|
||||
wasClient = Net.client();
|
||||
if(Net.client()) netClient.disconnectQuietly();
|
||||
runExitSave();
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
public void runExitSave(){
|
||||
if(state.isEditor() && !wasClient){
|
||||
ui.editor.resumeEditing();
|
||||
|
||||
@@ -71,7 +71,7 @@ public class HudFragment extends Fragment{
|
||||
}else{
|
||||
state.set(state.is(State.paused) ? State.playing : State.paused);
|
||||
}
|
||||
}).update(i -> {
|
||||
}).name("pause").update(i -> {
|
||||
if(Net.active()){
|
||||
i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-players");
|
||||
}else{
|
||||
@@ -312,9 +312,10 @@ public class HudFragment extends Fragment{
|
||||
.update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
||||
});
|
||||
|
||||
//tutorial text
|
||||
parent.fill(t -> {
|
||||
t.top().visible(() -> state.rules.tutorial);
|
||||
t.table("button-trans", f -> f.labelWrap(() -> control.tutorial.stage.text()).width(400f).pad(3f));
|
||||
t.table("button-trans", f -> f.labelWrap(() -> control.tutorial.stage.text()).width(500f).pad(3f));
|
||||
});
|
||||
|
||||
//paused table
|
||||
@@ -549,6 +550,7 @@ public class HudFragment extends Fragment{
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
table.setName("waves");
|
||||
table.labelWrap(() -> {
|
||||
builder.setLength(0);
|
||||
builder.append(wavef.get(state.wave));
|
||||
|
||||
@@ -55,6 +55,6 @@ public class LoadingFragment extends Fragment{
|
||||
table.clearActions();
|
||||
table.toFront();
|
||||
table.touchable(Touchable.disabled);
|
||||
table.actions(Actions.fadeOut(1f), Actions.visible(false));
|
||||
table.actions(Actions.fadeOut(0.5f), Actions.visible(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,7 @@ public class MenuFragment extends Fragment{
|
||||
|
||||
parent = group;
|
||||
|
||||
parent.fill((x, y, w, h) -> {
|
||||
renderer.render();
|
||||
});
|
||||
parent.fill((x, y, w, h) -> renderer.render());
|
||||
|
||||
parent.fill(c -> {
|
||||
container = c;
|
||||
|
||||
@@ -13,8 +13,7 @@ import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.UnlockEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
@@ -200,8 +199,10 @@ public class PlacementFragment extends Fragment{
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(unlocked(lastDisplay)){
|
||||
header.addButton("?", "clear-partial", () -> ui.content.show(lastDisplay))
|
||||
.size(8 * 5).padTop(-5).padRight(-5).right().grow();
|
||||
header.addButton("?", "clear-partial", () -> {
|
||||
ui.content.show(lastDisplay);
|
||||
Events.fire(new BlockInfoEvent());
|
||||
}).size(8 * 5).padTop(-5).padRight(-5).right().grow().name("blockinfo");
|
||||
}
|
||||
if(lastDisplay.buildVisibility == Blocks.padVisible && !lastDisplay.buildVisibility.get()){
|
||||
header.row();
|
||||
|
||||
@@ -131,7 +131,7 @@ public class ItemTurret extends CooledTurret{
|
||||
|
||||
//fire events for the tutorial
|
||||
if(state.rules.tutorial){
|
||||
Events.fire(new AmmoDeliverEvent());
|
||||
Events.fire(new TurretAmmoDeliverEvent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.world.blocks.storage;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.EnumSet;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
@@ -11,6 +12,7 @@ import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
@@ -122,7 +124,12 @@ public class CoreBlock extends StorageBlock{
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
if(Net.server() || !Net.active()) super.handleItem(item, tile, source);
|
||||
if(Net.server() || !Net.active()){
|
||||
super.handleItem(item, tile, source);
|
||||
if(state.rules.tutorial){
|
||||
Events.fire(new CoreItemDeliverEvent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user