mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-02-22 04:28:27 +07:00
Random in-game music, untested
This commit is contained in:
parent
4ef60af4a8
commit
2341da995e
@ -25,7 +25,7 @@ public class Annotations{
|
||||
}
|
||||
|
||||
/** Indicates that a method return or field cannot be null.*/
|
||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface NonNull{
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
@ -1448,7 +1448,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
size = 2;
|
||||
range = 150f;
|
||||
reload = 30f;
|
||||
reload = 38f;
|
||||
restitution = 0.03f;
|
||||
ammoEjectBack = 3f;
|
||||
cooldown = 0.03f;
|
||||
|
@ -358,18 +358,7 @@ public class Control implements ApplicationListener{
|
||||
//autosave global data if it's modified
|
||||
data.checkSave();
|
||||
|
||||
if(state.is(State.menu)){
|
||||
if(ui.deploy.isShown()){
|
||||
music.play(Musics.launch);
|
||||
}else if(ui.editor.isShown()){
|
||||
music.play(Musics.editor);
|
||||
}else{
|
||||
music.play(Musics.menu);
|
||||
}
|
||||
}else{
|
||||
//TODO game music
|
||||
music.silence();
|
||||
}
|
||||
music.update();
|
||||
|
||||
if(!state.is(State.menu)){
|
||||
input.update();
|
||||
|
@ -3,44 +3,162 @@ package io.anuke.mindustry.game;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.audio.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/** Controls playback of multiple music tracks.*/
|
||||
public class MusicControl{
|
||||
private static final float finTime = 120f, foutTime = 120f;
|
||||
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.25f, musicWaveChance = 0.2f;
|
||||
|
||||
/** normal, ambient music, plays at any time */
|
||||
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6);
|
||||
/** darker music, used in times of conflict */
|
||||
public final Array<Music> darkMusic = Array.with(Musics.game2, Musics.game5, Musics.game7);
|
||||
/** all music, both dark and ambient */
|
||||
public final Array<Music> allMusic = Array.withArrays(ambientMusic, darkMusic);
|
||||
|
||||
private Music lastRandomPlayed;
|
||||
private Interval timer = new Interval();
|
||||
private @Nullable Music current;
|
||||
private float fade;
|
||||
private boolean silenced;
|
||||
|
||||
public void play(@Nullable Music music){
|
||||
if(current != null){
|
||||
current.setVolume(fade * Core.settings.getInt("musicvol") / 100f);
|
||||
}
|
||||
public MusicControl(){
|
||||
Events.on(WaveEvent.class, e -> Time.run(60f * 10f, () -> {
|
||||
if(Mathf.chance(musicWaveChance)){
|
||||
playRandom();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if(current == null && music != null){
|
||||
current = music;
|
||||
current.setLooping(true);
|
||||
current.setVolume(fade = 0f);
|
||||
current.play();
|
||||
}else if(current == music && music != null){
|
||||
fade = Mathf.clamp(fade + Time.delta()/finTime);
|
||||
}else if(current != null){
|
||||
fade = Mathf.clamp(fade - Time.delta()/foutTime);
|
||||
/** Update and play the right music track.*/
|
||||
public void update(){
|
||||
if(state.is(State.menu)){
|
||||
if(ui.deploy.isShown()){
|
||||
play(Musics.launch);
|
||||
}else if(ui.editor.isShown()){
|
||||
play(Musics.editor);
|
||||
}else{
|
||||
play(Musics.menu);
|
||||
}
|
||||
}else if(state.rules.editor){
|
||||
play(Musics.editor);
|
||||
}else{
|
||||
//this just fades out the last track to make way for ingame music
|
||||
silence();
|
||||
|
||||
if(fade <= 0.01f){
|
||||
current.stop();
|
||||
current = null;
|
||||
if(music != null){
|
||||
current = music;
|
||||
current.setVolume(fade = 0f);
|
||||
current.setLooping(true);
|
||||
current.play();
|
||||
//play music at intervals
|
||||
if(timer.get(musicInterval)){
|
||||
//chance to play it per interval
|
||||
if(Mathf.chance(musicChance)){
|
||||
playRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void silence(){
|
||||
/** Plays a random track.*/
|
||||
private void playRandom(){
|
||||
if(isDark()){
|
||||
playOnce(darkMusic.random(lastRandomPlayed));
|
||||
}else{
|
||||
playOnce(ambientMusic.random(lastRandomPlayed));
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether to play dark music.*/
|
||||
private boolean isDark(){
|
||||
if(!state.teams.get(player.getTeam()).cores.isEmpty() && state.teams.get(player.getTeam()).cores.first().entity.healthf() < 0.85f){
|
||||
//core damaged -> dark
|
||||
return true;
|
||||
}
|
||||
|
||||
if(state.enemies() > 25){
|
||||
//many enemies -> dark
|
||||
return true;
|
||||
}
|
||||
|
||||
//it may be dark based on wave
|
||||
if(Mathf.chance((float)(Math.log10((state.wave - 17f)/19f) + 1) / 4f)){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Plays and fades in a music track. This must be called every frame.
|
||||
* If something is already playing, fades out that track and fades in this new music.*/
|
||||
private void play(@Nullable Music music){
|
||||
//update volume of current track
|
||||
if(current != null){
|
||||
current.setVolume(fade * Core.settings.getInt("musicvol") / 100f);
|
||||
}
|
||||
|
||||
//do not update once the track has faded out completely, just stop
|
||||
if(silenced){
|
||||
return;
|
||||
}
|
||||
|
||||
if(current == null && music != null){
|
||||
//begin playing in a new track
|
||||
current = music;
|
||||
current.setLooping(true);
|
||||
current.setVolume(fade = 0f);
|
||||
current.play();
|
||||
silenced = false;
|
||||
}else if(current == music && music != null){
|
||||
//fade in the playing track
|
||||
fade = Mathf.clamp(fade + Time.delta()/finTime);
|
||||
}else if(current != null){
|
||||
//fade out the current track
|
||||
fade = Mathf.clamp(fade - Time.delta()/foutTime);
|
||||
|
||||
if(fade <= 0.01f){
|
||||
//stop current track when it hits 0 volume
|
||||
current.stop();
|
||||
current = null;
|
||||
silenced = true;
|
||||
if(music != null){
|
||||
//play newly scheduled track
|
||||
current = music;
|
||||
current.setVolume(fade = 0f);
|
||||
current.setLooping(true);
|
||||
current.play();
|
||||
silenced = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Plays a music track once and only once. If something is already playing, does nothing.*/
|
||||
private void playOnce(@NonNull Music music){
|
||||
if(current != null) return; //do not interrupt already-playing tracks
|
||||
|
||||
//save last random track played to prevent duplicates
|
||||
lastRandomPlayed = music;
|
||||
|
||||
//set fade to 1 and play it, stopping the current when it's done
|
||||
fade = 1f;
|
||||
current = music;
|
||||
current.setVolume(1f);
|
||||
current.setLooping(false);
|
||||
current.setCompletionListener(m -> {
|
||||
if(current == m){
|
||||
current = null;
|
||||
fade = 0f;
|
||||
}
|
||||
});
|
||||
current.play();
|
||||
}
|
||||
|
||||
/** Fades out the current track, unless it has already been silenced. */
|
||||
private void silence(){
|
||||
play(null);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.function.Supplier;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.input.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LoadoutDialog extends FloatingDialog{
|
||||
private Runnable hider;
|
||||
@ -14,24 +16,58 @@ public class LoadoutDialog extends FloatingDialog{
|
||||
private Runnable resetter;
|
||||
private Runnable updater;
|
||||
private Predicate<Item> filter;
|
||||
private Table items;
|
||||
private int capacity;
|
||||
|
||||
public LoadoutDialog(){
|
||||
super("$configure");
|
||||
setFillParent(false);
|
||||
addCloseButton();
|
||||
setFillParent(true);
|
||||
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
|
||||
Core.app.post(this::hide);
|
||||
}
|
||||
});
|
||||
|
||||
cont.add(items = new Table()).left();
|
||||
|
||||
shown(this::setup);
|
||||
hidden(() -> {
|
||||
if(hider != null){
|
||||
hider.run();
|
||||
}
|
||||
});
|
||||
buttons.row();
|
||||
buttons.addButton("$settings.reset", () -> {
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.addButton("$add", () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("");
|
||||
dialog.setFillParent(false);
|
||||
for(Item item : content.items().select(item -> filter.test(item) && item.type == ItemType.material && supplier.get().find(stack -> stack.item == item) == null)){
|
||||
TextButton button = dialog.cont.addButton("", "clear", () -> {
|
||||
dialog.hide();
|
||||
supplier.get().add(new ItemStack(item, 0));
|
||||
updater.run();
|
||||
setup();
|
||||
}).size(300f, 36f).get();
|
||||
button.clearChildren();
|
||||
button.left();
|
||||
button.addImage(item.icon(Item.Icon.medium)).size(8 * 3).pad(4);
|
||||
button.add(item.localizedName);
|
||||
dialog.cont.row();
|
||||
}
|
||||
dialog.show();
|
||||
}).size(100f, 40).left().disabled(b -> !content.items().contains(item -> filter.test(item) && !supplier.get().contains(stack -> stack.item == item)));
|
||||
|
||||
cont.row();
|
||||
cont.addButton("$settings.reset", () -> {
|
||||
resetter.run();
|
||||
updater.run();
|
||||
setup();
|
||||
}).size(210f, 64f);
|
||||
|
||||
cont.row();
|
||||
cont.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f);
|
||||
}
|
||||
|
||||
public void show(int capacity, Supplier<Array<ItemStack>> supplier, Runnable reseter, Runnable updater, Runnable hider, Predicate<Item> filter){
|
||||
@ -45,50 +81,31 @@ public class LoadoutDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
items.clearChildren();
|
||||
items.left();
|
||||
float bsize = 40f;
|
||||
int step = 50;
|
||||
|
||||
for(ItemStack stack : supplier.get()){
|
||||
cont.addButton("x", "clear-partial", () -> {
|
||||
items.addButton("x", "clear-partial", () -> {
|
||||
supplier.get().remove(stack);
|
||||
updater.run();
|
||||
setup();
|
||||
}).size(bsize);
|
||||
|
||||
cont.addButton("-", "clear-partial", () -> {
|
||||
items.addButton("-", "clear-partial", () -> {
|
||||
stack.amount = Math.max(stack.amount - step, 0);
|
||||
updater.run();
|
||||
}).size(bsize);
|
||||
cont.addButton("+", "clear-partial", () -> {
|
||||
items.addButton("+", "clear-partial", () -> {
|
||||
stack.amount = Math.min(stack.amount + step, capacity);
|
||||
updater.run();
|
||||
}).size(bsize);
|
||||
|
||||
cont.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(4);
|
||||
cont.label(() -> stack.amount + "").left();
|
||||
items.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(4).padLeft(4);
|
||||
items.label(() -> stack.amount + "").left();
|
||||
|
||||
cont.row();
|
||||
items.row();
|
||||
}
|
||||
|
||||
cont.addButton("$add", () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("");
|
||||
dialog.setFillParent(false);
|
||||
for(Item item : content.items().select(item -> filter.test(item) && item.type == ItemType.material && supplier.get().find(stack -> stack.item == item) == null)){
|
||||
TextButton button = dialog.cont.addButton("", "clear", () -> {
|
||||
supplier.get().add(new ItemStack(item, 0));
|
||||
updater.run();
|
||||
setup();
|
||||
dialog.hide();
|
||||
}).size(300f, 36f).get();
|
||||
button.clearChildren();
|
||||
button.left();
|
||||
button.addImage(item.icon(Item.Icon.medium)).size(8 * 3).pad(4);
|
||||
button.add(item.localizedName);
|
||||
dialog.cont.row();
|
||||
}
|
||||
dialog.show();
|
||||
}).colspan(4).size(100f, bsize).left().disabled(b -> !content.items().contains(item -> filter.test(item) && !supplier.get().contains(stack -> stack.item == item)));
|
||||
pack();
|
||||
}
|
||||
}
|
||||
|
@ -147,12 +147,7 @@ public class ServerControl implements ApplicationListener{
|
||||
Array<Map> maps = world.maps.customMaps().size == 0 ? world.maps.defaultMaps() : world.maps.customMaps();
|
||||
|
||||
Map previous = world.getMap();
|
||||
Map map = previous;
|
||||
if(maps.size > 1){
|
||||
while(map == previous) map = maps.random();
|
||||
}else if(!previous.custom && !world.maps.customMaps().isEmpty()){
|
||||
map = maps.first();
|
||||
}
|
||||
Map map = maps.random(previous);
|
||||
|
||||
Call.onInfoMessage((state.rules.pvp
|
||||
? "[YELLOW]The " + event.winner.name() + " team is victorious![]" : "[SCARLET]Game over![]")
|
||||
@ -162,9 +157,7 @@ public class ServerControl implements ApplicationListener{
|
||||
|
||||
info("Selected next map to be {0}.", map.name());
|
||||
|
||||
Map fmap = map;
|
||||
|
||||
play(true, () -> world.loadMap(fmap));
|
||||
play(true, () -> world.loadMap(map));
|
||||
}
|
||||
}else{
|
||||
netServer.kickAll(KickReason.gameover);
|
||||
|
Loading…
Reference in New Issue
Block a user