Skip to content

Commit 01b26c3

Browse files
committed
✨(mapScript/tags/towerDefend) 开源 塔防模式
1 parent 87c6f56 commit 01b26c3

3 files changed

Lines changed: 298 additions & 0 deletions

File tree

scripts/mapScript/tags/TDDrop.kts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package mapScript.tags
2+
3+
import mindustry.content.Items.*
4+
import mindustry.content.UnitTypes.*
5+
import mindustry.gen.Unit
6+
import mindustry.type.ItemStack
7+
import mindustry.type.ItemStack.with
8+
import kotlin.random.Random
9+
10+
/** 打怪掉落
11+
* @author WayZer
12+
* 如果有修改建议,建议提交PR,维护社区统一。
13+
* */
14+
15+
val dropMap = mapOf(
16+
// Ground Attack
17+
dagger to with(copper, 20, lead, 10, silicon, 3),
18+
mace to with(copper, 30, lead, 40, silicon, 10, titanium, 5),
19+
fortress to with(lead, 100, silicon, 40, graphite, 40, thorium, 10),
20+
scepter to with(copper, 300, silicon, 80, metaglass, 80, titanium, 80, thorium, 20, phaseFabric, 10),
21+
reign to with(
22+
copper, 400, lead, 400, silicon, 120, graphite, 120, thorium, 40,
23+
plastanium, 40, phaseFabric, 5, surgeAlloy, 15
24+
),
25+
// Spiders
26+
crawler to with(copper, 20, lead, 10, graphite, 3),
27+
atrax to with(copper, 30, lead, 40, graphite, 10, titanium, 5),
28+
spiroct to with(lead, 100, silicon, 40, graphite, 40, thorium, 10),
29+
arkyid to with(copper, 300, graphite, 80, metaglass, 80, titanium, 80, thorium, 20, phaseFabric, 10),
30+
toxopid to with(
31+
copper, 400, lead, 400, silicon, 120, graphite, 120, thorium, 40,
32+
plastanium, 40, phaseFabric, 5, surgeAlloy, 15
33+
),
34+
// Ground Support
35+
nova to with(copper, 20, lead, 10, titanium, 3),
36+
pulsar to with(copper, 30, lead, 40, titanium, 10),
37+
quasar to with(lead, 100, metaglass, 40, silicon, 40, titanium, 80, thorium, 10),
38+
vela to with(copper, 300, metaglass, 80, graphite, 80, titanium, 60, plastanium, 20, surgeAlloy, 5),
39+
corvus to with(
40+
copper, 400, lead, 400, silicon, 100, metaglass, 120,
41+
graphite, 100, titanium, 120, thorium, 60, phaseFabric, 10, surgeAlloy, 10
42+
),
43+
// Air Attack
44+
flare to with(copper, 20, lead, 10, graphite, 3),
45+
horizon to with(copper, 30, lead, 40, graphite, 10),
46+
zenith to with(lead, 100, silicon, 40, graphite, 40, titanium, 30, plastanium, 10),
47+
antumbra to with(copper, 300, graphite, 80, metaglass, 80, titanium, 60, surgeAlloy, 15),
48+
eclipse to with(
49+
copper, 400, lead, 400, silicon, 120, graphite, 120,
50+
titanium, 120, thorium, 40, plastanium, 40, phaseFabric, 10, surgeAlloy, 5
51+
),
52+
// Air Support
53+
mono to with(copper, 20, lead, 10, silicon, 3),
54+
poly to with(copper, 30, lead, 40, silicon, 10, titanium, 5),
55+
mega to with(lead, 100, silicon, 40, graphite, 40, thorium, 10),
56+
quad to with(copper, 300, silicon, 80, metaglass, 80, titanium, 80, thorium, 20, phaseFabric, 10),
57+
oct to with(
58+
copper, 400, lead, 400, silicon, 120, graphite, 120,
59+
thorium, 40, plastanium, 40, phaseFabric, 5, surgeAlloy, 15
60+
),
61+
// Ship Attack
62+
risso to with(copper, 20, lead, 10, metaglass, 3),
63+
minke to with(copper, 30, lead, 40, metaglass, 10),
64+
bryde to with(lead, 100, metaglass, 40, silicon, 40, titanium, 60, thorium, 15),
65+
sei to with(copper, 300, metaglass, 80, graphite, 80, titanium, 60, plastanium, 20, surgeAlloy, 5),
66+
omura to with(
67+
copper, 400, lead, 400, silicon, 100, metaglass, 120,
68+
graphite, 100, titanium, 120, thorium, 60, phaseFabric, 10, surgeAlloy, 10
69+
),
70+
71+
// Ship Support
72+
retusa to with(copper, 20, metaglass, 5, titanium, 5),
73+
oxynoe to with(copper, 30, lead, 40, metaglass, 8, titanium, 8),
74+
cyerce to with(lead, 100, metaglass, 40, silicon, 40, titanium, 80, thorium, 10),
75+
aegires to with(copper, 300, metaglass, 80, graphite, 80, titanium, 80, plastanium, 25),
76+
navanax to with(
77+
copper, 400, lead, 400, silicon, 100, metaglass, 120,
78+
graphite, 100, titanium, 80, plastanium, 45, phaseFabric, 5, surgeAlloy, 15
79+
),
80+
81+
// Basic
82+
alpha to with(copper, 5, lead, 10, silicon, 2, graphite, 3, metaglass, 3),
83+
beta to with(copper, 8, silicon, 5),
84+
gamma to with(lead, 10, metaglass, 8, graphite, 8),
85+
86+
//Erekir Field
87+
//Tank (focus on mining res)
88+
stell to with(beryllium, 20, graphite, 15),
89+
locus to with(beryllium, 50, graphite, 30, tungsten, 15),
90+
precept to with(beryllium, 100, graphite, 45, tungsten, 25, thorium, 20),
91+
vanquish to with(beryllium, 300, graphite, 100, tungsten, 80, thorium, 55, oxide, 15),
92+
conquer to with(
93+
beryllium, 400, graphite, 400, silicon, 120, tungsten, 120, thorium, 80,
94+
oxide, 10, carbide, 5
95+
),
96+
97+
//Mech (focus on process res)
98+
merui to with(beryllium, 25, silicon, 10),
99+
cleroi to with(beryllium, 50, graphite, 30, silicon, 25, oxide, 5),
100+
anthicus to with(beryllium, 100, graphite, 45, silicon, 50, oxide, 20),
101+
tecta to with(beryllium, 300, graphite, 100, silicon, 80, oxide, 25, carbide, 5),
102+
collaris to with(
103+
beryllium, 400, graphite, 400, silicon, 150, thorium, 120,
104+
oxide, 35, carbide, 20
105+
),
106+
107+
//Ship (mixed)
108+
elude to with(graphite, 25, silicon, 10),
109+
avert to with(beryllium, 50, tungsten, 30, silicon, 25),
110+
obviate to with(beryllium, 100, graphite, 45, silicon, 50, thorium, 20),
111+
quell to with(beryllium, 300, graphite, 150, silicon, 100, thorium, 50, oxide, 25),
112+
disrupt to with(
113+
beryllium, 400, graphite, 400, silicon, 130, tungsten, 100, thorium, 80,
114+
oxide, 25, carbide, 10
115+
),
116+
117+
// erekir core unit(might be killed at certain situation)
118+
evoke to with(beryllium, 35, graphite, 35, silicon, 20),
119+
incite to with(beryllium, 40, graphite, 40, tungsten, 20),
120+
emanate to with(beryllium, 50, graphite, 50, tungsten, 30, thorium, 15),
121+
)
122+
123+
fun handleDrop(unit: Unit, drop: Array<ItemStack>?) {
124+
if (unit.spawnedByCore || drop == null) return
125+
126+
val core = unit.closestEnemyCore() ?: return
127+
128+
val msg = drop.joinToString(" ") {
129+
val amount = Random.nextInt(it.amount - it.amount / 2, it.amount + it.amount * 2)
130+
val accept = core.acceptStack(it.item, amount, null)
131+
if (accept > 0)
132+
Call.transferItemTo(
133+
null, it.item, accept,
134+
unit.x + Random.nextFloat() * 2, unit.y + Random.nextFloat() * 2, core
135+
)
136+
"[accent]+$amount[]${it.item.emoji()}"
137+
}
138+
Call.label(msg, drop.size * 0.3f, unit.x + (Random.nextFloat() * 4 - 2f), unit.y + (Random.nextFloat() * 4 - 2f))
139+
}
140+
141+
val tdMode by mapTag("@TDDrop")
142+
onEnable {
143+
if (tdMode == "false" || tdMode == "off")
144+
ScriptManager.disableScript(this, "@TDDrop=$tdMode")
145+
}
146+
listen<EventType.UnitDestroyEvent> { e ->
147+
if (e.unit.team == state.rules.waveTeam || tdMode == "all")
148+
handleDrop(e.unit, dropMap[e.unit.type])
149+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package mapScript.tags
2+
3+
import mindustry.ai.Pathfinder
4+
import mindustry.entities.Units
5+
import mindustry.entities.units.AIController
6+
import mindustry.gen.Teamc
7+
import mindustry.gen.Unitc
8+
import mindustry.world.Tile
9+
import mindustry.world.blocks.environment.Floor
10+
import mindustry.world.blocks.storage.CoreBlock
11+
12+
class TowerDefendAI(private val floors: Set<Floor>) : AIController() {
13+
override fun shouldShoot(): Boolean = target != null && !invalid(target)
14+
override fun invalid(target: Teamc?) = when (target) {
15+
is CoreBlock.CoreBuild -> true
16+
is Tile -> target.block() is CoreBlock
17+
is Unitc -> with(target) {
18+
!isFlying && !isPlayer && floorOn() in floors
19+
}
20+
21+
else -> false
22+
}.not()
23+
24+
override fun findTarget(x: Float, y: Float, range: Float, air: Boolean, ground: Boolean): Teamc? {
25+
return if (unit.type.flying) unit.closestEnemyCore()
26+
else Units.closestEnemy(unit.team, x, y, range) { !invalid(it) }
27+
}
28+
29+
override fun updateMovement() {
30+
val core = unit.closestEnemyCore() ?: return
31+
val range = (unit.type.range * 0.8f).coerceAtMost(80f)
32+
if (unit.within(core, range)) {
33+
target = core
34+
if (unit.type.circleTarget) {
35+
this.circleAttack(range)
36+
}
37+
} else {
38+
if (unit.type.flying)
39+
moveTo(core, unit.type.range * 0.8f)
40+
else
41+
pathfind(Pathfinder.fieldCore)
42+
}
43+
faceTarget()
44+
}
45+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
@file:Depends("mapScript/tags/TDDrop", "掉落", soft = true)
2+
3+
package mapScript.tags
4+
5+
import arc.math.geom.Geometry
6+
import mindustry.net.Administration
7+
import mindustry.world.blocks.ConstructBlock
8+
import mindustry.world.blocks.environment.Floor
9+
10+
/** 塔防模式
11+
* @author WayZer
12+
* 如果有修改建议,建议提交PR,维护社区统一。
13+
* */
14+
15+
registerMapTag("@towerDefend")
16+
modeIntroduce(
17+
"塔防模式", """
18+
1.怪物只会攻击核心,可以放心建筑
19+
2.过于靠近怪物的兵可能会被杀掉
20+
3.道路上不准建筑(原因由上)
21+
4.核心附加的道路允许放置武装传送带
22+
5.怪物会掉落大量战利品(不限距离)
23+
6.部分物品被禁用(保证平衡)
24+
""".trimIndent()
25+
)
26+
27+
val allowBlocks = arrayOf(Blocks.armoredConveyor, Blocks.plastaniumConveyor)
28+
val floors = mutableSetOf<Floor>()
29+
onEnable {
30+
state.rules.bannedBlocks.takeIf { it.isEmpty }?.apply {
31+
add(Blocks.arc)
32+
add(Blocks.lancer)
33+
add(Blocks.airFactory)
34+
add(Blocks.mendProjector)
35+
}
36+
for (tile in spawner.spawns) {
37+
Geometry.circle(0, 0, 4) { dx, dy ->
38+
floors += tile.nearby(dx, dy)?.floor() ?: return@circle
39+
}
40+
}
41+
}
42+
onDisable { floors.clear() }
43+
44+
//build
45+
46+
registerActionFilter {
47+
when (it.type) {
48+
Administration.ActionType.placeBlock -> {
49+
if (it.block in allowBlocks && it.player.team().cores().any { core -> core.dst(it.tile) < 80 }) {
50+
return@registerActionFilter true //允许在核心附近建武装传送带
51+
}
52+
(it.tile.floor() !in floors).also { b ->
53+
if (!b) it.player.sendMessage("[red]你不能在此处建造".with(), MsgType.InfoToast, 3f)
54+
}
55+
}
56+
57+
Administration.ActionType.configure -> {
58+
when {
59+
it.tile.block() == Blocks.itemSource || it.tile.block() == Blocks.liquidSource -> {
60+
it.player.sendMessage("[red]不允许修改源".with(), MsgType.InfoToast, 3f)
61+
return@registerActionFilter false
62+
}
63+
}
64+
true
65+
}
66+
67+
else -> true
68+
}
69+
}
70+
listen<EventType.BlockBuildBeginEvent> {
71+
if (it.breaking) return@listen
72+
if (it.tile.floor() in floors) {
73+
if (it.unit.isPlayer) {
74+
return@listen//limited by filter
75+
}
76+
it.tile.remove()
77+
}
78+
}
79+
listen<EventType.TileChangeEvent> {
80+
val tile = it.tile
81+
if (tile.block() == Blocks.air || tile.block() in allowBlocks || tile.floor() !in floors) return@listen
82+
val building = tile.build
83+
if (building is ConstructBlock.ConstructBuild && building.current in allowBlocks)
84+
return@listen
85+
launch(Dispatchers.gamePost) {
86+
Call.deconstructFinish(tile, Blocks.air, null)
87+
}
88+
}
89+
90+
//unit
91+
92+
val specialFlag = 1024.0//use for identify unit spawned from factory
93+
listen<EventType.UnitCreateEvent> {
94+
if (it.unit.team == state.rules.waveTeam)
95+
it.unit.flag = specialFlag
96+
}
97+
listen(EventType.Trigger.update) {
98+
val units = state.rules.waveTeam.data().units
99+
units.forEach {
100+
if (it.flag == specialFlag) return@forEach
101+
if (it.controller() !is TowerDefendAI)
102+
it.controller(TowerDefendAI(floors))
103+
}
104+
}

0 commit comments

Comments
 (0)