2
2
3
3
import arc .*;
4
4
import arc .files .*;
5
+ import arc .math .*;
6
+ import arc .math .geom .*;
5
7
import arc .struct .*;
8
+ import arc .struct .IntFloatMap .*;
6
9
import arc .util .*;
7
10
import arc .util .serialization .*;
8
11
import arc .util .serialization .JsonWriter .*;
9
12
10
13
import mindustry .content .*;
14
+ import mindustry .entities .*;
11
15
import mindustry .game .*;
12
16
import mindustry .game .EventType .*;
13
17
import mindustry .gen .*;
14
18
import mindustry .mod .Plugin ;
15
19
16
- import fr .xpdustry .domination .DominationSettings .*;
17
-
18
- import java .util .*;
19
- import java .util .Map .*;
20
+ import fr .xpdustry .domination .Zone .*;
20
21
21
22
import static arc .util .Log .*;
22
23
import static mindustry .Vars .*;
23
24
25
+
24
26
@ SuppressWarnings ("unused" )
25
27
public class DominationPlugin extends Plugin {
26
28
private static DominationSettings settings ;
27
-
28
29
private static final Json json = new Json ();
29
30
private static final Fi config = new Fi (Core .files .external ("domination-config.json" ).absolutePath ());
30
31
31
32
private static final Interval interval = new Interval (3 );
32
33
private static final ObjectSet <Playerc > editors = new ObjectSet <>();
33
34
35
+ private static final IntFloatMap leaderboard = new IntFloatMap ();
36
+ private static final Seq <Effect > effects = Seq .with (Fx .mine , Fx .mineBig , Fx .mineHuge );
37
+
34
38
static {
35
39
json .setOutputType (OutputType .json );
36
40
json .setSerializer (DominationSettings .class , new DominationIO ());
37
41
}
38
42
39
- /** The zones of the current map, might throw a NPE if used when not playing */
40
43
private Seq <Zone > currentZones (){
41
44
return settings .maps .get (state .map .name (), Seq ::new );
42
45
}
@@ -51,46 +54,90 @@ public void init(){
51
54
config .writeString (json .prettyPrint (settings ));
52
55
}
53
56
57
+ Events .run (PlayEvent .class , () -> {
58
+ state .rules .modeName = "[red]Domination" ;
59
+ });
60
+
54
61
Events .run (WorldLoadEvent .class , () -> {
55
- // updates the radius if it has been changed
56
- currentZones ().each (z -> z .setRadius (settings .zoneRadius ));
57
- interval .reset (2 , 0 ); // Resets the timer when a new game begin
62
+ interval .reset (2 , 0 ); // Reset the timer
58
63
});
59
64
65
+ // Main
60
66
Events .run (Trigger .update , () -> {
61
- if (state .rules .pvp && !state .gameOver ){
62
- if (interval .get (0 , settings .updateTicks )){
63
- currentZones ().forEach (z -> z .update (settings .captureRate ));
64
- // Time remaining in seconds
65
- int time = (int ) ((settings .gameDuration - interval .getTime (2 )) / Time .toSeconds );
66
- Call .setHudText (Strings .format ("Time remaining > @:@" , time / 60 , time % 60 ));
67
- }if (interval .get (1 , settings .renderTicks )){
68
- currentZones ().forEach (z -> z .render (settings .updateTicks ));
69
- // Shows the zone center to the editors
70
- editors .each (p -> {
71
- currentZones ().each (z -> Call .effect (p .con (), Fx .heal , z .x * tilesize , z .y * tilesize , 0 , z .getTeam ().color ));
72
- });
67
+ if (isActive () && interval .get (0 , settings .updateTicks )){
68
+ // Updates the zone internal data
69
+ currentZones ().each (z -> z .update (settings ));
70
+
71
+ // Updates the leaderboard [team -> percent_captured]
72
+ leaderboard .clear (state .teams .active .size + 1 );
73
+ currentZones ().each (z -> leaderboard .increment (z .getTeam ().id , 0 , z .getPercent ()));
74
+ }
75
+
76
+ if (isActive () && interval .get (1 , settings .gameDuration )){
77
+ Entry winner = new Entry ();
78
+ for (Entry entry : leaderboard .entries ()){
79
+ if (entry .value > winner .value ){
80
+ winner = entry ;
81
+ }
73
82
}
74
83
75
- // Ugly way to determine the winner :^(
76
- if (interval .get (2 , settings .gameDuration )){
77
- Map <Team ,Float > teams = new HashMap <>(state .teams .getActive ().size ); // using map for the compute method...
78
- currentZones ().each (zone -> teams .compute (zone .getTeam (), (t , i ) -> zone .getPercent () + (i != null ? i : 0 )));
79
-
80
- // Gets the highest captured percent
81
- float max = 0F ;
82
- Team winner = Team .derelict ;
83
- for (Entry <Team ,Float > entry : teams .entrySet ()){
84
- if (entry .getValue () > max ){
85
- max = entry .getValue ();
86
- winner = entry .getKey ();
84
+ Events .fire (new GameOverEvent (Team .get (winner .key )));
85
+ }
86
+
87
+ if (interval .get (2 , Time .toSeconds / 6 )){
88
+ // HUD text
89
+ StringBuilder builder = new StringBuilder (100 );
90
+ // Generate a circle for the zone rendering
91
+ float [] circle = Geometry .regPoly ((int )(Mathf .pi * settings .zoneRadius ), settings .zoneRadius );
92
+
93
+ if (isActive ()){
94
+ currentZones ().each (z -> {
95
+ // Render the circle
96
+ Geometry .iteratePolygon ((cx , cy ) -> {
97
+ Call .effect (effects .random (), (cx + z .x ) * tilesize , (cy + z .y ) * tilesize , 0 , z .getTeam ().color );
98
+ }, circle );
99
+
100
+ // Display the percent in the circles
101
+ String percent = Strings .format ("[#@]@%" , z .getTeam ().color , Strings .fixed (z .getPercent (), 0 ));
102
+ Call .label (percent , 1.0F / 6 , z .x * tilesize , z .y * tilesize );
103
+ });
104
+
105
+ // Time remaining
106
+ int time = (int ) ((settings .gameDuration - interval .getTime (1 )) / Time .toSeconds );
107
+ builder .append (Strings .format ("Time remaining > @\n " , Strings .formatMillis (time * 1000L )));
108
+
109
+ // Leaderboard
110
+ var iterator = leaderboard .entries ().iterator ();
111
+ while (iterator .hasNext ()){
112
+ var entry = iterator .next ();
113
+ var team = Team .get (entry .key );
114
+ if (team != Team .derelict ){
115
+ builder .append (Strings .format ("[#@]@[] > @%" , team .color , team .name , (int )entry .value ));
116
+ if (iterator .hasNext ()) builder .append ('\n' );
87
117
}
88
118
}
89
119
90
- // Wee
91
- Events .fire (new GameOverEvent (winner ));
92
- Call .sendMessage (Strings .format ("Congrats, @ team win!" , winner ));
120
+ // Unclaimed zones
121
+ if (leaderboard .containsKey (Team .derelict .id )){
122
+ builder .append (Strings .format ("\n [#@]Unclaimed[] > @%" , Team .derelict .color , (int )leaderboard .get (Team .derelict .id )));
123
+ }
124
+
125
+ Call .setHudText (builder .toString ());
93
126
}
127
+
128
+ // Rendering for editors
129
+ editors .each (p -> {
130
+ currentZones ().each (z -> {
131
+ Call .effect (p .con (), Fx .unitLand , z .x * tilesize , z .y * tilesize , 0 , z .getTeam ().color );
132
+
133
+ if (!state .rules .pvp && state .isGame ()){
134
+ // Render the circle
135
+ Geometry .iteratePolygon ((cx , cy ) -> {
136
+ Call .effect (p .con (), effects .random (), (cx + z .x ) * tilesize , (cy + z .y ) * tilesize , 0 , z .getTeam ().color );
137
+ }, circle );
138
+ }
139
+ });
140
+ });
94
141
}
95
142
});
96
143
@@ -100,7 +147,6 @@ public void init(){
100
147
config .writeString (json .prettyPrint (settings ));
101
148
});
102
149
103
-
104
150
Events .on (PlayerLeave .class , event -> {
105
151
if (editors .contains (event .player )){
106
152
editors .remove (event .player );
@@ -111,7 +157,7 @@ public void init(){
111
157
if (editors .contains (event .player )){
112
158
Zone zone = currentZones ().find (z -> z .x == event .tile .x && z .y == event .tile .y );
113
159
if (zone == null ){
114
- currentZones ().add (new Zone (event .tile .x , event .tile .y , settings . zoneRadius ));
160
+ currentZones ().add (new Zone (event .tile .x , event .tile .y ));
115
161
}else {
116
162
currentZones ().remove (zone );
117
163
}
@@ -121,18 +167,13 @@ public void init(){
121
167
122
168
@ Override
123
169
public void registerServerCommands (CommandHandler handler ){
124
- handler .register ("domination-settings " , "<save/load>" , "Settings for the Domination plugin..." , args -> {
170
+ handler .register ("domination-config " , "<save/load>" , "Settings for the Domination plugin..." , args -> {
125
171
switch (args [0 ].toLowerCase ()){
126
172
case "save" -> {
127
173
config .writeString (json .prettyPrint (settings ));
128
174
info ("Settings have been successfully saved." );
129
175
}
130
176
case "load" -> {
131
- if (state .isGame ()){
132
- info ("You can't just modify the settings in the middle of the game..." );
133
- return ;
134
- }
135
-
136
177
settings = json .fromJson (DominationSettings .class , config );
137
178
info ("Settings have been successfully loaded." );
138
179
}
@@ -162,4 +203,16 @@ public void registerClientCommands(CommandHandler handler){
162
203
}
163
204
});
164
205
}
206
+
207
+ public static boolean isActive (){
208
+ return state .rules .pvp && !state .isMenu ();
209
+ }
210
+
211
+ static class DominationSettings {
212
+ public int zoneRadius = 5 ;
213
+ public float captureRate = 10F ;
214
+ public float updateTicks = Time .toSeconds ;
215
+ public float gameDuration = Time .toMinutes * 5 ;
216
+ public final ObjectMap <String , Seq <Zone >> maps = new ObjectMap <>();
217
+ }
165
218
}
0 commit comments