Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
baf6bdf6a5 | ||
|
|
889fd64656 | ||
|
|
59b5d809db | ||
|
|
6c3372e71c | ||
|
|
1cdea49383 | ||
|
|
a6307039b0 | ||
|
|
aaacf244d2 | ||
|
|
2a0af620be | ||
|
|
b801093597 | ||
|
|
81dae580a4 | ||
|
|
03f58a1b02 | ||
|
|
b2b0082c7d | ||
|
|
1d85495f7a | ||
|
|
41d388aa7f | ||
|
|
e88921c77e | ||
|
|
705728f16a | ||
|
|
a7c24d4bfd | ||
|
|
79ace277ed | ||
|
|
bc035f9490 | ||
|
|
73a5af2e5e | ||
|
|
ee7bdbf44e | ||
|
|
b611726c3e | ||
|
|
819686e812 | ||
|
|
94e40a32b9 | ||
|
|
3b2669fa21 | ||
|
|
801ff1701e | ||
|
|
364a2b43c2 | ||
|
|
279d898d68 | ||
|
|
a930b34c3e | ||
|
|
232a3dfe87 | ||
|
|
ddbca62f92 | ||
|
|
646b022d38 | ||
|
|
19ef414e5c | ||
|
|
f46eb24615 | ||
|
|
4e6faf3bac | ||
|
|
48f5007306 | ||
|
|
56acbcecfd | ||
|
|
7d0952d858 | ||
|
|
ef40a2e78e | ||
|
|
b4abd3b23d | ||
|
|
f2a984f3e7 | ||
|
|
1ffa3f21f0 | ||
|
|
7e323f1ebf | ||
|
|
bff79d7c27 | ||
|
|
117f002545 | ||
|
|
953c1889b5 | ||
|
|
cc024a0bac | ||
|
|
42bfab6e40 | ||
|
|
c8ef7ebafb | ||
|
|
5512c1817d | ||
|
|
877999dd1e | ||
|
|
699f2ca5a2 | ||
|
|
89f04ed3e9 | ||
|
|
956840b50b | ||
|
|
b79e0373f4 |
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 322 B |
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 319 B |
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 521 B |
|
Before Width: | Height: | Size: 242 B After Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 469 B |
|
Before Width: | Height: | Size: 337 B After Width: | Height: | Size: 481 B |
|
Before Width: | Height: | Size: 247 B After Width: | Height: | Size: 308 B |
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 360 B |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 294 B After Width: | Height: | Size: 347 B |
|
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 380 B |
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 539 B |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 489 B |
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 458 B |
|
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 527 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 508 B |
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 519 B |
@@ -581,7 +581,6 @@ settings.clearcampaignsaves.confirm = Are you sure you want to clear all of your
|
||||
paused = [accent]< Paused >
|
||||
clear = Clear
|
||||
banned = [scarlet]Banned
|
||||
unplaceable.sectorcaptured = [scarlet]Requires captured sector
|
||||
yes = Yes
|
||||
no = No
|
||||
info.title = Info
|
||||
@@ -640,7 +639,7 @@ stat.lightningchance = Lightning Chance
|
||||
stat.lightningdamage = Lightning Damage
|
||||
stat.flammability = Flammability
|
||||
stat.radioactivity = Radioactivity
|
||||
stat.heatcapacity = HeatCapacity
|
||||
stat.heatcapacity = Heat Capacity
|
||||
stat.viscosity = Viscosity
|
||||
stat.temperature = Temperature
|
||||
stat.speed = Speed
|
||||
@@ -727,6 +726,7 @@ setting.blockreplace.name = Automatic Block Suggestions
|
||||
setting.linear.name = Linear Filtering
|
||||
setting.hints.name = Hints
|
||||
setting.flow.name = Display Resource Flow Rate
|
||||
setting.backgroundpause.name = Pause In Background
|
||||
setting.buildautopause.name = Auto-Pause Building
|
||||
setting.animatedwater.name = Animated Surfaces
|
||||
setting.animatedshields.name = Animated Shields
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
credits.text = 作者[royal]Anuken[] - [sky]anukendev@gmail.com[] 译者[orange]老滑稽[] - [cyan]QQ:1290419934[]
|
||||
credits.text = 作者[royal]Anuken[] - [sky]anukendev@gmail.com[]
|
||||
credits = 致谢
|
||||
contributors = 翻译者和贡献者
|
||||
discord = 加入 Mindustry 的 Discord!
|
||||
@@ -20,8 +20,8 @@ gameover = 游戏结束
|
||||
gameover.pvp = [accent] {0}[]队获胜!
|
||||
highscore = [accent]新纪录!
|
||||
copied = 已复制。
|
||||
indev.popup = [accent]v6[]仍在[accent]测试版[].\n[lightgray]这意味着:[]\n[scarlet]- 战役不完善[]\n- 内容不完整\n - 大多[scarlet]单位AI[]运行不佳\n- 单位系统不完整\n- 一切内容都可能发生变动或调整。\n\n向[accent]主群(QQ681962751)[]提交错误报告。
|
||||
indev.notready = 还没做好看NM
|
||||
indev.popup = [accent]6.0[]仍在[accent]测试版[].\n[lightgray]这意味着:[]\n[scarlet]- 战役玩法完全没有完成[]\n- 很多内容还没有做完\n - 大多[scarlet]单位AI[]无法正确地运行\n- 单位系统完全没有完成\n- 一切您所看到的内容都可能会移除或调整。\n\n在[accent]Github[]提交错误报告。\n[#66ccff]来自译者WinterUnderTheSnow的忠告:不建议新玩家游玩还在测试阶段的6.0!建议您先从[orange]v104.6[#66ccff]或[orange]v104.10[#66ccff]开始游玩!
|
||||
indev.notready = 这部分玩法还未开发完成。
|
||||
|
||||
load.sound = 音乐加载中
|
||||
load.map = 地图加载中
|
||||
@@ -66,7 +66,7 @@ stat.delivered = 装运资源:
|
||||
stat.playtime = 游玩时间:[accent] {0}
|
||||
stat.rank = 最终评级:[accent]{0}
|
||||
|
||||
globalitems = [accent]Global Items
|
||||
globalitems = [accent]全局物品
|
||||
map.delete = 确定要删除“[accent]{0}[]”地图吗?
|
||||
level.highscore = 最高分:[accent]{0}
|
||||
level.select = 选择关卡
|
||||
@@ -115,7 +115,7 @@ mod.disable = 禁用
|
||||
mod.content = 内容:
|
||||
mod.delete.error = 无法删除模组。可能文件被占用。
|
||||
mod.requiresversion = [scarlet]所需的游戏版本:[accent]{0}
|
||||
mod.outdated = [scarlet]模组不兼容6.0(缺失 minGameVersion: 105)
|
||||
mod.outdated = [scarlet]该模组可能不能在6.0上正确地运行(缺失 minGameVersion: 105)
|
||||
mod.missingdependencies = [scarlet]缺少前置模组:{0}
|
||||
mod.erroredcontent = [scarlet]内容错误
|
||||
mod.errors = 读取内容时发生错误.
|
||||
@@ -127,14 +127,14 @@ mod.reloadrequired = [scarlet]需要重启
|
||||
mod.import = 导入模组
|
||||
mod.import.file = 导入文件
|
||||
mod.import.github = 从 GitHub 导入模组
|
||||
mod.jarwarn = [scarlet]JAR模组存在危险性。[]\n请确保此模组来源安全可靠!
|
||||
mod.jarwarn = [scarlet]JAR模组注定存在危险性。[]\n请确保此模组来源安全可靠!
|
||||
mod.item.remove = 这个物品是[accent] '{0}'[]模组的一部分. 删除物品需要先卸载此模组.
|
||||
mod.remove.confirm = 此模组将被删除。
|
||||
mod.author = [lightgray]作者:[] {0}
|
||||
mod.missing = 此存档包含您最近已更新或者现在未安装的模组。存档可能会损坏。确定要加载它吗?\n[lightgray]模组:\n{0}
|
||||
mod.preview.missing = 在创意工坊中发布此模组前,您必须添加一则预览图像。\n请将名为[accent] preview.png[] 的图像放入模组文件夹,然后重试。
|
||||
mod.folder.missing = 只有文件夹形式的模组能在创意工坊上发布。\n若要将任何模组转换为文件夹,只需将其文件解压缩到文件夹中并删除旧压缩包,然后重新启动游戏或重新加载模组。
|
||||
mod.scripts.disable = 你的设备不支持含有脚本的模组。必须禁用相关模组以进入游戏。
|
||||
mod.scripts.disable = 您的设备不支持含有脚本的模组。必须禁用相关模组以进入游戏。
|
||||
|
||||
about.button = 关于
|
||||
name = 名字:
|
||||
@@ -157,22 +157,22 @@ server.closing = [accent]服务器关闭…
|
||||
server.kicked.kick = 你被踢出了服务器。
|
||||
server.kicked.whitelist = 你不在服务器白名单中。
|
||||
server.kicked.serverClose = 服务器已关闭。
|
||||
server.kicked.vote = 你被投票踢出了服务器。
|
||||
server.kicked.vote = 您被投票踢出了服务器。
|
||||
server.kicked.clientOutdated = 客户端过旧,请更新你的游戏。
|
||||
server.kicked.serverOutdated = 服务器过旧,请联系服务器管理员升级服务器。
|
||||
server.kicked.banned = 你在这个服务器上被封禁了。
|
||||
server.kicked.banned = 您在这个服务器上被封禁了。
|
||||
server.kicked.typeMismatch = 此服务器与你的不稳定测试版不兼容。
|
||||
server.kicked.playerLimit = 服务器已满,请等待一个空位。
|
||||
server.kicked.recentKick = 你刚刚被踢出服务器。\n请稍后重新连接!
|
||||
server.kicked.nameInUse = 你的名字与服务器中的一个人重复了。
|
||||
server.kicked.nameInUse = 您的名字与服务器中的一个人重复了。
|
||||
server.kicked.nameEmpty = 无效的名字!
|
||||
server.kicked.idInUse = 你已经连接了这个服务器!不允许在一台电脑上用两个客户端连接。
|
||||
server.kicked.idInUse = 您已经连接了这个服务器!不允许在一台设备上用两个客户端连接。
|
||||
server.kicked.customClient = 这个服务器不支持自定义客户端。请下载官方版本。
|
||||
server.kicked.gameover = 游戏结束!
|
||||
server.kicked.serverRestarting = 服务器正在重启.
|
||||
server.versions = 客户端版本:[accent] {0}[]\n服务器版本:[accent] {1}[]
|
||||
host.info = [accent]创建局域网游戏[]按钮会在[scarlet] 6567 []端口运行一个服务器。[]\n任何在同一个[lightgray] Wi-Fi 或本地网络[]下的人应该都可以在服务器列表中看到你的服务器。\n\n如果你想让别人在任何地方都能通过 IP 地址连接,你需要设定[accent]端口转发[]。\n\n[lightgray]注意:如果某人无法连接到你的局域网游戏,请确保你在防火墙设置里允许了 Mindustry 访问本地网络。
|
||||
join.info = 您可以输入[accent]服务器的 IP 地址[]来连接,或寻找[accent]本地网络[]中的服务器来连接。\n支持局域网或广域网的多人游戏。\n\n[lightgray]注意:没有全球服务器列表;如果你想通过 IP 地址连接某个服务器,你需要向房主询问 IP 地址。
|
||||
join.info = 您可以输入[accent]服务器的 IP 地址[]来连接,或寻找[accent]本地网络[]中的服务器来连接。\n支持局域网或广域网的多人游戏。\n\n[lightgray]注意:没有全球服务器列表;如果你想通过 IP 地址连接某个服务器,你需要向服主询问 IP 地址。
|
||||
hostserver = 创建服务器
|
||||
invitefriends = 邀请朋友
|
||||
hostserver.mobile = 创建\n服务器
|
||||
@@ -201,7 +201,7 @@ server.bans.none = 没有被封禁的玩家!
|
||||
server.admins = 管理员
|
||||
server.admins.none = 该服务器没有管理员!
|
||||
server.add = 添加服务器
|
||||
server.delete = 你确定要删除这个服务器吗?
|
||||
server.delete = 您确定要删除这个服务器吗?
|
||||
server.edit = 编辑服务器
|
||||
server.outdated = [crimson]服务器过旧![]
|
||||
server.outdated.client = [crimson]客户端过旧![]
|
||||
@@ -228,11 +228,11 @@ server.addressinuse = 地址已在使用!
|
||||
server.invalidport = 无效的端口!
|
||||
server.error = [crimson]创建服务器错误:[accent]{0}
|
||||
save.new = 新存档
|
||||
save.overwrite = 你确定你要覆盖这个存档吗?
|
||||
save.overwrite = 您确定要覆盖这个存档吗?
|
||||
overwrite = 覆盖
|
||||
save.none = 没有找到存档!
|
||||
savefail = 保存失败!
|
||||
save.delete.confirm = 你确定你要删除这个存档吗?
|
||||
save.delete.confirm = 您确定要删除这个存档吗?
|
||||
save.delete = 删除
|
||||
save.export = 导出存档
|
||||
save.import.invalid = [accent]此存档无效!
|
||||
@@ -245,7 +245,7 @@ save.rename.text = 新名称:
|
||||
selectslot = 选择一个存档。
|
||||
slot = [accent]存档位 {0}
|
||||
editmessage = 编辑消息
|
||||
save.corrupted = [accent]存档损坏或无效!\n如果你刚刚升级了游戏,那么这可能是因为存档格式改变了,而[scarlet]不是[] bug 。
|
||||
save.corrupted = [accent]存档损坏或无效!\n如果您刚刚升级了游戏,那么这可能是因为存档格式改变了,而[scarlet]不是[] bug 。
|
||||
empty = < 空 >
|
||||
on = 开
|
||||
off = 关
|
||||
@@ -297,8 +297,8 @@ loadimage = 加载图片
|
||||
saveimage = 保存图片
|
||||
unknown = 未知
|
||||
custom = 自定义
|
||||
builtin = 内建的
|
||||
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法撤销!
|
||||
builtin = 内置的
|
||||
map.delete.confirm = 您确定你想要删除这张地图吗?这个操作无法撤销!
|
||||
map.random = [accent]随机地图
|
||||
map.nospawn = 这个地图没有核心!请在编辑器中添加一个[royal]己方[]的核心。
|
||||
map.nospawn.pvp = 这个地图没有敌人的核心!请在编辑器中添加一个[royal]敌人[]的核心。
|
||||
@@ -363,7 +363,7 @@ editor.removeunit = 移除单位
|
||||
editor.teams = 队伍
|
||||
editor.errorload = 读取文件出错:\n[accent]{0}
|
||||
editor.errorsave = 保存文件出错:\n[accent]{0}
|
||||
editor.errorimage = 这是一幅图片,不是地图。请不要更改文件的扩展名来导入。\n\n如果你想导入地图,请在编辑器中使用“导入地图”按钮。
|
||||
editor.errorimage = 这是一幅图片,不是地图。请不要更改文件的扩展名来导入。\n\n如果您想导入地图,请在编辑器中使用“导入地图”按钮。
|
||||
editor.errorlegacy = 此地图太旧了,旧的地图格式已不再支持。
|
||||
editor.errornot = 这不是地图文件。
|
||||
editor.errorheader = 此地图文件无效或已损坏。
|
||||
@@ -376,8 +376,8 @@ editor.resize = 调整大小
|
||||
editor.loadmap = 载入地图
|
||||
editor.savemap = 保存地图
|
||||
editor.saved = 已保存!
|
||||
editor.save.noname = 你的地图没有名字!在“地图信息”菜单里设置一个。
|
||||
editor.save.overwrite = 你的地图覆盖了一个内置的地图!在“地图信息”菜单里重新设置一个不同的名称。
|
||||
editor.save.noname = 您的地图没有名字!在“地图信息”菜单里设置一个。
|
||||
editor.save.overwrite = 您的地图覆盖了一个内置的地图!在“地图信息”菜单里重新设置一个不同的名称。
|
||||
editor.import.exists = [scarlet]无法导入:[]存在名为“{0}”的内置地图!
|
||||
editor.import = 导入…
|
||||
editor.importmap = 导入地图
|
||||
@@ -794,8 +794,8 @@ keybind.clear_building.name = 清除建筑
|
||||
keybind.press = 请按一个键…
|
||||
keybind.press.axis = 请按一个轴或键…
|
||||
keybind.screenshot.name = 地图截图
|
||||
keybind.toggle_power_lines.name = 显隐能量标识线
|
||||
keybind.toggle_block_status.name = 显隐方块状态
|
||||
keybind.toggle_power_lines.name = 显示/隐藏能量标识线
|
||||
keybind.toggle_block_status.name = 显示/隐藏方块状态
|
||||
keybind.move_x.name = 水平移动
|
||||
keybind.move_y.name = 竖直移动
|
||||
keybind.mouse_move.name = 跟随鼠标
|
||||
@@ -922,36 +922,36 @@ liquid.oil.name = 石油
|
||||
liquid.cryofluid.name = 冷冻液
|
||||
|
||||
unit.dagger.name = 尖刀
|
||||
unit.mace.name = 牙狼
|
||||
unit.mace.name = 战锤
|
||||
unit.fortress.name = 堡垒
|
||||
unit.nova.name = 新星
|
||||
unit.pulsar.name = 脉冲星
|
||||
unit.pulsar.name = 恒星
|
||||
unit.quasar.name = 超星
|
||||
unit.crawler.name = 爬虫
|
||||
unit.atrax.name = 火蛛
|
||||
unit.spiroct.name = 天蝎
|
||||
unit.arkyid.name = 血蛭
|
||||
unit.toxopid.name = 毒蟒
|
||||
unit.flare.name = 星耀
|
||||
unit.atrax.name = 毒蛛
|
||||
unit.spiroct.name = 血蛭
|
||||
unit.arkyid.name = 毒蛊
|
||||
unit.toxopid.name = 天蝎
|
||||
unit.flare.name = 星辉
|
||||
unit.horizon.name = 天垠
|
||||
unit.zenith.name = 苍穹
|
||||
unit.antumbra.name = 半影
|
||||
unit.antumbra.name = 月影
|
||||
unit.eclipse.name = 日蚀
|
||||
unit.mono.name = 独影
|
||||
unit.poly.name = 聚幻
|
||||
unit.mega.name = 巨像
|
||||
unit.poly.name = 聚辉
|
||||
unit.mega.name = 巨灵
|
||||
unit.quad.name = 雷霆
|
||||
unit.oct.name = 要塞
|
||||
unit.risso.name = 梭鱼
|
||||
unit.minke.name = 刺鲸
|
||||
unit.bryde.name = 虎鲨
|
||||
unit.sei.name = 湖妖
|
||||
unit.bryde.name = 戟鲸
|
||||
unit.sei.name = 水怪
|
||||
unit.omura.name = 海神
|
||||
unit.alpha.name = 阿尔法
|
||||
unit.alpha.name = 沉思者
|
||||
unit.beta.name = 贝塔
|
||||
unit.gamma.name = 伽玛
|
||||
unit.gamma.name = 伽马
|
||||
unit.scepter.name = 权杖
|
||||
unit.reign.name = 君王
|
||||
unit.reign.name = 王座
|
||||
unit.vela.name = 灾星
|
||||
unit.corvus.name = 死星
|
||||
|
||||
@@ -1056,7 +1056,7 @@ block.conveyor.name = 传送带
|
||||
block.titanium-conveyor.name = 钛传送带
|
||||
block.plastanium-conveyor.name = 塑钢传送带
|
||||
block.armored-conveyor.name = 装甲传送带
|
||||
block.armored-conveyor.description = 运送物品,与钛传送带一样的速度,但有更强的装甲。除其他传送带,不接受任何边的输入。
|
||||
block.armored-conveyor.description = 运送物品,与钛传送带一样的速度,但有更强的装甲。除其他传送带,不接受任何边上的输入。
|
||||
block.junction.name = 连接器
|
||||
block.router.name = 路由器
|
||||
block.distributor.name = 分配器
|
||||
@@ -1148,26 +1148,26 @@ block.launch-pad.name = 发射台
|
||||
block.launch-pad-large.name = 大型发射台
|
||||
block.segment.name = 裂解光束
|
||||
block.command-center.name = 指挥中心
|
||||
block.ground-factory.name = 陆战单位工厂
|
||||
block.air-factory.name = 空战单位工厂
|
||||
block.naval-factory.name = 海战单位工厂
|
||||
block.additive-reconstructor.name = 数增级单位重构工厂
|
||||
block.multiplicative-reconstructor.name = 倍增级单位重构工厂
|
||||
block.exponential-reconstructor.name = 幂乘级单位重构工厂
|
||||
block.tetrative-reconstructor.name = 无量级单位重构工厂
|
||||
block.ground-factory.name = 陆军工厂
|
||||
block.air-factory.name = 空军工厂
|
||||
block.naval-factory.name = 海军工厂
|
||||
block.additive-reconstructor.name = 添改单位重构工厂
|
||||
block.multiplicative-reconstructor.name = 多倍单位重构工厂
|
||||
block.exponential-reconstructor.name = 多幂级单位重构工厂
|
||||
block.tetrative-reconstructor.name = 实验性泰坦重构工厂
|
||||
block.payload-conveyor.name = 载荷传送带
|
||||
block.payload-router.name = 载荷路由器
|
||||
block.disassembler.name = 分离机
|
||||
block.silicon-crucible.name = 热能坩埚
|
||||
block.overdrive-dome.name = 超速场投射器
|
||||
block.disassembler.name = 离心机
|
||||
block.silicon-crucible.name = 硅坩埚
|
||||
block.overdrive-dome.name = 超速穹顶投射器
|
||||
|
||||
block.switch.name = 开关
|
||||
block.micro-processor.name = 微型处理器
|
||||
block.logic-processor.name = 逻辑处理器
|
||||
block.hyper-processor.name = 超频处理器
|
||||
block.hyper-processor.name = 超核处理器
|
||||
block.logic-display.name = 逻辑显示屏
|
||||
block.large-logic-display.name = 大型逻辑显示屏
|
||||
block.memory-cell.name = 存储单元
|
||||
block.memory-cell.name = 内存单位
|
||||
block.memory-bank.name = Memory Bank
|
||||
|
||||
team.blue.name = 蓝
|
||||
|
||||
|
Before Width: | Height: | Size: 562 KiB After Width: | Height: | Size: 556 KiB |
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 185 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
@@ -36,8 +36,8 @@ public class Vars implements Loadable{
|
||||
public static boolean loadLocales = true;
|
||||
/** Whether the logger is loaded. */
|
||||
public static boolean loadedLogger = false, loadedFileLogger = false;
|
||||
/** Whether to show the cliff button in the editor*/
|
||||
public static boolean addCliffButton = false;
|
||||
/** Whether to enable various experimental features (e.g. cliffs) */
|
||||
public static boolean experimental = false;
|
||||
/** Maximum extra padding around deployment schematics. */
|
||||
public static final int maxLoadoutSchematicPad = 5;
|
||||
/** Maximum schematic size.*/
|
||||
|
||||
@@ -312,6 +312,28 @@ public class BlockIndexer{
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Find the closest ore block relative to a position. */
|
||||
public Tile findClosestOre(Unit unit, Item item){
|
||||
if(!(unit instanceof Minerc miner)) return null;
|
||||
|
||||
TileArray arr = getOrePositions(item);
|
||||
|
||||
arr.tiles.sort(t -> t.dst2(unit.x, unit.y));
|
||||
|
||||
for(Tile tile : arr.tiles){
|
||||
for(int x = Math.max(0, tile.x - quadrantSize / 2); x < tile.x + quadrantSize / 2 && x < world.width(); x++){
|
||||
for(int y = Math.max(0, tile.y - quadrantSize / 2); y < tile.y + quadrantSize / 2 && y < world.height(); y++){
|
||||
Tile res = world.tile(x, y);
|
||||
if(res.drop() == item && miner.validMine(res, false)){
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return extra unit cap of a team. This is added onto the base value. */
|
||||
public int getExtraUnits(Team team){
|
||||
return unitCaps[team.id];
|
||||
@@ -457,8 +479,8 @@ public class BlockIndexer{
|
||||
}
|
||||
|
||||
public static class TileArray implements Iterable<Tile>{
|
||||
private Seq<Tile> tiles = new Seq<>(false, 16);
|
||||
private IntSet contained = new IntSet();
|
||||
Seq<Tile> tiles = new Seq<>(false, 16);
|
||||
IntSet contained = new IntSet();
|
||||
|
||||
public void add(Tile tile){
|
||||
if(contained.add(tile.pos())){
|
||||
|
||||
@@ -14,7 +14,7 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class LogicAI extends AIController{
|
||||
/** Minimum delay between item transfers. */
|
||||
public static final float transferDelay = 60f * 3f;
|
||||
public static final float transferDelay = 60f * 2f;
|
||||
/** Time after which the unit resets its controlled and reverts to a normal unit. */
|
||||
public static final float logicControlTimeout = 10f * 60f;
|
||||
|
||||
@@ -44,8 +44,8 @@ public class LogicAI extends AIController{
|
||||
|
||||
@Override
|
||||
protected void updateMovement(){
|
||||
if(itemTimer > 0) itemTimer -= Time.delta;
|
||||
if(payTimer > 0) payTimer -= Time.delta;
|
||||
if(itemTimer >= 0) itemTimer -= Time.delta;
|
||||
if(payTimer >= 0) payTimer -= Time.delta;
|
||||
|
||||
if(targetTimer > 0f){
|
||||
targetTimer -= Time.delta;
|
||||
|
||||
@@ -39,8 +39,8 @@ public class MinerAI extends AIController{
|
||||
if(unit.stack.amount >= unit.type.itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){
|
||||
mining = false;
|
||||
}else{
|
||||
if(retarget() && targetItem != null){
|
||||
ore = indexer.findClosestOre(unit.x, unit.y, targetItem);
|
||||
if(timer.get(timerTarget, 60) && targetItem != null){
|
||||
ore = indexer.findClosestOre(unit, targetItem);
|
||||
}
|
||||
|
||||
if(ore != null){
|
||||
|
||||
@@ -103,6 +103,7 @@ public class Blocks implements ContentList{
|
||||
alwaysReplace = true;
|
||||
hasShadow = false;
|
||||
useColor = false;
|
||||
wall = this;
|
||||
}
|
||||
|
||||
@Override public void drawBase(Tile tile){}
|
||||
@@ -1651,17 +1652,19 @@ public class Blocks implements ContentList{
|
||||
float brange = range + 10f;
|
||||
|
||||
ammo(
|
||||
Items.thorium, new ShrapnelBulletType(){{
|
||||
length = brange;
|
||||
damage = 105f;
|
||||
ammoMultiplier = 5f;
|
||||
}},
|
||||
Items.titanium, new ShrapnelBulletType(){{
|
||||
length = brange;
|
||||
damage = 66f;
|
||||
ammoMultiplier = 4f;
|
||||
width = 17f;
|
||||
reloadMultiplier = 1.3f;
|
||||
}},
|
||||
Items.thorium, new ShrapnelBulletType(){{
|
||||
length = brange;
|
||||
damage = 105f;
|
||||
ammoMultiplier = 5f;
|
||||
toColor = Pal.thoriumPink;
|
||||
shootEffect = smokeEffect = Fx.thoriumShoot;
|
||||
}}
|
||||
);
|
||||
}};
|
||||
@@ -2034,7 +2037,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
microProcessor = new LogicBlock("micro-processor"){{
|
||||
requirements(Category.logic, with(Items.copper, 80, Items.lead, 50, Items.silicon, 50));
|
||||
requirements(Category.logic, with(Items.copper, 80, Items.lead, 50, Items.silicon, 30));
|
||||
|
||||
instructionsPerTick = 2;
|
||||
|
||||
@@ -2042,7 +2045,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
logicProcessor = new LogicBlock("logic-processor"){{
|
||||
requirements(Category.logic, with(Items.lead, 320, Items.silicon, 100, Items.graphite, 60, Items.thorium, 50));
|
||||
requirements(Category.logic, with(Items.lead, 320, Items.silicon, 60, Items.graphite, 60, Items.thorium, 50));
|
||||
|
||||
instructionsPerTick = 8;
|
||||
|
||||
@@ -2052,7 +2055,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
hyperProcessor = new LogicBlock("hyper-processor"){{
|
||||
requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgeAlloy, 50));
|
||||
requirements(Category.logic, with(Items.lead, 450, Items.silicon, 130, Items.thorium, 75, Items.surgeAlloy, 50));
|
||||
|
||||
consumes.liquid(Liquids.cryofluid, 0.08f);
|
||||
hasLiquids = true;
|
||||
|
||||
@@ -1217,7 +1217,15 @@ public class Fx{
|
||||
randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 50f, (x, y) -> {
|
||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f);
|
||||
});
|
||||
}),
|
||||
|
||||
thoriumShoot = new Effect(12f, e -> {
|
||||
color(Color.white, Pal.thoriumPink, e.fin());
|
||||
stroke(e.fout() * 1.2f + 0.5f);
|
||||
|
||||
randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 50f, (x, y) -> {
|
||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f);
|
||||
});
|
||||
}),
|
||||
|
||||
reactorsmoke = new Effect(17, e -> {
|
||||
|
||||
@@ -17,6 +17,7 @@ public class SectorPresets implements ContentList{
|
||||
|
||||
groundZero = new SectorPreset("groundZero", serpulo, 15){{
|
||||
alwaysUnlocked = true;
|
||||
addStartingItems = true;
|
||||
captureWave = 10;
|
||||
difficulty = 1;
|
||||
}};
|
||||
|
||||
@@ -6,6 +6,8 @@ import arc.math.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -18,6 +20,7 @@ public class StatusEffects implements ContentList{
|
||||
none = new StatusEffect("none");
|
||||
|
||||
burning = new StatusEffect("burning"){{
|
||||
color = Pal.lightFlame;
|
||||
damage = 0.12f; //over 8 seconds, this would be 60 damage
|
||||
effect = Fx.burning;
|
||||
|
||||
@@ -32,6 +35,7 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
freezing = new StatusEffect("freezing"){{
|
||||
color = Color.valueOf("6ecdec");
|
||||
speedMultiplier = 0.6f;
|
||||
healthMultiplier = 0.8f;
|
||||
effect = Fx.freezing;
|
||||
@@ -47,10 +51,12 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
unmoving = new StatusEffect("unmoving"){{
|
||||
color = Pal.gray;
|
||||
speedMultiplier = 0.001f;
|
||||
}};
|
||||
|
||||
slow = new StatusEffect("slow"){{
|
||||
color = Pal.lightishGray;
|
||||
speedMultiplier = 0.4f;
|
||||
}};
|
||||
|
||||
@@ -80,6 +86,7 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
melting = new StatusEffect("melting"){{
|
||||
color = Color.valueOf("ffa166");
|
||||
speedMultiplier = 0.8f;
|
||||
healthMultiplier = 0.8f;
|
||||
damage = 0.3f;
|
||||
@@ -92,6 +99,7 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
sapped = new StatusEffect("sapped"){{
|
||||
color = Pal.sap;
|
||||
speedMultiplier = 0.7f;
|
||||
healthMultiplier = 0.8f;
|
||||
effect = Fx.sapped;
|
||||
@@ -99,12 +107,14 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
sporeSlowed = new StatusEffect("spore-slowed"){{
|
||||
color = Pal.spore;
|
||||
speedMultiplier = 0.8f;
|
||||
effect = Fx.sapped;
|
||||
effectChance = 0.04f;
|
||||
}};
|
||||
|
||||
tarred = new StatusEffect("tarred"){{
|
||||
color = Color.valueOf("313131");
|
||||
speedMultiplier = 0.6f;
|
||||
effect = Fx.oily;
|
||||
|
||||
@@ -115,6 +125,7 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
overdrive = new StatusEffect("overdrive"){{
|
||||
color = Pal.accent;
|
||||
healthMultiplier = 0.95f;
|
||||
speedMultiplier = 1.15f;
|
||||
damageMultiplier = 1.4f;
|
||||
@@ -124,6 +135,7 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
overclock = new StatusEffect("overclock"){{
|
||||
color = Pal.accent;
|
||||
speedMultiplier = 1.15f;
|
||||
damageMultiplier = 1.15f;
|
||||
reloadMultiplier = 1.25f;
|
||||
@@ -132,20 +144,27 @@ public class StatusEffects implements ContentList{
|
||||
}};
|
||||
|
||||
shielded = new StatusEffect("shielded"){{
|
||||
color = Pal.accent;
|
||||
healthMultiplier = 3f;
|
||||
}};
|
||||
|
||||
boss = new StatusEffect("boss"){{
|
||||
color = Pal.health;
|
||||
permanent = true;
|
||||
damageMultiplier = 2f;
|
||||
healthMultiplier = 2f;
|
||||
}};
|
||||
|
||||
shocked = new StatusEffect("shocked");
|
||||
shocked = new StatusEffect("shocked"){{
|
||||
color = Pal.lancerLaser;
|
||||
}};
|
||||
|
||||
blasted = new StatusEffect("blasted");
|
||||
blasted = new StatusEffect("blasted"){{
|
||||
color = Color.valueOf("ff795e");
|
||||
}};
|
||||
|
||||
corroded = new StatusEffect("corroded"){{
|
||||
color = Pal.plastanium;
|
||||
damage = 0.1f;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -1200,7 +1200,7 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 3;
|
||||
health = 500;
|
||||
armor = 5f;
|
||||
speed = 2.3f;
|
||||
speed = 2.4f;
|
||||
accel = 0.06f;
|
||||
drag = 0.017f;
|
||||
lowAltitude = true;
|
||||
@@ -1770,6 +1770,7 @@ public class UnitTypes implements ContentList{
|
||||
health = 1;
|
||||
rotateSpeed = 360f;
|
||||
itemCapacity = 0;
|
||||
commandLimit = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -39,7 +39,7 @@ public class Weathers implements ContentList{
|
||||
minAlpha = 0f;
|
||||
maxAlpha = 0.2f;
|
||||
density = 1500f;
|
||||
baseSpeed = 6.1f;
|
||||
baseSpeed = 5.4f;
|
||||
attrs.set(Attribute.light, -0.1f);
|
||||
attrs.set(Attribute.water, -0.1f);
|
||||
opacityMultiplier = 0.8f;
|
||||
|
||||
@@ -181,6 +181,12 @@ public class Control implements ApplicationListener, Loadable{
|
||||
Time.run(Fx.coreLand.lifetime, () -> {
|
||||
Fx.launch.at(core);
|
||||
Effect.shake(5f, 5f, core);
|
||||
|
||||
if(state.isCampaign()){
|
||||
ui.announce("[accent]" + state.rules.sector.name() + "\n" +
|
||||
(state.rules.sector.info.resources.any() ? "[lightgray]" + bundle.get("sectors.resources") + "[white] " +
|
||||
state.rules.sector.info.resources.toString(" ", u -> u.emoji()) : ""), 5);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -264,7 +270,6 @@ public class Control implements ApplicationListener, Loadable{
|
||||
slot.load();
|
||||
slot.setAutosave(true);
|
||||
state.rules.sector = sector;
|
||||
state.secinfo = state.rules.sector.info;
|
||||
|
||||
//if there is no base, simulate a new game and place the right loadout at the spawn position
|
||||
if(state.rules.defaultTeam.cores().isEmpty()){
|
||||
@@ -282,8 +287,12 @@ public class Control implements ApplicationListener, Loadable{
|
||||
//reset wave so things are more fair
|
||||
state.wave = 1;
|
||||
|
||||
//reset win wave??
|
||||
state.rules.winWave = sector.preset != null ? sector.preset.captureWave : 40;
|
||||
|
||||
//kill all units, since they should be dead anwyay
|
||||
Groups.unit.clear();
|
||||
Groups.fire.clear();
|
||||
|
||||
Tile spawn = world.tile(sector.info.spawnPosition);
|
||||
Schematics.placeLaunchLoadout(spawn.x, spawn.y);
|
||||
@@ -311,8 +320,8 @@ public class Control implements ApplicationListener, Loadable{
|
||||
world.loadSector(sector);
|
||||
state.rules.sector = sector;
|
||||
//assign origin when launching
|
||||
state.secinfo.origin = origin;
|
||||
state.secinfo.destination = origin;
|
||||
sector.info.origin = origin;
|
||||
sector.info.destination = origin;
|
||||
logic.play();
|
||||
control.saves.saveSector(sector);
|
||||
Events.fire(Trigger.newGame);
|
||||
@@ -403,13 +412,15 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
@Override
|
||||
public void pause(){
|
||||
wasPaused = state.is(State.paused);
|
||||
if(state.is(State.playing)) state.set(State.paused);
|
||||
if(settings.getBool("backgroundpause", true)){
|
||||
wasPaused = state.is(State.paused);
|
||||
if(state.is(State.playing)) state.set(State.paused);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume(){
|
||||
if(state.is(State.paused) && !wasPaused){
|
||||
if(state.is(State.paused) && !wasPaused && settings.getBool("backgroundpause", true)){
|
||||
state.set(State.playing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ public class GameState{
|
||||
public GameStats stats = new GameStats();
|
||||
/** Global attributes of the environment, calculated by weather. */
|
||||
public Attributes envAttrs = new Attributes();
|
||||
/** Sector information. Only valid in the campaign. */
|
||||
public SectorInfo secinfo = new SectorInfo();
|
||||
/** Team data. Gets reset every new game. */
|
||||
public Teams teams = new Teams();
|
||||
/** Number of enemies in the game; only used clientside in servers. */
|
||||
|
||||
@@ -55,15 +55,14 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack));
|
||||
|
||||
//when loading a 'damaged' sector, propagate the damage
|
||||
Events.on(SaveLoadEvent.class, e -> {
|
||||
if(state.isCampaign()){
|
||||
state.secinfo.write();
|
||||
SectorInfo info = state.rules.sector.info;
|
||||
info.write();
|
||||
|
||||
//how much wave time has passed
|
||||
int wavesPassed = state.secinfo.wavesPassed;
|
||||
int wavesPassed = info.wavesPassed;
|
||||
|
||||
//wave has passed, remove all enemies, they are assumed to be dead
|
||||
if(wavesPassed > 0){
|
||||
@@ -84,10 +83,10 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
|
||||
//reset values
|
||||
state.secinfo.damage = 0f;
|
||||
state.secinfo.wavesPassed = 0;
|
||||
state.secinfo.hasCore = true;
|
||||
state.secinfo.secondsPassed = 0;
|
||||
info.damage = 0f;
|
||||
info.wavesPassed = 0;
|
||||
info.hasCore = true;
|
||||
info.secondsPassed = 0;
|
||||
|
||||
state.rules.sector.saveInfo();
|
||||
}
|
||||
@@ -273,7 +272,7 @@ public class Logic implements ApplicationListener{
|
||||
state.teams.updateTeamStats();
|
||||
|
||||
if(state.isCampaign()){
|
||||
state.secinfo.update();
|
||||
state.rules.sector.info.update();
|
||||
}
|
||||
|
||||
if(state.isCampaign()){
|
||||
|
||||
@@ -293,6 +293,13 @@ public class NetClient implements ApplicationListener{
|
||||
setHudText(message);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.both)
|
||||
public static void announce(String message){
|
||||
if(message == null) return;
|
||||
|
||||
ui.announce(message);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.both)
|
||||
public static void infoMessage(String message){
|
||||
if(message == null) return;
|
||||
|
||||
@@ -378,6 +378,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
cont.add(text).pad(2f).growX().wrap().get().setAlignment(Align.center);
|
||||
cont.row();
|
||||
cont.button("@ok", this::hide).size(120, 50).pad(4);
|
||||
closeOnBack();
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -405,6 +406,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
cont.button("@ok", this::hide).size(110, 50).fillX().left();
|
||||
cont.row();
|
||||
cont.add(col).colspan(2).pad(2);
|
||||
closeOnBack();
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -420,6 +422,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
cont.add(text).width(400f).wrap().get().setAlignment(align, align);
|
||||
cont.row();
|
||||
buttons.button("@ok", this::hide).size(110, 50).pad(4);
|
||||
closeOnBack();
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -427,6 +430,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
new Dialog(titleText){{
|
||||
cont.margin(15).add(text).width(400f).wrap().left().get().setAlignment(Align.left, Align.left);
|
||||
buttons.button("@ok", this::hide).size(110, 50).pad(4);
|
||||
closeOnBack();
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -436,6 +440,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
titleTable.row();
|
||||
titleTable.image().color(Pal.accent).height(3f).growX().pad(2f);
|
||||
buttons.button("@ok", this::hide).size(110, 50).pad(4);
|
||||
closeOnBack();
|
||||
}}.show();
|
||||
}
|
||||
|
||||
@@ -487,13 +492,19 @@ public class UI implements ApplicationListener, Loadable{
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
/** Display text in the middle of the screen, then fade out. */
|
||||
public void announce(String text){
|
||||
Table t = new Table();
|
||||
announce(text, 3);
|
||||
}
|
||||
|
||||
/** Display text in the middle of the screen, then fade out. */
|
||||
public void announce(String text, float duration){
|
||||
Table t = new Table(Styles.black3);
|
||||
t.touchable = Touchable.disabled;
|
||||
t.background(Styles.black3).margin(8f)
|
||||
.add(text).style(Styles.outlineLabel).labelAlign(Align.center);
|
||||
t.margin(8f).add(text).style(Styles.outlineLabel).labelAlign(Align.center);
|
||||
t.update(() -> t.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Align.center));
|
||||
t.actions(Actions.fadeOut(3, Interp.pow4In), Actions.remove());
|
||||
t.actions(Actions.fadeOut(duration, Interp.pow4In), Actions.remove());
|
||||
t.pack();
|
||||
Core.scene.add(t);
|
||||
}
|
||||
|
||||
|
||||
@@ -570,7 +570,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}).growX().top();
|
||||
}
|
||||
|
||||
if(addCliffButton){
|
||||
if(experimental){
|
||||
mid.row();
|
||||
|
||||
mid.table(t -> {
|
||||
|
||||
@@ -34,9 +34,7 @@ public class WaveInfoDialog extends BaseDialog{
|
||||
super("@waves.title");
|
||||
|
||||
shown(this::setup);
|
||||
hidden(() -> {
|
||||
state.rules.spawns = groups;
|
||||
});
|
||||
hidden(() -> state.rules.spawns = groups);
|
||||
|
||||
addCloseListener();
|
||||
|
||||
@@ -96,6 +94,14 @@ public class WaveInfoDialog extends BaseDialog{
|
||||
view(1);
|
||||
}
|
||||
});
|
||||
|
||||
if(experimental){
|
||||
buttons.button("Random", Icon.refresh, () -> {
|
||||
groups.clear();
|
||||
groups = DefaultWaves.generate(1f / 10f);
|
||||
updateWaves();
|
||||
}).width(200f);
|
||||
}
|
||||
}
|
||||
|
||||
void view(int amount){
|
||||
|
||||
@@ -11,5 +11,6 @@ class GroupDefs<G>{
|
||||
@GroupDef(value = Buildingc.class) G build;
|
||||
@GroupDef(value = Syncc.class, mapping = true) G sync;
|
||||
@GroupDef(value = Drawc.class) G draw;
|
||||
@GroupDef(value = Firec.class) G fire;
|
||||
@GroupDef(value = WeatherStatec.class) G weather;
|
||||
}
|
||||
|
||||
@@ -869,7 +869,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
public void placed(){
|
||||
if(net.client()) return;
|
||||
|
||||
if((block.consumesPower && !block.outputsPower) || (!block.consumesPower && block.outputsPower)){
|
||||
if(block.consumesPower || block.outputsPower){
|
||||
int range = 10;
|
||||
tempTiles.clear();
|
||||
Geometry.circle(tileX(), tileY(), range, (x, y) -> {
|
||||
@@ -1319,7 +1319,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
@Override
|
||||
public void control(LAccess type, Object p1, double p2, double p3, double p4){
|
||||
|
||||
if(type == LAccess.configure && block.logicConfigurable){
|
||||
//change config only if it's new
|
||||
Object prev = senseObject(LAccess.config);
|
||||
if(prev != p1){
|
||||
configureAny(p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -32,12 +32,16 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
}
|
||||
|
||||
boolean mining(){
|
||||
return mineTile != null && !(((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding());
|
||||
return mineTile != null && !(((Object)this) instanceof Builderc b && b.activelyBuilding());
|
||||
}
|
||||
|
||||
public boolean validMine(Tile tile, boolean checkDst){
|
||||
return !(tile == null || tile.block() != Blocks.air || (!within(tile.worldx(), tile.worldy(), miningRange) && checkDst)
|
||||
|| tile.drop() == null || !canMine(tile.drop())) && state.teams.canMine(self(), tile);
|
||||
}
|
||||
|
||||
public boolean validMine(Tile tile){
|
||||
return !(tile == null || tile.block() != Blocks.air || !within(tile.worldx(), tile.worldy(), miningRange)
|
||||
|| tile.drop() == null || !canMine(tile.drop()));
|
||||
return validMine(tile, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,6 +62,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
mineTile = null;
|
||||
mineTimer = 0f;
|
||||
}else if(mining()){
|
||||
state.teams.registerMined(mineTile, self());
|
||||
Item item = mineTile.drop();
|
||||
lookAt(angleTo(mineTile.worldx(), mineTile.worldy()));
|
||||
mineTimer += Time.delta *type.mineSpeed;
|
||||
@@ -84,8 +89,6 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
mineTimer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
team = state.rules.defaultTeam;
|
||||
admin = typing = false;
|
||||
textFadeTime = 0f;
|
||||
x = y = 0f;
|
||||
if(!dead()){
|
||||
unit.controller(unit.type.createController());
|
||||
unit = Nulls.unit;
|
||||
|
||||
@@ -114,13 +114,14 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
StatusEntry entry = statuses.get(index++);
|
||||
|
||||
entry.time = Math.max(entry.time - Time.delta, 0);
|
||||
applied.set(entry.effect.id);
|
||||
|
||||
if(entry.time <= 0 && !entry.effect.permanent){
|
||||
if(entry.effect == null || (entry.time <= 0 && !entry.effect.permanent)){
|
||||
Pools.free(entry);
|
||||
index --;
|
||||
statuses.remove(index);
|
||||
}else{
|
||||
applied.set(entry.effect.id);
|
||||
|
||||
speedMultiplier *= entry.effect.speedMultiplier;
|
||||
healthMultiplier *= entry.effect.healthMultiplier;
|
||||
damageMultiplier *= entry.effect.damageMultiplier;
|
||||
|
||||
@@ -160,7 +160,7 @@ public class AIController implements UnitController{
|
||||
}
|
||||
|
||||
protected boolean retarget(){
|
||||
return timer.get(timerTarget, 30);
|
||||
return timer.get(timerTarget, 40);
|
||||
}
|
||||
|
||||
protected Teamc findTarget(float x, float y, float range, boolean air, boolean ground){
|
||||
|
||||
@@ -262,9 +262,7 @@ public class DefaultWaves{
|
||||
{dagger, mace, fortress, scepter, reign},
|
||||
{nova, pulsar, quasar, vela, corvus},
|
||||
{crawler, atrax, spiroct, arkyid, toxopid},
|
||||
//{risso, minke, bryde, sei, omura}, //questionable choices
|
||||
{flare, horizon, difficulty > 0.5 ? poly : zenith, quad, quad},
|
||||
{flare, horizon, zenith, antumbra, eclipse}
|
||||
{flare, horizon, rand.chance(0.2) && difficulty > 0.5 ? poly : zenith, rand.chance(0.5) ? quad : antumbra, rand.chance(0.1) ? quad : eclipse}
|
||||
};
|
||||
|
||||
//required progression:
|
||||
@@ -276,6 +274,7 @@ public class DefaultWaves{
|
||||
int cap = 150;
|
||||
|
||||
float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f;
|
||||
float[] scaling = {1, 1, 1.5f, 3f, 4f};
|
||||
|
||||
Intc createProgression = start -> {
|
||||
//main sequence
|
||||
@@ -284,18 +283,19 @@ public class DefaultWaves{
|
||||
|
||||
for(int i = start; i < cap;){
|
||||
int f = i;
|
||||
int next = rand.random(8, 16);
|
||||
int next = rand.random(8, 16) + curTier * 4;
|
||||
|
||||
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
|
||||
int space = start == 0 ? 1 : rand.random(1, 2);
|
||||
int ctier = curTier;
|
||||
|
||||
//main progression
|
||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||
unitAmount = f == 0 ? 1 : 10;
|
||||
unitAmount = f == start ? 1 : 6 / (int)scaling[ctier];
|
||||
begin = f;
|
||||
end = f + next >= cap ? never : f + next;
|
||||
max = 14;
|
||||
unitScaling = rand.random(1f, 3f);
|
||||
unitScaling = (difficulty < 0.4f ? rand.random(2f, 4f) : rand.random(1f, 3f)) * scaling[ctier];
|
||||
shields = shieldAmount;
|
||||
shieldScaling = shieldsPerWave;
|
||||
spacing = space;
|
||||
@@ -303,18 +303,18 @@ public class DefaultWaves{
|
||||
|
||||
//extra progression that tails out, blends in
|
||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||
unitAmount = 6;
|
||||
begin = f + next;
|
||||
end = f + next + rand.random(8, 12);
|
||||
max = 11;
|
||||
unitScaling = rand.random(2f);
|
||||
spacing = rand.random(2, 3);
|
||||
shields = shieldAmount;
|
||||
unitAmount = 3 / (int)scaling[ctier];
|
||||
begin = f + next - 1;
|
||||
end = f + next + rand.random(6, 10);
|
||||
max = 6;
|
||||
unitScaling = rand.random(1f, 2f);
|
||||
spacing = rand.random(2, 4);
|
||||
shields = shieldAmount/2f;
|
||||
shieldScaling = shieldsPerWave;
|
||||
}});
|
||||
|
||||
i += next;
|
||||
if(curTier < 3 || rand.chance(0.2)){
|
||||
i += next + 1;
|
||||
if(curTier < 3 || rand.chance(0.05)){
|
||||
curTier ++;
|
||||
}
|
||||
|
||||
@@ -330,11 +330,11 @@ public class DefaultWaves{
|
||||
|
||||
createProgression.get(0);
|
||||
|
||||
int step = 5 + rand.random(3);
|
||||
int step = 5 + rand.random(5);
|
||||
|
||||
while(step <= cap){
|
||||
createProgression.get(step);
|
||||
step += (int)(rand.random(13, 25) * Mathf.lerp(1f, 0.5f, difficulty));
|
||||
step += (int)(rand.random(15, 30) * Mathf.lerp(1f, 0.5f, difficulty));
|
||||
}
|
||||
|
||||
int bossWave = (int)(rand.random(30, 60) * Mathf.lerp(1f, 0.7f, difficulty));
|
||||
|
||||
@@ -38,7 +38,7 @@ public class Objectives{
|
||||
|
||||
@Override
|
||||
public boolean complete(){
|
||||
return preset.sector.save != null && preset.sector.save.meta.wave >= preset.captureWave;
|
||||
return preset.sector.save != null && !preset.sector.isAttacked() && preset.sector.hasBase();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -288,6 +288,10 @@ public class Schematics implements Loadable{
|
||||
return loadouts.get(block, Seq::new);
|
||||
}
|
||||
|
||||
public ObjectMap<CoreBlock, Seq<Schematic>> getLoadouts(){
|
||||
return loadouts;
|
||||
}
|
||||
|
||||
/** Checks a schematic for deployment validity and adds it to the cache. */
|
||||
private void checkLoadout(Schematic s, boolean validate){
|
||||
Stile core = s.tiles.find(t -> t.block instanceof CoreBlock);
|
||||
|
||||
@@ -156,7 +156,6 @@ public class SectorInfo{
|
||||
damage = 0;
|
||||
|
||||
if(state.rules.sector != null){
|
||||
state.rules.sector.info = this;
|
||||
state.rules.sector.saveInfo();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import mindustry.content.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
@@ -26,6 +27,8 @@ public class Teams{
|
||||
public Seq<TeamData> active = new Seq<>();
|
||||
/** Teams with block or unit presence. */
|
||||
public Seq<TeamData> present = new Seq<>(TeamData.class);
|
||||
/** Ores currently being mined. */
|
||||
private IntMap<Unit> mined = new IntMap<>();
|
||||
|
||||
public Teams(){
|
||||
active.add(get(Team.crux));
|
||||
@@ -142,7 +145,20 @@ public class Teams{
|
||||
}
|
||||
}
|
||||
|
||||
/** @return whether this ore is taken. */
|
||||
public boolean canMine(Unit unit, Tile tile){
|
||||
if(tile == null) return false;
|
||||
Unit u = mined.get(tile.pos());
|
||||
return u == unit || u == null;
|
||||
}
|
||||
|
||||
public void registerMined(Tile tile, Unit unit){
|
||||
if(tile == null || unit == null) return;
|
||||
mined.put(tile.pos(), unit);
|
||||
}
|
||||
|
||||
public void updateTeamStats(){
|
||||
mined.clear();
|
||||
present.clear();
|
||||
|
||||
for(Team team : Team.all){
|
||||
|
||||
@@ -197,7 +197,7 @@ public class Universe{
|
||||
if(!sector.isAttacked() && turn > invasionGracePeriod){
|
||||
//invasion chance depends on # of nearby bases
|
||||
if(Mathf.chance(baseInvasionChance * sector.near().count(Sector::hasEnemyBase))){
|
||||
int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : 0) + Mathf.random(2, 5) * 5;
|
||||
int waveMax = Math.max(sector.info.winWave, state.wave) + Mathf.random(2, 5) * 5;
|
||||
|
||||
//assign invasion-related things
|
||||
if(sector.isBeingPlayed()){
|
||||
|
||||
@@ -5,6 +5,8 @@ import arc.graphics.*;
|
||||
public class Pal{
|
||||
public static Color
|
||||
|
||||
thoriumPink = Color.valueOf("f9a3c7"),
|
||||
|
||||
items = Color.valueOf("2ea756"),
|
||||
command = Color.valueOf("eab678"),
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
if(isPlacing() && mode == placing){
|
||||
updateLine(selectX, selectY);
|
||||
}else if(!selectRequests.isEmpty()){
|
||||
}else if(!selectRequests.isEmpty() && !ui.chatfrag.shown()){
|
||||
rotateRequests(selectRequests, Mathf.sign(Core.input.axisTap(Binding.rotate)));
|
||||
}
|
||||
}
|
||||
@@ -660,7 +660,7 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
|
||||
//update commander unit
|
||||
if(Core.input.keyTap(Binding.command)){
|
||||
if(Core.input.keyTap(Binding.command) && unit.type.commandLimit > 0){
|
||||
Call.unitCommand(player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,6 +336,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
public static void unitControl(Player player, @Nullable Unit unit){
|
||||
if(player == null) return;
|
||||
|
||||
//make sure player is allowed to control the unit
|
||||
if(net.server() && !netServer.admins.allowAction(player, ActionType.control, action -> action.unit = unit)){
|
||||
throw new ValidateException(player, "Player cannot control a unit.");
|
||||
}
|
||||
|
||||
//clear player unit when they possess a core
|
||||
if((unit instanceof BlockUnitc && ((BlockUnitc)unit).tile() instanceof CoreBuild)){
|
||||
Fx.spawn.at(player);
|
||||
@@ -376,6 +381,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
public static void unitCommand(Player player){
|
||||
if(player == null || player.dead() || !(player.unit() instanceof Commanderc commander)) return;
|
||||
|
||||
//make sure player is allowed to make the command
|
||||
if(net.server() && !netServer.admins.allowAction(player, ActionType.command, action -> {})){
|
||||
throw new ValidateException(player, "Player cannot command a unit.");
|
||||
}
|
||||
|
||||
if(commander.isCommanding()){
|
||||
commander.clearCommand();
|
||||
}else if(player.unit().type.commandLimit > 0){
|
||||
@@ -935,10 +945,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
|
||||
boolean canMine(Tile tile){
|
||||
return !Core.scene.hasMouse()
|
||||
&& tile.drop() != null && player.miner().canMine(tile.drop())
|
||||
&& tile.drop() != null
|
||||
&& player.miner().validMine(tile)
|
||||
&& !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null)
|
||||
&& player.unit().acceptsItem(tile.drop())
|
||||
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= miningRange;
|
||||
&& tile.block() == Blocks.air;
|
||||
}
|
||||
|
||||
/** Returns the tile at the specified MOUSE coordinates. */
|
||||
@@ -1203,7 +1214,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
line.x = point.x;
|
||||
line.y = point.y;
|
||||
if(!overrideLineRotation || diagonal){
|
||||
line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation;
|
||||
if(next != null){
|
||||
line.rotation = Tile.relativeTo(point.x, point.y, next.x, next.y);
|
||||
}else if(block.conveyorPlacement && i > 0){
|
||||
Point2 prev = points.get(i - 1);
|
||||
line.rotation = Tile.relativeTo(prev.x, prev.y, point.x, point.y);
|
||||
}else{
|
||||
line.rotation = baseRotation;
|
||||
}
|
||||
}else{
|
||||
line.rotation = rotation;
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
//reset payload target
|
||||
payloadTarget = null;
|
||||
//apply command on double tap when own unit is tapped
|
||||
if(Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f)){
|
||||
if(!player.dead() && Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f) && player.unit().type.commandLimit > 0){
|
||||
Call.unitCommand(player);
|
||||
}else{
|
||||
//control a unit/block
|
||||
|
||||
@@ -72,7 +72,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
public void writeMeta(DataOutput stream, StringMap tags) throws IOException{
|
||||
//prepare campaign data for writing
|
||||
if(state.isCampaign()){
|
||||
state.secinfo.prepare();
|
||||
state.rules.sector.info.prepare();
|
||||
state.rules.sector.saveInfo();
|
||||
}
|
||||
|
||||
@@ -110,11 +110,6 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
|
||||
lastReadBuild = map.getInt("build", -1);
|
||||
|
||||
//load in sector info
|
||||
if(state.rules.sector != null){
|
||||
state.secinfo = state.rules.sector.info;
|
||||
}
|
||||
|
||||
if(!headless){
|
||||
Tmp.v1.tryFromString(map.get("viewpos"));
|
||||
Core.camera.position.set(Tmp.v1);
|
||||
|
||||
@@ -38,12 +38,15 @@ public enum LAccess{
|
||||
//values with parameters are considered controllable
|
||||
enabled("to"), //"to" is standard for single parameter access
|
||||
shoot("x", "y", "shoot"),
|
||||
shootp(true, "unit", "shoot")
|
||||
shootp(true, "unit", "shoot"),
|
||||
configure(true, 30, "to")
|
||||
|
||||
;
|
||||
|
||||
public final String[] params;
|
||||
public final boolean isObj;
|
||||
/** Tick cooldown between invocations. */
|
||||
public float cooldown = -1;
|
||||
|
||||
public static final LAccess[]
|
||||
all = values(),
|
||||
@@ -59,4 +62,10 @@ public enum LAccess{
|
||||
this.params = params;
|
||||
isObj = obj;
|
||||
}
|
||||
|
||||
LAccess(boolean obj, float cooldown, String... params){
|
||||
this.params = params;
|
||||
this.cooldown = cooldown;
|
||||
isObj = obj;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ public class LExecutor{
|
||||
this.outX = outX;
|
||||
this.outY = outY;
|
||||
this.outFound = outFound;
|
||||
this.outBuild = outBuild;
|
||||
}
|
||||
|
||||
public UnitLocateI(){
|
||||
@@ -245,7 +246,7 @@ public class LExecutor{
|
||||
switch(locate){
|
||||
case ore -> {
|
||||
if(exec.obj(ore) instanceof Item item){
|
||||
res = indexer.findClosestOre(unit.x, unit.y, item);
|
||||
res = indexer.findClosestOre(unit, item);
|
||||
}
|
||||
}
|
||||
case building -> {
|
||||
@@ -272,8 +273,9 @@ public class LExecutor{
|
||||
cache.found = false;
|
||||
exec.setnum(outFound, 0);
|
||||
}
|
||||
exec.setobj(outFound, res != null && res.build != null && res.build.team == exec.team ? res.build : null);
|
||||
exec.setobj(outBuild, res != null && res.build != null && res.build.team == exec.team ? cache.build = res.build : null);
|
||||
}else{
|
||||
exec.setobj(outBuild, cache.build);
|
||||
exec.setbool(outFound, cache.found);
|
||||
exec.setnum(outX, cache.x);
|
||||
exec.setnum(outY, cache.y);
|
||||
@@ -284,20 +286,22 @@ public class LExecutor{
|
||||
static class Cache{
|
||||
float x, y;
|
||||
boolean found;
|
||||
Building build;
|
||||
}
|
||||
}
|
||||
|
||||
/** Controls the unit based on some parameters. */
|
||||
public static class UnitControlI implements LInstruction{
|
||||
public LUnitControl type = LUnitControl.move;
|
||||
public int p1, p2, p3, p4;
|
||||
public int p1, p2, p3, p4, p5;
|
||||
|
||||
public UnitControlI(LUnitControl type, int p1, int p2, int p3, int p4){
|
||||
public UnitControlI(LUnitControl type, int p1, int p2, int p3, int p4, int p5){
|
||||
this.type = type;
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.p3 = p3;
|
||||
this.p4 = p4;
|
||||
this.p5 = p5;
|
||||
}
|
||||
|
||||
public UnitControlI(){
|
||||
@@ -435,7 +439,7 @@ public class LExecutor{
|
||||
}
|
||||
|
||||
ai.plan.set(x, y, rot, block);
|
||||
ai.plan.config = null;
|
||||
ai.plan.config = exec.obj(p5) instanceof Content c ? c : null;
|
||||
|
||||
builder.clearBuilding();
|
||||
|
||||
@@ -462,9 +466,8 @@ public class LExecutor{
|
||||
if(ai.itemTimer > 0) return;
|
||||
|
||||
Building build = exec.building(p1);
|
||||
int amount = exec.numi(p2);
|
||||
int dropped = Math.min(unit.stack.amount, amount);
|
||||
if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange)){
|
||||
int dropped = Math.min(unit.stack.amount, exec.numi(p2));
|
||||
if(build != null && dropped > 0 && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){
|
||||
int accepted = build.acceptStack(unit.item(), dropped, unit);
|
||||
if(accepted > 0){
|
||||
Call.transferItemTo(unit, unit.item(), accepted, unit.x, unit.y, build);
|
||||
@@ -478,7 +481,7 @@ public class LExecutor{
|
||||
Building build = exec.building(p1);
|
||||
int amount = exec.numi(p3);
|
||||
|
||||
if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){
|
||||
if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange + build.block.size * tilesize/2f)){
|
||||
int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item)));
|
||||
|
||||
if(taken > 0){
|
||||
@@ -498,6 +501,7 @@ public class LExecutor{
|
||||
public int target;
|
||||
public LAccess type = LAccess.enabled;
|
||||
public int p1, p2, p3, p4;
|
||||
public Interval timer = new Interval(1);
|
||||
|
||||
public ControlI(LAccess type, int target, int p1, int p2, int p3, int p4){
|
||||
this.type = type;
|
||||
@@ -513,7 +517,7 @@ public class LExecutor{
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
Object obj = exec.obj(target);
|
||||
if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id)){
|
||||
if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id) && (type.cooldown <= 0 || timer.get(type.cooldown))){
|
||||
if(type.isObj){
|
||||
b.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4));
|
||||
}else{
|
||||
@@ -872,10 +876,11 @@ public class LExecutor{
|
||||
if(v.isobj && value != 0){
|
||||
String strValue =
|
||||
v.objval == null ? "null" :
|
||||
v.objval instanceof String ? (String)v.objval :
|
||||
v.objval instanceof String s ? s :
|
||||
v.objval instanceof MappableContent content ? content.name :
|
||||
v.objval instanceof Content ? "[content]" :
|
||||
v.objval instanceof Building ? "[building]" :
|
||||
v.objval instanceof Unit ? "[unit]" :
|
||||
v.objval instanceof Building build ? build.block.name :
|
||||
v.objval instanceof Unit unit ? unit.type.name :
|
||||
"[object]";
|
||||
|
||||
exec.textBuffer.append(strValue);
|
||||
|
||||
@@ -748,7 +748,7 @@ public class LStatements{
|
||||
@RegisterStatement("ucontrol")
|
||||
public static class UnitControlStatement extends LStatement{
|
||||
public LUnitControl type = LUnitControl.move;
|
||||
public String p1 = "0", p2 = "0", p3 = "0", p4 = "0";
|
||||
public String p1 = "0", p2 = "0", p3 = "0", p4 = "0", p5 = "0";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
@@ -777,9 +777,13 @@ public class LStatements{
|
||||
int c = 0;
|
||||
for(int i = 0; i < type.params.length; i++){
|
||||
|
||||
fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : p4, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : v -> p4 = v).width(110f);
|
||||
fields(table, type.params[i], i == 0 ? p1 : i == 1 ? p2 : i == 2 ? p3 : i == 3 ? p4 : p5, i == 0 ? v -> p1 = v : i == 1 ? v -> p2 = v : i == 2 ? v -> p3 = v : i == 3 ? v -> p4 = v : v -> p5 = v).width(100f);
|
||||
|
||||
if(++c % 2 == 0) row(table);
|
||||
|
||||
if(i == 3){
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -790,7 +794,7 @@ public class LStatements{
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new UnitControlI(type, builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4));
|
||||
return new UnitControlI(type, builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4), builder.var(p5));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,7 +865,7 @@ public class LStatements{
|
||||
table.table(ts -> {
|
||||
ts.color.set(table.color);
|
||||
|
||||
field(ts, ore, str -> ore = str);
|
||||
fields(ts, ore, str -> ore = str);
|
||||
|
||||
ts.button(b -> {
|
||||
b.image(Icon.pencilSmall);
|
||||
@@ -905,8 +909,10 @@ public class LStatements{
|
||||
table.add(" found ").left();
|
||||
fields(table, outFound, str -> outFound = str);
|
||||
|
||||
table.add(" building ").left();
|
||||
fields(table, outBuild, str -> outBuild = str);
|
||||
if(locate != LLocate.ore){
|
||||
table.add(" building ").left();
|
||||
fields(table, outBuild, str -> outBuild = str);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public enum LUnitControl{
|
||||
payTake("takeUnits"),
|
||||
mine("x", "y"),
|
||||
flag("value"),
|
||||
build("x", "y", "block", "rotation"),
|
||||
build("x", "y", "block", "rotation", "config"),
|
||||
getBlock("x", "y", "type", "building"),
|
||||
within("x", "y", "radius", "result");
|
||||
|
||||
|
||||
@@ -82,13 +82,13 @@ public class SectorDamage{
|
||||
/** Applies wave damage based on sector parameters. */
|
||||
public static void applyCalculatedDamage(){
|
||||
//calculate base damage fraction
|
||||
float damage = getDamage(state.secinfo);
|
||||
float damage = getDamage(state.rules.sector.info);
|
||||
|
||||
//scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
|
||||
float scaled = Mathf.pow(damage, 1.5f);
|
||||
|
||||
//apply damage to units
|
||||
float unitDamage = damage * state.secinfo.sumHealth;
|
||||
float unitDamage = damage * state.rules.sector.info.sumHealth;
|
||||
Tile spawn = spawner.getFirstSpawn();
|
||||
|
||||
//damage only units near the spawn point
|
||||
@@ -114,7 +114,7 @@ public class SectorDamage{
|
||||
}
|
||||
}
|
||||
|
||||
if(state.secinfo.wavesPassed > 0){
|
||||
if(state.rules.sector.info.wavesPassed > 0){
|
||||
//simply remove each block in the spawner range if a wave passed
|
||||
for(Tile spawner : spawner.getSpawns()){
|
||||
spawner.circle((int)(state.rules.dropZoneRadius / tilesize), tile -> {
|
||||
@@ -207,7 +207,7 @@ public class SectorDamage{
|
||||
//first, calculate the total health of blocks in the path
|
||||
|
||||
//radius around the path that gets counted
|
||||
int radius = 7;
|
||||
int radius = 9;
|
||||
IntSet counted = new IntSet();
|
||||
|
||||
for(Tile t : sparse2){
|
||||
|
||||
@@ -37,7 +37,7 @@ public abstract class GenerateFilter{
|
||||
apply();
|
||||
|
||||
tile.setFloor(in.floor.asFloor());
|
||||
tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay);
|
||||
tile.setOverlay(!in.floor.asFloor().hasSurface() && in.overlay.asFloor().needsSurface ? Blocks.air : in.overlay);
|
||||
|
||||
if(!tile.block().synthetic() && !in.block.synthetic()){
|
||||
tile.setBlock(in.block);
|
||||
@@ -49,7 +49,7 @@ public abstract class GenerateFilter{
|
||||
apply();
|
||||
|
||||
tile.setFloor(in.floor.asFloor());
|
||||
tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay);
|
||||
tile.setOverlay(!in.floor.asFloor().hasSurface() && in.overlay.asFloor().needsSurface ? Blocks.air : in.overlay);
|
||||
|
||||
if(!tile.block().synthetic() && !in.block.synthetic()){
|
||||
tile.setBlock(in.block);
|
||||
|
||||
@@ -14,9 +14,11 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class FileMapGenerator implements WorldGenerator{
|
||||
public final Map map;
|
||||
public final SectorPreset preset;
|
||||
|
||||
public FileMapGenerator(String mapName){
|
||||
public FileMapGenerator(String mapName, SectorPreset preset){
|
||||
this.map = maps != null ? maps.loadInternalMap(mapName) : null;
|
||||
this.preset = preset;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,6 +58,10 @@ public class FileMapGenerator implements WorldGenerator{
|
||||
if(tile.isCenter() && tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam && !anyCores){
|
||||
Schematics.placeLaunchLoadout(tile.x, tile.y);
|
||||
anyCores = true;
|
||||
|
||||
if(preset.addStartingItems){
|
||||
tile.build.items.add(state.rules.loadout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -569,7 +569,9 @@ public class ContentParser{
|
||||
if(field.field.getType().isPrimitive()) return;
|
||||
|
||||
if(!field.field.isAnnotationPresent(Nullable.class) && field.field.get(object) == null && !implicitNullable.contains(field.field.getType())){
|
||||
throw new RuntimeException("'" + field.field.getName() + "' in " + object.getClass().getSimpleName() + " is missing!");
|
||||
throw new RuntimeException("'" + field.field.getName() + "' in " +
|
||||
((object.getClass().isAnonymousClass() ? object.getClass().getSuperclass() : object.getClass()).getSimpleName()) +
|
||||
" is missing! Object = " + object + ", field = (" + field.field.getName() + " = " + field.field.get(object) + ")");
|
||||
}
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -142,11 +142,18 @@ public class Administration{
|
||||
|
||||
/** @return whether this action is allowed by the action filters. */
|
||||
public boolean allowAction(Player player, ActionType type, Tile tile, Cons<PlayerAction> setter){
|
||||
return allowAction(player, type, action -> setter.get(action.set(player, type, tile)));
|
||||
}
|
||||
|
||||
/** @return whether this action is allowed by the action filters. */
|
||||
public boolean allowAction(Player player, ActionType type, Cons<PlayerAction> setter){
|
||||
//some actions are done by the server (null player) and thus are always allowed
|
||||
if(player == null) return true;
|
||||
|
||||
PlayerAction act = Pools.obtain(PlayerAction.class, PlayerAction::new);
|
||||
setter.get(act.set(player, type, tile));
|
||||
act.player = player;
|
||||
act.type = type;
|
||||
setter.get(act);
|
||||
for(ActionFilter filter : actionFilters){
|
||||
if(!filter.allow(act)){
|
||||
Pools.free(act);
|
||||
@@ -699,7 +706,7 @@ public class Administration{
|
||||
public static class PlayerAction implements Poolable{
|
||||
public Player player;
|
||||
public ActionType type;
|
||||
public Tile tile;
|
||||
public @Nullable Tile tile;
|
||||
|
||||
/** valid for block placement events only */
|
||||
public @Nullable Block block;
|
||||
@@ -712,6 +719,9 @@ public class Administration{
|
||||
public @Nullable Item item;
|
||||
public int itemAmount;
|
||||
|
||||
/** valid for unit-type events only, and even in that case may be null. */
|
||||
public @Nullable Unit unit;
|
||||
|
||||
public PlayerAction set(Player player, ActionType type, Tile tile){
|
||||
this.player = player;
|
||||
this.type = type;
|
||||
@@ -719,6 +729,13 @@ public class Administration{
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlayerAction set(Player player, ActionType type, Unit unit){
|
||||
this.player = player;
|
||||
this.type = type;
|
||||
this.unit = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
item = null;
|
||||
@@ -728,11 +745,12 @@ public class Administration{
|
||||
type = null;
|
||||
tile = null;
|
||||
block = null;
|
||||
unit = null;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ActionType{
|
||||
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem
|
||||
breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem, control, command
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@ public class SectorPreset extends UnlockableContent{
|
||||
public Cons<Rules> rules = rules -> rules.winWave = captureWave;
|
||||
/** Difficulty, 0-10. */
|
||||
public float difficulty;
|
||||
public boolean addStartingItems = false;
|
||||
|
||||
public SectorPreset(String name, Planet planet, int sector){
|
||||
super(name);
|
||||
this.generator = new FileMapGenerator(name);
|
||||
this.generator = new FileMapGenerator(name, this);
|
||||
this.planet = planet;
|
||||
sector %= planet.sectors.size;
|
||||
this.sector = planet.sectors.get(sector);
|
||||
|
||||
@@ -199,7 +199,7 @@ public class UnitType extends UnlockableContent{
|
||||
|
||||
stats.add(Stat.health, health);
|
||||
stats.add(Stat.speed, speed);
|
||||
stats.add(Stat.itemCapacity, health);
|
||||
stats.add(Stat.itemCapacity, itemCapacity);
|
||||
stats.add(Stat.range, (int)(maxRange / tilesize), StatUnit.blocks);
|
||||
stats.add(Stat.commandLimit, commandLimit);
|
||||
//TODO abilities, maybe try something like DPS
|
||||
|
||||
@@ -50,7 +50,7 @@ public class Weapon{
|
||||
public float x = 5f, y = 0f;
|
||||
/** random spread on the X axis */
|
||||
public float xRand = 0f;
|
||||
/** radius of occlusion drawn under the weapon; <0 to diable */
|
||||
/** radius of occlusion drawn under the weapon; <0 to disable */
|
||||
public float occlusion = -1f;
|
||||
/** fraction of velocity that is random */
|
||||
public float velocityRnd = 0f;
|
||||
|
||||
@@ -74,7 +74,7 @@ public class ParticleWeather extends Weather{
|
||||
float sspeed = 1f, sscl = 1f, salpha = 1f, offset = 0f;
|
||||
Color col = Tmp.c1.set(noiseColor);
|
||||
for(int i = 0; i < noiseLayers; i++){
|
||||
drawNoise(noise, noiseColor, noiseScale * sscl, state.opacity * salpha * opacityMultiplier, baseSpeed * sspeed, state.intensity, windx, windy, offset);
|
||||
drawNoise(noise, noiseColor, noiseScale * sscl, state.opacity * salpha * opacityMultiplier, sspeed * (useWindVector ? 1f : baseSpeed), state.intensity, windx, windy, offset);
|
||||
sspeed *= noiseLayerSpeedM;
|
||||
salpha *= noiseLayerAlphaM;
|
||||
sscl *= noiseLayerSclM;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import arc.input.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.util.*;
|
||||
import mindustry.core.GameState.*;
|
||||
@@ -54,11 +53,7 @@ public class BaseDialog extends Dialog{
|
||||
}
|
||||
|
||||
public void addCloseListener(){
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.escape || key == KeyCode.back){
|
||||
Core.app.post(this::hide);
|
||||
}
|
||||
});
|
||||
closeOnBack();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -99,18 +99,24 @@ public class LaunchLoadoutDialog extends BaseDialog{
|
||||
cont.pane(t -> {
|
||||
int i = 0;
|
||||
|
||||
for(Schematic s : schematics.getLoadouts(core)){
|
||||
for(var entry : schematics.getLoadouts()){
|
||||
if(entry.key.size <= core.size){
|
||||
for(Schematic s : entry.value){
|
||||
|
||||
t.button(b -> b.add(new SchematicImage(s)), Styles.togglet, () -> {
|
||||
selected = s;
|
||||
update.run();
|
||||
rebuildItems.run();
|
||||
}).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f);
|
||||
t.button(b -> b.add(new SchematicImage(s)), Styles.togglet, () -> {
|
||||
selected = s;
|
||||
update.run();
|
||||
rebuildItems.run();
|
||||
}).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f);
|
||||
|
||||
if(++i % cols == 0){
|
||||
t.row();
|
||||
if(++i % cols == 0){
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}).growX().get().setScrollingDisabled(true, false);
|
||||
|
||||
cont.row();
|
||||
|
||||
@@ -49,6 +49,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
|
||||
shouldPause = true;
|
||||
|
||||
addCloseListener();
|
||||
|
||||
buttons.defaults().size(200f, 56f).pad(2);
|
||||
buttons.button("@back", Icon.left, this::hide);
|
||||
buttons.button("@techtree", Icon.tree, () -> ui.research.show());
|
||||
@@ -242,7 +244,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
addListener(new ElementGestureListener(){
|
||||
@Override
|
||||
public void tap(InputEvent event, float x, float y, int count, KeyCode button){
|
||||
if(hovered != null && ((mode == look ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){
|
||||
if(hovered != null && (canSelect(hovered) || debugSelect)){
|
||||
selected = hovered;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +281,9 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
game.checkPref("blockreplace", true);
|
||||
game.checkPref("conveyorpathfinding", true);
|
||||
game.checkPref("hints", true);
|
||||
|
||||
if(!mobile){
|
||||
game.checkPref("backgroundpause", true);
|
||||
game.checkPref("buildautopause", false);
|
||||
}
|
||||
|
||||
|
||||
@@ -368,9 +368,9 @@ public class HudFragment extends Fragment{
|
||||
c.clearChildren();
|
||||
|
||||
for(Item item : content.items()){
|
||||
if(state.secinfo.getExport(item) >= 1){
|
||||
if(state.rules.sector != null && state.rules.sector.info.getExport(item) >= 1){
|
||||
c.image(item.icon(Cicon.small));
|
||||
c.label(() -> (int)state.secinfo.getExport(item) + " /s").color(Color.lightGray);
|
||||
c.label(() -> (int)state.rules.sector.info.getExport(item) + " /s").color(Color.lightGray);
|
||||
c.row();
|
||||
}
|
||||
}
|
||||
@@ -379,7 +379,7 @@ public class HudFragment extends Fragment{
|
||||
c.update(() -> {
|
||||
boolean wrong = false;
|
||||
for(Item item : content.items()){
|
||||
boolean has = state.secinfo.getExport(item) >= 1;
|
||||
boolean has = state.rules.sector != null && state.rules.sector.info.getExport(item) >= 1;
|
||||
if(used.get(item.id) != has){
|
||||
used.set(item.id, has);
|
||||
wrong = true;
|
||||
@@ -389,7 +389,7 @@ public class HudFragment extends Fragment{
|
||||
rebuild.run();
|
||||
}
|
||||
});
|
||||
}).visible(() -> state.isCampaign() && content.items().contains(i -> state.secinfo.getExport(i) > 0));
|
||||
}).visible(() -> state.isCampaign() && content.items().contains(i -> state.rules.sector != null && state.rules.sector.info.getExport(i) > 0));
|
||||
});
|
||||
|
||||
blockfrag.build(parent);
|
||||
|
||||
@@ -342,7 +342,7 @@ public class PlacementFragment extends Fragment{
|
||||
topTable.row();
|
||||
topTable.table(b -> {
|
||||
b.image(Icon.cancel).padRight(2).color(Color.scarlet);
|
||||
b.add(!player.isBuilder() ? "@unit.nobuild" : displayBlock.unplaceableMessage()).width(190f).wrap();
|
||||
b.add(!player.isBuilder() ? "@unit.nobuild" : "@banned").width(190f).wrap();
|
||||
b.left();
|
||||
}).padTop(2).left();
|
||||
}
|
||||
|
||||
@@ -133,6 +133,8 @@ public class Block extends UnlockableContent{
|
||||
public int unitCapModifier = 0;
|
||||
/** Whether the block can be tapped and selected to configure. */
|
||||
public boolean configurable;
|
||||
/** If true, this block can be configured by logic. */
|
||||
public boolean logicConfigurable = false;
|
||||
/** Whether this block consumes touchDown events when tapped. */
|
||||
public boolean consumesTap;
|
||||
/** Whether to draw the glow of the liquid for this block, if it has one. */
|
||||
@@ -189,8 +191,6 @@ public class Block extends UnlockableContent{
|
||||
public float buildCost;
|
||||
/** Whether this block is visible and can currently be built. */
|
||||
public BuildVisibility buildVisibility = BuildVisibility.hidden;
|
||||
/** Defines when this block can be placed. */
|
||||
public BuildPlaceability buildPlaceability = BuildPlaceability.always;
|
||||
/** Multiplier for speed of building this block. */
|
||||
public float buildCostMultiplier = 1f;
|
||||
/** Multiplier for cost of research in tech tree. */
|
||||
@@ -519,7 +519,7 @@ public class Block extends UnlockableContent{
|
||||
}
|
||||
|
||||
public boolean isPlaceable(){
|
||||
return isVisible() && buildPlaceability.placeable() && !state.rules.bannedBlocks.contains(this);
|
||||
return isVisible() && !state.rules.bannedBlocks.contains(this);
|
||||
}
|
||||
|
||||
/** Called when building of this block begins. */
|
||||
@@ -532,11 +532,6 @@ public class Block extends UnlockableContent{
|
||||
|
||||
}
|
||||
|
||||
/** @return a message detailing why this block can't be placed. */
|
||||
public String unplaceableMessage(){
|
||||
return state.rules.bannedBlocks.contains(this) ? Core.bundle.get("banned") : buildPlaceability.message();
|
||||
}
|
||||
|
||||
public boolean isFloor(){
|
||||
return this instanceof Floor;
|
||||
}
|
||||
@@ -622,7 +617,7 @@ public class Block extends UnlockableContent{
|
||||
public ItemStack[] researchRequirements(){
|
||||
ItemStack[] out = new ItemStack[requirements.length];
|
||||
for(int i = 0; i < out.length; i++){
|
||||
int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.15f) * 20 * researchCostMultiplier, 10);
|
||||
int quantity = 60 + Mathf.round(Mathf.pow(requirements[i].amount, 1.15f) * 20 * researchCostMultiplier, 10);
|
||||
|
||||
out[i] = new ItemStack(requirements[i].item, UI.roundAmount(quantity));
|
||||
}
|
||||
@@ -674,6 +669,14 @@ public class Block extends UnlockableContent{
|
||||
|
||||
consumes.init();
|
||||
|
||||
if(!logicConfigurable){
|
||||
configurations.each((key, val) -> {
|
||||
if(UnlockableContent.class.isAssignableFrom(key)){
|
||||
logicConfigurable = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
|
||||
throw new IllegalArgumentException("Consumer using buffered power: " + name);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ public class Build{
|
||||
for(int dy = 0; dy < type.size; dy++){
|
||||
int wx = dx + offsetx + tile.x, wy = dy + offsety + tile.y;
|
||||
|
||||
|
||||
Tile check = world.tile(wx, wy);
|
||||
|
||||
if(
|
||||
@@ -136,6 +135,10 @@ public class Build{
|
||||
!check.interactable(team) || //cannot interact
|
||||
!check.floor().placeableOn || //solid wall
|
||||
!((type.canReplace(check.block()) || //can replace type
|
||||
//controversial change: allow rebuilding damaged blocks
|
||||
//this could be buggy and abusable, so I'm not enabling it yet
|
||||
//note that this requires a change in BuilderComp as well
|
||||
//(type == check.block() && check.centerX() == x && check.centerY() == y && check.build != null && check.build.health < check.build.maxHealth - 0.0001f) ||
|
||||
(check.block instanceof ConstructBlock && check.<ConstructBuild>bc().cblock == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction
|
||||
type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement
|
||||
(type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found
|
||||
|
||||
@@ -119,7 +119,7 @@ public class LaunchPad extends Block{
|
||||
|
||||
table.row();
|
||||
table.label(() -> {
|
||||
Sector dest = state.secinfo.getRealDestination();
|
||||
Sector dest = state.rules.sector == null ? null : state.rules.sector.info.getRealDestination();
|
||||
|
||||
return Core.bundle.format("launch.destination",
|
||||
dest == null ? Core.bundle.get("sectors.nonelaunch") :
|
||||
@@ -135,7 +135,11 @@ public class LaunchPad extends Block{
|
||||
}
|
||||
|
||||
table.button(Icon.upOpen, Styles.clearTransi, () -> {
|
||||
ui.planet.showSelect(state.rules.sector, other -> state.secinfo.destination = other);
|
||||
ui.planet.showSelect(state.rules.sector, other -> {
|
||||
if(state.isCampaign()){
|
||||
state.rules.sector.info.destination = other;
|
||||
}
|
||||
});
|
||||
deselect();
|
||||
}).size(40f);
|
||||
}
|
||||
@@ -208,7 +212,7 @@ public class LaunchPad extends Block{
|
||||
public void remove(){
|
||||
if(!state.isCampaign()) return;
|
||||
|
||||
Sector destsec = state.secinfo.getRealDestination();
|
||||
Sector destsec = state.rules.sector.info.getRealDestination();
|
||||
|
||||
//actually launch the items upon removal
|
||||
if(team() == state.rules.defaultTeam){
|
||||
@@ -219,7 +223,7 @@ public class LaunchPad extends Block{
|
||||
dest.add(stack);
|
||||
|
||||
//update export
|
||||
state.secinfo.handleItemExport(stack);
|
||||
state.rules.sector.info.handleItemExport(stack);
|
||||
Events.fire(new LaunchItemEvent(stack));
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ public class PowerNode extends PowerBlock{
|
||||
|
||||
protected void getPotentialLinks(Tile tile, Cons<Building> others){
|
||||
Boolf<Building> valid = other -> other != null && other.tile() != tile && other.power != null &&
|
||||
((!other.block.outputsPower && other.block.consumesPower) || (other.block.outputsPower && !other.block.consumesPower) || other.block instanceof PowerNode) &&
|
||||
(other.block.outputsPower || other.block.consumesPower || other.block instanceof PowerNode) &&
|
||||
overlaps(tile.x * tilesize + offset, tile.y * tilesize + offset, other.tile(), laserRange * tilesize) && other.team == player.team()
|
||||
&& !other.proximity.contains(e -> e.tile == tile) && !graphs.contains(other.power.graph);
|
||||
|
||||
|
||||
@@ -37,11 +37,6 @@ public class GenericCrafter extends Block{
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
if(consumes.has(ConsumeType.liquid)){
|
||||
ConsumeLiquidBase cons = consumes.get(ConsumeType.liquid);
|
||||
cons.timePeriod = craftTime;
|
||||
}
|
||||
|
||||
super.setStats();
|
||||
stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds);
|
||||
|
||||
@@ -50,7 +45,7 @@ public class GenericCrafter extends Block{
|
||||
}
|
||||
|
||||
if(outputLiquid != null){
|
||||
stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount, false);
|
||||
stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount * (60f / craftTime), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public class LiquidConverter extends GenericCrafter{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
stats.remove(Stat.output);
|
||||
stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount * craftTime, false);
|
||||
stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount * 60f, true);
|
||||
}
|
||||
|
||||
public class LiquidConverterBuild extends GenericCrafterBuild{
|
||||
|
||||
@@ -34,11 +34,6 @@ public class Separator extends Block{
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
if(consumes.has(ConsumeType.liquid)){
|
||||
ConsumeLiquidBase cons = consumes.get(ConsumeType.liquid);
|
||||
cons.timePeriod = craftTime;
|
||||
}
|
||||
|
||||
super.setStats();
|
||||
|
||||
stats.add(Stat.output, new ItemFilterValue(item -> {
|
||||
|
||||
@@ -339,15 +339,15 @@ public class CoreBlock extends StorageBlock{
|
||||
public void itemTaken(Item item){
|
||||
if(state.isCampaign() && team == state.rules.defaultTeam){
|
||||
//update item taken amount
|
||||
state.secinfo.handleCoreItem(item, -1);
|
||||
state.rules.sector.info.handleCoreItem(item, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleItem(Building source, Item item){
|
||||
if(net.server() || !net.active()){
|
||||
if(team == state.rules.defaultTeam){
|
||||
state.secinfo.handleCoreItem(item, 1);
|
||||
if(team == state.rules.defaultTeam && state.isCampaign()){
|
||||
state.rules.sector.info.handleCoreItem(item, 1);
|
||||
}
|
||||
|
||||
if(items.get(item) >= getMaximumAccepted(item)){
|
||||
|
||||
@@ -33,8 +33,6 @@ public class UnitFactory extends UnitBlock{
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
solid = true;
|
||||
//flags = EnumSet.of(BlockFlag.producer, BlockFlag.unitModifier);
|
||||
//unitCapModifier = 2;
|
||||
configurable = true;
|
||||
outputsPayload = true;
|
||||
rotate = true;
|
||||
@@ -44,6 +42,11 @@ public class UnitFactory extends UnitBlock{
|
||||
tile.progress = 0;
|
||||
});
|
||||
|
||||
config(UnitType.class, (UnitFactoryBuild tile, UnitType val) -> {
|
||||
tile.currentPlan = plans.indexOf(p -> p.unit == val);
|
||||
tile.progress = 0;
|
||||
});
|
||||
|
||||
consumes.add(new ConsumeItemDynamic((UnitFactoryBuild e) -> e.currentPlan != -1 ? plans.get(e.currentPlan).requirements : ItemStack.empty));
|
||||
}
|
||||
|
||||
@@ -88,6 +91,18 @@ public class UnitFactory extends UnitBlock{
|
||||
super.setStats();
|
||||
|
||||
stats.remove(Stat.itemCapacity);
|
||||
|
||||
stats.add(Stat.output, table -> {
|
||||
Seq<UnitPlan> p = plans.select(u -> u.unit.unlockedNow());
|
||||
table.row();
|
||||
for(var plan : p){
|
||||
if(plan.unit.unlockedNow()){
|
||||
table.image(plan.unit.icon(Cicon.small)).size(8 * 3).padRight(2).right();
|
||||
table.add(plan.unit.localizedName).left();
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,6 +46,6 @@ public class ConsumeLiquid extends ConsumeLiquidBase{
|
||||
|
||||
@Override
|
||||
public void display(Stats stats){
|
||||
stats.add(booster ? Stat.booster : Stat.input, liquid, amount * timePeriod, timePeriod == 60);
|
||||
stats.add(booster ? Stat.booster : Stat.input, liquid, amount * 60f, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,6 @@ import mindustry.gen.*;
|
||||
public abstract class ConsumeLiquidBase extends Consume{
|
||||
/** amount used per frame */
|
||||
public final float amount;
|
||||
/**
|
||||
* How much time is taken to use this liquid, in ticks. Used only for visual purposes.
|
||||
* Example: a normal ConsumeLiquid with 10/s and a 10 second timePeriod would display as "100 seconds".
|
||||
* Without a time override, it would display as "10 liquid/second".
|
||||
* This is used for generic crafters.
|
||||
*/
|
||||
public float timePeriod = 60;
|
||||
|
||||
public ConsumeLiquidBase(float amount){
|
||||
this.amount = amount;
|
||||
|
||||
@@ -50,6 +50,6 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{
|
||||
|
||||
@Override
|
||||
public void display(Stats stats){
|
||||
stats.add(booster ? Stat.booster : Stat.input, new LiquidFilterValue(filter, amount * timePeriod, timePeriod == 60f));
|
||||
stats.add(booster ? Stat.booster : Stat.input, new LiquidFilterValue(filter, amount * 60f, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package mindustry.world.meta;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import mindustry.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Like BuildVisiblity, but defines whether a block can be *placed*, with an extra message.
|
||||
* This is like defining a conditionally banned block.
|
||||
* */
|
||||
public enum BuildPlaceability{
|
||||
always(() -> true),
|
||||
sectorCaptured(() -> Vars.state.rules.sector != null && Vars.state.rules.sector.isCaptured());
|
||||
|
||||
private final Boolp placeability;
|
||||
|
||||
BuildPlaceability(Boolp placeability){
|
||||
this.placeability = placeability;
|
||||
}
|
||||
|
||||
public boolean placeable(){
|
||||
return placeability.get();
|
||||
}
|
||||
|
||||
/** @return why this block is banned. */
|
||||
public String message(){
|
||||
return Core.bundle.get("unplaceable." + name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public enum BuildVisibility{
|
||||
debugOnly(() -> false),
|
||||
sandboxOnly(() -> Vars.state.rules.infiniteResources),
|
||||
campaignOnly(() -> Vars.state.isCampaign()),
|
||||
lightingOnly(() -> Vars.state.rules.lighting),
|
||||
lightingOnly(() -> Vars.state.rules.lighting || Vars.state.isCampaign()),
|
||||
ammoOnly(() -> Vars.state.rules.unitAmmo);
|
||||
|
||||
private final Boolp visible;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
- Added 4 new custom game maps (untested)
|
||||
- Added new stats to unit info
|
||||
- Added buttons to clear campaign research+saves
|
||||
- Added fog weather
|
||||
- Added weather to some custom game maps
|
||||
- Added support for weather in JSON mods
|
||||
- Added better control sync for commanded units
|
||||
- Added recipe display for reconstructors
|
||||
- Added titanium fuse ammo
|
||||
- Made campaign load research from older versions (5.0)
|
||||
- Campaign: Added more schematics for bases to use
|
||||
- router.
|
||||
@@ -1,3 +1,3 @@
|
||||
org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||
archash=f8ef0f3a72de0f79ca49da895fed0b6889cd597e
|
||||
archash=7090a07ce5d02dcb697f6c5a8d1fb6e0a00de45f
|
||||
|
||||