Compare commits

...
55 Commits
Author SHA1 Message Date
Anuken baf6bdf6a5 Increased sector damage calculation radius 2020-10-25 17:21:34 -04:00
Anuken 889fd64656 arc 2020-10-25 15:55:34 -04:00
Anuken 59b5d809db Balance 2020-10-25 15:55:23 -04:00
Anuken 6c3372e71c Slightly more reasonable waves 2020-10-25 15:07:51 -04:00
Anuken 1cdea49383 Merge remote-tracking branch 'origin/master' 2020-10-25 12:35:52 -04:00
Anuken a6307039b0 Fixed some nullability issues 2020-10-25 12:35:48 -04:00
Anuken aaacf244d2 Merge pull request #3096 from azureblue/placement-direction
make ending direction follow the path
2020-10-25 12:28:41 -04:00
Anuken 2a0af620be Sector land announcement 2020-10-25 12:00:57 -04:00
Anuken b801093597 Merge remote-tracking branch 'origin/master' 2020-10-25 11:22:19 -04:00
Anuken 81dae580a4 Bugfixes / Removed tile unit multi-mining 2020-10-25 11:22:10 -04:00
Anuken 03f58a1b02 Merge pull request #2972 from sk7725/patch-20
Add colors to StatusEffects
2020-10-25 10:35:42 -04:00
Anuken b2b0082c7d Fixed #3108 / Fixed #3112 2020-10-25 09:23:13 -04:00
Anuken 1d85495f7a Merge remote-tracking branch 'origin/master' 2020-10-24 19:06:09 -04:00
Anuken 41d388aa7f Item sprite cleanup 2020-10-24 19:06:05 -04:00
Anuken e88921c77e Merge pull request #3100 from MEEPofFaith/patch-1
"diable"
2020-10-24 16:56:49 -04:00
MEEP of Faith 705728f16a "diable"
oh no
2020-10-24 13:49:30 -07:00
azureblue a7c24d4bfd fixing formatting 2020-10-24 22:10:02 +02:00
Anuken 79ace277ed Merge remote-tracking branch 'origin/master' 2020-10-24 15:55:25 -04:00
Anuken bc035f9490 Fixed #3095 2020-10-24 15:55:20 -04:00
azureblue 73a5af2e5e make ending direction follow the path 2020-10-24 21:34:47 +02:00
Anuken ee7bdbf44e Merge pull request #3081 from genNAowl/standardize-liquid-stats
Remove timePeriod in LiquidBaseValue
2020-10-24 15:18:47 -04:00
Anuken b611726c3e Merge remote-tracking branch 'origin/master' 2020-10-24 15:11:31 -04:00
Anuken 819686e812 Unit factory production list 2020-10-24 15:11:27 -04:00
Anuken 94e40a32b9 Merge pull request #3093 from DeltaNedas/patch-11
add more info to print object
2020-10-24 15:09:50 -04:00
DeltaNedas 3b2669fa21 pattern variables? 2020-10-24 17:23:54 +00:00
DeltaNedas 801ff1701e silly 2020-10-24 17:19:50 +00:00
DeltaNedas 364a2b43c2 add Content fallback 2020-10-24 17:04:58 +00:00
DeltaNedas 279d898d68 add more info to print object 2020-10-24 16:37:55 +00:00
Anuken a930b34c3e Merge pull request #3090 from QmelZ/master
Turkish Translation
2020-10-24 11:58:21 -04:00
QmelZ 232a3dfe87 one last little fix 2020-10-24 17:28:10 +03:00
Anuken ddbca62f92 Merge remote-tracking branch 'origin/master' 2020-10-24 10:22:04 -04:00
Anuken 646b022d38 Bugfixes 2020-10-24 10:21:57 -04:00
QmelZ 19ef414e5c even more fixes 2020-10-24 17:18:56 +03:00
QmelZ f46eb24615 some other fixes 2020-10-24 17:07:52 +03:00
Anuken 4e6faf3bac Merge pull request #3083 from genNAowl/titanium-ammo-fuse
Switch places of titanium and thorium ammo in `Blocks.java`
2020-10-24 09:47:21 -04:00
Anuken 48f5007306 Merge pull request #2990 from driver1748/patch-5
Update bundle_zh_CN.properties
2020-10-24 09:46:09 -04:00
Anuken 56acbcecfd Merge branch 'master' into patch-5 2020-10-24 09:46:02 -04:00
QmelZ 7d0952d858 small fix 2020-10-24 15:59:28 +03:00
QmelZ ef40a2e78e Update bundle_tr.properties 2020-10-24 15:56:51 +03:00
QmelZ b4abd3b23d Merge pull request #1 from SilentOwl476/patch-1
Update bundle_tr.properties
2020-10-24 09:10:32 +03:00
Leonwang4234 f2a984f3e7 Lets hope this compiles because I don't have time to test it 2020-10-23 19:53:21 -07:00
Anuken 1ffa3f21f0 (2) 2020-10-23 20:41:32 -04:00
Anuken 7e323f1ebf Logic locate fix 2020-10-23 20:38:33 -04:00
SilentOwl476 bff79d7c27 Update bundle_tr.properties 2020-10-24 01:46:02 +03:00
Anuken 117f002545 Fixed #3082 2020-10-23 18:24:18 -04:00
Anuken 953c1889b5 Fixed #3080 2020-10-23 17:18:49 -04:00
Leonwang4234 cc024a0bac remove timePeriod in LiquidBaseValue 2020-10-23 13:34:07 -07:00
Anuken 42bfab6e40 Fixed #3079 2020-10-23 16:12:36 -04:00
Anuken c8ef7ebafb Fixed #3078 + action listeners for player control events 2020-10-23 15:59:52 -04:00
Anuken 5512c1817d Extra scrap for debris field map 2020-10-23 14:09:05 -04:00
WinterUnderTheSnow 877999dd1e Update bundle_zh_CN.properties 2020-10-20 07:13:10 +08:00
WinterUnderTheSnow 699f2ca5a2 Update bundle_zh_CN.properties
Confirmed units,name this may be the final version of translation by main translating team for v108
2020-10-17 17:38:12 +08:00
Sunny Kim 89f04ed3e9 oh no 2020-10-17 01:22:07 +09:00
Sunny Kim 956840b50b oops 2020-10-16 20:59:40 +09:00
Sunny Kim b79e0373f4 Add colors to StatusEffects 2020-10-16 20:12:54 +09:00
99 changed files with 707 additions and 535 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 B

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

