Mod语法

来自RustedWarfare Wiki
AbAb留言 | 贡献2022年7月19日 (二) 19:30的版本 →‎属性(property):​ 先更了[core]的部分,小白知道键的功能容易,但具体怎么填值容易搞乱,该表提供了对应值类型,和不填键时的缺省值

.ini文件

纯文本文件。游戏通过读取以.ini为扩展名的文件来获取具体单位的属性。内容组成方面,由节(section)、键(key)、注释(comment)三个部分组成:

节(section)

包含用两个半角英文方括号包围的节的名称([section]),单独占一行。用于声明相关的键从属于该节。其后的行直到另一个节前一行的键均归属于该节。名称不同的节视为不同类型的节。

节的类型:

[core]
[canBuild_NAME]
[graphics]
[attack]
[turret_NAME]
[projectile_NAME]
[movement]
[ai]
[leg_#]
[arm_#]
[attachment_NAME]
[action_NAME]
[hiddenAction_NAME]
[effect_NAME]
[animation_NAME]
[placementRule_NAME]
[global_resource_NAME]
[resource_NAME]
[template_NAME]
[comment_NAME]

属性(property)

在Rusted Warfare中,属性包含一组键值对。键(key)的名称与其对应的值(value)用半角冒号隔开,单独占一行。用于规定单位的具体属性。名称不同的键视为不同类型的键,名称相同的键从属于不同类型的节视为不同类型的键。

键的类型(施工中):

SectionCodeValueDefaultNotes
[core]name"string"
[core]altNames"string"(s)
[core]classCustomUnitMetadataCustomUnitMetadata
[core]strictLevel0/10
[core]price"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]
[core]mass"int"(>=0)
[core]techLevel1/2/31
[core]buildSpeed"float"/"float"s1"float"=1/("float"s*60)
[core]radius"int"(>=0)
[core]isBio"bool"false
[core]isBug"bool"false
[core]isBuilderboolfalse
[core]streamingCost"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"];[core]resourceRate:0;[core]switchPriceWithStreamingCost:false
[core]switchPriceWithStreamingCost"bool"false[core]resourceRate:0;[core]StreamingCost:
[core]maxHp"int"(>=0, if ${core.disableDeathOnZeroHp} != true)
[core]selfRegenRate"float"0hp/s=("float"*60)/s
[core]maxShield"int"(>=0)0
[core]startShieldAtZero"bool"false
[core]shieldRegen"float"0.25shield/s=("float"*60)/s
[core]energyMax"float"(>=0)0
[core]energyRegen"float"0energy/s=("float"*60)/s
[core]energyStartingPercentage"float"(0-1)1
[core]energyNeedsToRechargeToFull"bool"false
[core]energyRegenWhenRecharging"float"${core.energyRegen}energy/s=("float"*60)/s
[core]armour"int"0
[core]armourMinDamageToKeep"int"1
[core]borrowResourcesWhileAlive"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]
[core]borrowResourcesWhileBuilt"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]
[core]generation_resources"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]
[core]generation_active"logicBoolean"true
[core]generation_credits"int"
[core]generation_delay"int"(>=0)40
[core]showInEditor"bool"true
[core]displayText"string"/i:"localeKey"/assets/translations/Strings.properties-->"localeKey"=xxx;if displayText:i:"localeKey", displayText_"LANG":"string"
[core]displayText_"LANG""string"/i:"localeKey""LANG" = ISO 639-1 Code(zh,ru,ja...);/assets/translations/Strings.properties-->"localeKey"=xxx;displayText:"string"(/i:"localeKey");if displayText_"LANG":i:"localeKey", displayText:"string"
[core]displayDescription"string"/i:"localeKey"/assets/translations/Strings.properties-->"localeKey"=xxx;if displayDescription:i:"localeKey", displayDescription_"LANG":"string"
[core]displayDescription_"LANG""string"/i:"localeKey""LANG" = ISO 639-1 Code(zh,ru,ja...);/assets/translations/Strings.properties-->"localeKey"=xxx;displayDescription:"string"(/i:"localeKey");if displayDescription_"LANG":i:"localeKey", displayDescription:"string"
[core]displayLocaleKey"unitLocaleKey"/assets/translations/Strings.properties-->units."unitLocaleKey".name
[core]displayRadius"int"(>=0)${core.radius}
[core]uiTargetRadius"int"(>=0;==6, if ${core.radius} < 6)${core.radius}
[core]shieldRenderRadius"int"(>=0)${core.radius}
[core]shieldDisplayOnlyDeflection"bool"false
[core]shieldDeflectionDisplayRate"float"4Unfiled
[core]showOnMinimap"bool"true
[core]showActionsWithMixedSelectionIfOtherUnitsHaveTag"tag"(s)
[core]showOnMinimapToEnemies"bool"${graphics.isVisibleToEnemies}
[core]isBuilding"bool"false
[core]footprint-"int",-"int","int","int"(>=0)-0,-0,0,0"int"="int"*tile="int"*(20px*20px)
[core]constructionFootprint-"int",-"int","int","int"<(>=0)/td>-0,-0,0,0"int"="int"*tile="int"*(20px*20px)
[core]displayFootprint-"int",-"int","int","int"(>=0)${core.footprint}"int"="int"*tile="int"*(20px*20px)
[core]buildingSelectionOffset"int"0"int"="int"px*"int"px
[core]buildingToFootprintOffsetX"float"10"float"="float"px
[core]buildingToFootprintOffsetY"float"10"float"="float"px
[core]placeOnlyOnResPool"bool"false
[core]selfBuildRate"float"/"float"s0"float"=1/("float"s*60)
[core]ignoreInUnitCapCalculation"bool"${core.isBuilding}
[core]copyFrom"filePath"(.ini)(s)"filePath" = ./../xxx/xx/xxxx.ini
[core]dont_load"bool"false
[core]overrideAndReplace"unitName"(s)"unitName" = ${core.name}
[core]onNewMapSpawnemptyResourcePools_asNeutral/emptyOrOccupiedResourcePools_asNeutral/mapCenter_asNeutral/mapCenter_eachActiveTeam/spawnPoint_eachActiveTeam
[core]isLocked"bool"false
[core]isLockedIfGameModeNoNuke"bool"false
[core]experimental"bool"false
[core]stayNeutral"bool"false
[core]createNeutral"bool"false
[core]createOnAggressiveTeam"bool"false
[core]tags"tag"(s)
[core]defineUnitMemoryboolean/float/number/unit/string "string"(s)
[core]fogOfWarSightRange"int"(>=0)15"int"="int"px
[core]fogOfWarSightRangeWhileNotBuilt"int"(>=0)${core.fogOfWarSightRange}"int"="int"px
[core]softCollisionOnAll"int"(>=0)0
[core]disableAllUnitCollisions"bool"false
[core]isUnrepairableUnit"bool"false
[core]isUnselectable"bool"false
[core]isUnselectableAsTarget"bool"${core.isUnselectable}
[core]isPickableStartingUnit"bool"false
[core]startFallingWhenStartingUnit"bool"false
[core]soundOnAttackOrder"filePath"(.ogg/.wav)(s)"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)
[core]soundOnMoveOrder"filePath"(.ogg/.wav)(s)"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)
[core]soundOnNewSelection"filePath"(.ogg/.wav)(s)"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)
[core]canNotBeDirectlyAttacked"bool"false[core]canOnlyBeAttackedByUnitsWithTags:
[core]canNotBeDamaged"bool"${core.canNotBeDirectlyAttacked}
[core]canNotBeGivenOrdersByPlayer"bool"false
[core]canOnlyBeAttackedByUnitsWithTags"tag"(s)[core]canNotBeDirectlyAttacked:
[core]disableDeathOnZeroHp"bool"false
[core]transportSlotsNeeded"int"(>=0)1
[core]maxTransportingUnits"int"(>=0)0
[core]transportUnitsRequireTag"tag"(s)
[core]transportUnitsRequireMovementTypeNONE/LAND/BUILDING/HOVER/OVER_CLIFF/OVER_CLIFF_WATER/AIR/WATER(s)
[core]transportUnitsBlockAirAndWaterUnits"bool"true
[core]transportUnitsKeepBuiltUnits"logicBoolean"false
[core]transportUnitsCanUnloadUnits"logicBoolean"if not (self.isOverLiquid or self.isMoving)
[core]transportUnitsAddUnloadOption"bool"true/false(if ${core.transportUnitsCanUnloadUnits} == false)
[core]transportUnitsUnloadDelayBetweenEachUnit"float"/"float"s30"float"s="float"*60
[core]transportUnitsKillOnDeath"logicBoolean"true
[core]transportUnitsHealBy"float"0hp/s=("float"*60)/s
[core]transportUnitsBlockOtherTransports"bool"true
[core]whileNeutralTransportAnyTeam"bool"false
[core]whileNeutralConvertToTransportedTeam"bool"false
[core]convertToNeutralIfNotTransporting"bool"false
[core]transportUnitsOnTeamChangeKeepCurrentTeam"bool"false
[core]resourceRate"float"(>0)0[core]switchPriceWithStreamingCost:false;[core]StreamingCost:
[core]similarResourcesHaveTag"tag"(s)
[core]resourceMaxConcurrentReclaimingThis"int"(>=0)
[core]reclaimPrice"int"/"customResourceX"="float"(s)"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]
[core]canReclaimResources"bool"false
[core]canReclaimResourcesNextSearchRange"int"(>=0)500
[core]canReclaimResourcesOnlyWithTags"tag"(s)
[core]canReclaimUnitsOnlyWithTags"tag"(s)[core]canRepairBuildings:true/[core]canRepairUnits:true
[core]resourceReclaimMultiplier"float"1
[core]canRepairUnitsOnlyWithTags"tag"(s)[core]canRepairBuildings:true/[core]canRepairUnits:true
[core]canRepairBuildings"bool"false
[core]canRepairUnits"bool"false
[core]autoRepair"bool"false
[core]nanoRange"int"(>=0)85
[core]nanoRepairSpeed"float"0.2hp/s=("float"*60)/s
[core]nanoBuildSpeed"float"(>=0)1
[core]nanoUnbuildSpeed"float"(>=0)1
[core]nanoReclaimSpeed"float"(>=0)${core.nanoRepairSpeed}*5.1hp/s=("float"*60)/s
[core]nanoRangeForRepairIsMelee"bool"false
[core]nanoRangeForReclaimIsMelee"bool"false
[core]nanoRangeForRepair"int"(>=0)${core.nanoRange}
[core]nanoRangeForReclaim"int"(>=0)${core.nanoRange}
[core]nanoFactorySpeed"float"(>=0)1
[core]extraBuildRangeWhenBuildingThis"int"0
[core]builtFrom_"#"_name"unitName"(s)"#" = "int"(>=0);"unitName" = ${core.name}
[core]builtFrom_"#"_pos"float""#" = "int"(>=0)
[core]builtFrom_"#"_forceNano"bool"false"#" = "int"(>=0)
[core]builtFrom_"#"_isLocked"logicBoolean"false"#" = "int"(>=0)
[core]builtFrom_"#"_isLockedMessage"string"/i:"localeKey""#" = "int"(>=0);/assets/translations/Strings.properties-->"localeKey"=xxx
[core]exit_x"float"0
[core]exit_y"float"9
[core]exit_dirOffset"float"180(units)/0(buildings)
[core]exit_heightOffset"float"0
[core]exit_moveAwayAmount"float"70
[core]exitHeightIgnoreParent"bool"false
[core]dieOnConstruct"bool"false
[core]dieOnZeroEnergy"bool"false
[core]numBitsOnDeath"int"(>=0)4(if ${core.mass} <= 30000)/8(if ${core.mass} > 30000)/7(buildings)
[core]nukeOnDeath"bool"false
[core]nukeOnDeathRange"float"(>=0)250
[core]nukeOnDeathDamage"float"5400
[core]nukeOnDeathDisableWhenNoNuke"bool"false
[core]fireTurretXAtSelfOnDeath"turretX"[turret_"turretX"]
[core]explodeOnDeath"bool"true
[core]explodeOnDeathGroundCollision"bool"true
[core]explodeTypeOnDeathverysmall/small/normal/large/largeUnit/building/buildingNoShockwaveOrSmoke/verylargeBuilding(s)normal
[core]effectOnDeathsmoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)[effect_"customEffectX"]
[core]effectOnDeathGroundCollisionsmoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)[effect_"customEffectX"]
[core]unitsSpawnedOnDeath"unitName"*"int"(>=0)(s)"unitName" = ${core.name}
[core]unitsSpawnedOnDeath_setToTeamOfLastAttacker"bool"false
[core]hideScorchMark"bool"false
[core]soundOnDeath"built-inSound"/"filePath"(.ogg/.wav)(s)\res\raw\"built-inSound".ogg(/.wav)
[core]effectOnDeathIfUnbuiltsmoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)[effect_"customEffectX"]
[core]autoTriggerCooldownTime"float"(>=5;<120;>=0,if ${core.autoTriggerCooldownTime_allowDangerousHighCPU} == true)/"float"s(>=${5/60}s;<2s;>=0s,if ${core.autoTriggerCooldownTime_allowDangerousHighCPU} == true)60
[core]autoTriggerCooldownTime_allowDangerousHighCPU"bool"false
[core]autoTriggerCheckRateeveryFrame/every4Frames/every8FrameseveryFrame

注释

注释即为对代码的解释和说明。清晰的注释有利于帮助理解代码的含义。铁锈战争的.ini文件语法在注释方面提供了三种方式:

(1)用#进行单行的注释

在行的开头加上符号#后,游戏程序会忽略这一行的内容,不将其作为代码解析。但编写这些的人类可以注意到这些。

[projectile_1]
#directDamage: 20
#有人反映单发伤害太低,这里改成了30
directDamage: 30
…

(2)用""""""的组合进行多行注释

在行头使用"""作为起始,在之后的行尾使用"""作为结束。在其之间的内容均会被游戏忽略。

"""
这是三个英文引号
实际上这个组合还有个功能,就是用它引住key: value的value使value可以换行输入如:
builtFrom_1_name: airFactory
可以是
builtFrom_1_name: """airF
actory"""
可是有一种情况,你用多行注释注释掉了有换行输入的内容它显然就会混乱,也就是目前的情况
"""

(3)用[comment_NAME]进行成节的注释

该节之后的行直到下一个节前一行均不会被加载。

[comment_hiddenAction_1]
autoTriggerOnEvent: created
addGlobalTeamTags: 计时
[comment_1]
maxHp: 2000
[core]
#[comment_NAME]节下的东西是不会被加载的,去引用它会提示找不到任何key
@copyFromSection: comment_1
…