After

Width:  |  Height:  |  Size: 469 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 B

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 B

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 519 B

+2 -2
View File
@@ -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
File diff suppressed because it is too large Load Diff
+51 -51
View File
@@ -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 = 蓝
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 KiB

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

+2 -2
View File
@@ -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.*/
+24 -2
View File
@@ -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())){
+3 -3
View File
@@ -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;
+2 -2
View File
@@ -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){
+11 -8
View File
@@ -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;
+8
View File
@@ -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;
}};
+21 -2
View File
@@ -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;
}};
}
+2 -1
View File
@@ -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
+1 -1
View File
@@ -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;
+17 -6
View File
@@ -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);
}
}
-2
View File
@@ -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. */
+8 -9
View File
@@ -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()){
+7
View File
@@ -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;
+15 -4
View File
@@ -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){
+17 -17
View File
@@ -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));
+1 -1
View File
@@ -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
+4
View File
@@ -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);
-1
View File
@@ -156,7 +156,6 @@ public class SectorInfo{
damage = 0;
if(state.rules.sector != null){
state.rules.sector.info = this;
state.rules.sector.saveInfo();
}
+16
View File
@@ -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){
+1 -1
View File
@@ -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()){
+2
View File
@@ -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"),
+2 -2
View File
@@ -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);
}
}
+21 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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
+1 -6
View File
@@ -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);
+10 -1
View File
@@ -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;
}
}
+18 -13
View File
@@ -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);
+12 -6
View File
@@ -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);
}
}
+1 -1
View File
@@ -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");
+4 -4
View File
@@ -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);
}
}
}
+3 -1
View File
@@ -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);
+21 -3
View File
@@ -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
}
}
+2 -1
View File
@@ -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);
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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();
}
+12 -9
View File
@@ -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);
}
+4 -1
View File
@@ -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 -1
View File
@@ -1,3 +1,3 @@
org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=f8ef0f3a72de0f79ca49da895fed0b6889cd597e
archash=7090a07ce5d02dcb697f6c5a8d1fb6e0a00de45f