mod-info.txt文件

纯文本文件。游戏通过在mod文件夹根目录读取mod-info.txt这样命名的文件来获得mod作者提供的mod描述信息。

相关参数解释:

#(必填)
[mod]
#(选填)告诉游戏能够支持该mod运行的最低游戏版本。若不满足最低版本,提示后仍可加载,但除地图外不可用,同时不提供代码错误的报错提醒。
minVersion: v1.14
#(必填)该mod在游戏中显示的标题。
title: Mega Builders
#(选填)该mod在游戏中显示的描述。使用"\n"使其在游戏中换行显示(pc版并不会换行显示)。
description: Example mod which replaces builders with Mega Builders.

#(选填,在游戏中播放mod中的.ogg文件作为背景音乐)#关于.ogg文件的说明仍待补充
[music]
#填音乐文件夹路径。
sourceFolder: soundtrack
#当使用该mod的单位时仅播放该mod的音乐,填"true"或"false"。
whenUsingUnitsFromThisMod_playExclusively: true

#该文件支持单行注释
"""和
多行
注释"""

all-units.template文件

all-units.template也是INI格式的文件。文件中的代码会自动应用到模组内的所有单位中(效果与使用core节下的copyFrom一致)到同级及以下级文件夹的所有.ini文件中。若存在代码错误,报错不会指向其本身,而是其所应用的.ini文件。