Mod语法:修订间差异

来自RustedWarfare Wiki
添加的内容 删除的内容
→‎属性(property):​ 先更了[core]的部分,小白知道键的功能容易,但具体怎么填值容易搞乱,该表提供了对应值类型,和不填键时的缺省值
标签移动版编辑 移动版网页编辑 高级移动版编辑
 
(未显示2个用户的26个中间版本)
第1行: 第1行:
{{欢迎编辑}}
{{欢迎编辑}}
== .ini文件 ==
== .ini文件 ==
纯文本文件。游戏通过读取以<code>.ini</code>为扩展名的文件来获取具体[[单位]]属性。内容组成方面,由节(section)、键(key)、注释(comment)三个部分组成
UTF-8纯文本文件。游戏通过读取以<code>.ini</code>为扩展名的文件来获得某个单位的参数信息内容主要由节(Section)和参数(Parameter)部分组成
=== 节(section) ===
=== 格式 ===
<pre style="white-space:pre;overflow:auto;margin:0;padding:0;width:100%;">
包含用两个半角英文方括号包围的节的名称([section]),单独占一行。用于声明相关的键从属于该节。其后的行直到另一个节前一行的键均归属于该节。名称不同的节视为不同类型的节。
#节由两个半角方括号包裹,单独占一行
[section]
#参数由它的名称和它的值构成,名称和值使用半角冒号分隔,通常单独占一行
name: value
</pre>
<p style="font-size:12px;color:#888;margin-top:0px;"><nowiki>*</nowiki>另有部分代码存在不同的书写格式,待到具体代码再作讲解。</p>


参数从属于节,要想具体参数从属于具体节,需将节写在参数行的上方;不同参数的值有不同类型,且规定有取值区间。
节的类型:
=== 节的类型 ===
<pre style="white-space:pre;overflow:auto;">
截至<u>1.15</u>版本,节的类型有:
[core]
<pre style="white-space:pre;overflow:auto;margin:0;padding:0;width:100%;">
[canBuild_NAME]
[core]--基础节,涉及单位的名称、生命值、体积大小、是建筑与否等基本设置。
[graphics]
[canBuild_NAME]--可建造节,涉及单位能建造生产那些单位,建造方式和条件等设置。
[attack]
[graphics]--图像节,涉及单位主体贴图等设置。
[turret_NAME]
[attack]--攻击节,涉及单位能攻击与否、最大攻击范围等设置。
[projectile_NAME]
[turret_NAME]--炮塔节,涉及单位炮塔的贴图、旋转速度、攻击间隔等设置。
[movement]
[projectile_NAME]--炮弹节,涉及单位炮塔发射的弹丸的贴图、寿命、飞行速度、伤害等设置。
[ai]
[movement]--移动节,涉及单位的移动类型、速度、转向速度等设置。
[leg_#]
[ai]--AI节,涉及AI玩家对该单位的建造、升级概率以及部分单位特性等设置。
[arm_#]
[arm_#]--臂节,涉及单位臂装饰物的位置、贴图等设置。
[attachment_NAME]
[leg_#]--腿节,同上。
[action_NAME]
[attachment_NAME]--附属节,涉及单位的子附属单位的位置、能攻击与否等设置。
[hiddenAction_NAME]
[action_NAME]--操作节,涉及单位的资源手动添加、手动升级按钮、添加路径点等设置。
[effect_NAME]
[hiddenAction_NAME]--隐藏的操作节,同上。
[animation_NAME]
[effect_NAME]--特效节,涉及单位炮塔开火,弹丸飞行、爆炸等生成的特效的设置。
[placementRule_NAME]
[animation_NAME]--动画节,涉及单位移动、部署、攻击等时机播放的帧动画的设置。
[global_resource_NAME]
[placementRule_NAME]--放置规则节,单位建造时放置的规则的设置。
[resource_NAME]
[global_resource_NAME]--全局资源节,队伍内单位通用的自定义资源的名称、样式设置。
[template_NAME]
[resource_NAME]--资源节,具体单位自用的自定义资源的名称样式设置
[comment_NAME]
[template_NAME]--模板节,节之间复制参数时选用。
[comment_NAME]--注释节,用于大篇幅注释。
[decal_NAME]--贴花节,单位身上的贴花、伪3D等设置。
</pre>
</pre>
部分节可以自行添加名称或序号,如上面的"NAME"要求填写名称,"#"要求填写序号(1-20),这样得到的同类型不同名称的节,在应用时是各自独立的;允许重复书写一个节使其分布在文档的不同位置。
=== 属性(property) ===
在Rusted Warfare中,属性包含一组键值对。键(key)的名称与其对应的值(value)用半角冒号隔开,单独占一行。用于规定单位的具体属性。名称不同的键视为不同类型的键,名称相同的键从属于不同类型的节视为不同类型的键。


的类型(<b>施工中</b>):
=== 参数的类型 ===
参数是文档中真正起作用的部分,每行参数必然关联者一个功能;参数(行)必须跟随在某个节的后面,以从属该节;节会因缺少必要参数而报错;部分参数有默认值,即使不写出也会起作用。<br />
<table class="wikitable sortable" border="1" style="word-break:break-all;">
有关具体参数的参考请移步至[[mod参数]]。
<tr><th>Section</th><th>Code</th><th>Value</th><th>Default</th><th>Notes</th></tr>
<tr><td>[core]</td><td>name</td><td>"string"</td><td></td><td></td></tr>
<tr><td>[core]</td><td>altNames</td><td>"string"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>class</td><td>CustomUnitMetadata</td><td>CustomUnitMetadata</td><td></td></tr>
<tr><td>[core]</td><td>strictLevel</td><td>0/1</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>price</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]</td></tr>
<tr><td>[core]</td><td>mass</td><td>"int"(>=0)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>techLevel</td><td>1/2/3</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>buildSpeed</td><td>"float"/"float"s</td><td>1</td><td>"float"=1/("float"s*60)</td></tr>
<tr><td>[core]</td><td>radius</td><td>"int"(>=0)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>isBio</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isBug</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isBuilder</td><td>bool</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>streamingCost</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"];[core]resourceRate:0;[core]switchPriceWithStreamingCost:false</td></tr>
<tr><td>[core]</td><td>switchPriceWithStreamingCost</td><td>"bool"</td><td>false</td><td>[core]resourceRate:0;[core]<del>StreamingCost:</del></td></tr>
<tr><td>[core]</td><td>maxHp</td><td>"int"(>=0, if ${core.disableDeathOnZeroHp} != true)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>selfRegenRate</td><td>"float"</td><td>0</td><td>hp/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>maxShield</td><td>"int"(>=0)</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>startShieldAtZero</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>shieldRegen</td><td>"float"</td><td>0.25</td><td>shield/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>energyMax</td><td>"float"(>=0)</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>energyRegen</td><td>"float"</td><td>0</td><td>energy/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>energyStartingPercentage</td><td>"float"(0-1)</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>energyNeedsToRechargeToFull</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>energyRegenWhenRecharging</td><td>"float"</td><td>${core.energyRegen}</td><td>energy/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>armour</td><td>"int"</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>armourMinDamageToKeep</td><td>"int"</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>borrowResourcesWhileAlive</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]</td></tr>
<tr><td>[core]</td><td>borrowResourcesWhileBuilt</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]</td></tr>
<tr><td>[core]</td><td>generation_resources</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]</td></tr>
<tr><td>[core]</td><td>generation_active</td><td>"logicBoolean"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>generation_credits</td><td>"int"</td><td></td><td></td></tr>
<tr><td>[core]</td><td>generation_delay</td><td>"int"(>=0)</td><td>40</td><td></td></tr>
<tr><td>[core]</td><td>showInEditor</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>displayText</td><td>"string"/i:"localeKey"</td><td></td><td>/assets/translations/Strings.properties-->"localeKey"=xxx;if displayText:i:"localeKey", displayText_"LANG":"string"</td></tr>
<tr><td>[core]</td><td>displayText_"LANG"</td><td>"string"/i:"localeKey"</td><td></td><td>"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"</td></tr>
<tr><td>[core]</td><td>displayDescription</td><td>"string"/i:"localeKey"</td><td></td><td>/assets/translations/Strings.properties-->"localeKey"=xxx;if displayDescription:i:"localeKey", displayDescription_"LANG":"string"</td></tr>
<tr><td>[core]</td><td>displayDescription_"LANG"</td><td>"string"/i:"localeKey"</td><td></td><td>"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"</td></tr>
<tr><td>[core]</td><td>displayLocaleKey</td><td>"unitLocaleKey"</td><td></td><td>/assets/translations/Strings.properties-->units."unitLocaleKey".name</td></tr>
<tr><td>[core]</td><td>displayRadius</td><td>"int"(>=0)</td><td>${core.radius}</td><td></td></tr>
<tr><td>[core]</td><td>uiTargetRadius</td><td>"int"(>=0;==6, if ${core.radius} < 6)</td><td>${core.radius}</td><td></td></tr>
<tr><td>[core]</td><td>shieldRenderRadius</td><td>"int"(>=0)</td><td>${core.radius}</td><td></td></tr>
<tr><td>[core]</td><td>shieldDisplayOnlyDeflection</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>shieldDeflectionDisplayRate</td><td>"float"</td><td>4</td><td>Unfiled</td></tr>
<tr><td>[core]</td><td>showOnMinimap</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>showActionsWithMixedSelectionIfOtherUnitsHaveTag</td><td>"tag"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>showOnMinimapToEnemies</td><td>"bool"</td><td>${graphics.isVisibleToEnemies}</td><td></td></tr>
<tr><td>[core]</td><td>isBuilding</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>footprint</td><td>-"int",-"int","int","int"(>=0)</td><td>-0,-0,0,0</td><td>"int"="int"*tile="int"*(20px*20px)</td></tr>
<tr><td>[core]</td><td>constructionFootprint</td><td>-"int",-"int","int","int"<(>=0)/td><td>-0,-0,0,0</td><td>"int"="int"*tile="int"*(20px*20px)</td></tr>
<tr><td>[core]</td><td>displayFootprint</td><td>-"int",-"int","int","int"(>=0)</td><td>${core.footprint}</td><td>"int"="int"*tile="int"*(20px*20px)</td></tr>
<tr><td>[core]</td><td>buildingSelectionOffset</td><td>"int"</td><td>0</td><td>"int"="int"px*"int"px</td></tr>
<tr><td>[core]</td><td>buildingToFootprintOffsetX</td><td>"float"</td><td>10</td><td>"float"="float"px</td></tr>
<tr><td>[core]</td><td>buildingToFootprintOffsetY</td><td>"float"</td><td>10</td><td>"float"="float"px</td></tr>
<tr><td>[core]</td><td>placeOnlyOnResPool</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>selfBuildRate</td><td>"float"/"float"s</td><td>0</td><td>"float"=1/("float"s*60)</td></tr>
<tr><td>[core]</td><td>ignoreInUnitCapCalculation</td><td>"bool"</td><td>${core.isBuilding}</td><td></td></tr>
<tr><td>[core]</td><td>copyFrom</td><td>"filePath"(.ini)(s)</td><td></td><td>"filePath" = ./../xxx/xx/xxxx.ini</td></tr>
<tr><td>[core]</td><td>dont_load</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>overrideAndReplace</td><td>"unitName"(s)</td><td></td><td>"unitName" = ${core.name}</td></tr>
<tr><td>[core]</td><td>onNewMapSpawn</td><td>emptyResourcePools_asNeutral/emptyOrOccupiedResourcePools_asNeutral/mapCenter_asNeutral/mapCenter_eachActiveTeam/spawnPoint_eachActiveTeam</td><td></td><td></td></tr>
<tr><td>[core]</td><td>isLocked</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isLockedIfGameModeNoNuke</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>experimental</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>stayNeutral</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>createNeutral</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>createOnAggressiveTeam</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>tags</td><td>"tag"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>defineUnitMemory</td><td>boolean/float/number/unit/string "string"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>fogOfWarSightRange</td><td>"int"(>=0)</td><td>15</td><td>"int"="int"px</td></tr>
<tr><td>[core]</td><td>fogOfWarSightRangeWhileNotBuilt</td><td>"int"(>=0)</td><td>${core.fogOfWarSightRange}</td><td>"int"="int"px</td></tr>
<tr><td>[core]</td><td>softCollisionOnAll</td><td>"int"(>=0)</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>disableAllUnitCollisions</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isUnrepairableUnit</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isUnselectable</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>isUnselectableAsTarget</td><td>"bool"</td><td>${core.isUnselectable}</td><td></td></tr>
<tr><td>[core]</td><td>isPickableStartingUnit</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>startFallingWhenStartingUnit</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>soundOnAttackOrder</td><td>"filePath"(.ogg/.wav)(s)</td><td></td><td>"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)</td></tr>
<tr><td>[core]</td><td>soundOnMoveOrder</td><td>"filePath"(.ogg/.wav)(s)</td><td></td><td>"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)</td></tr>
<tr><td>[core]</td><td>soundOnNewSelection</td><td>"filePath"(.ogg/.wav)(s)</td><td></td><td>"filePath" = ./../xxx/xx/xxxx.ogg(/.wav)</td></tr>
<tr><td>[core]</td><td>canNotBeDirectlyAttacked</td><td>"bool"</td><td>false</td><td>[core]<del>canOnlyBeAttackedByUnitsWithTags:</del></td></tr>
<tr><td>[core]</td><td>canNotBeDamaged</td><td>"bool"</td><td>${core.canNotBeDirectlyAttacked}</td><td></td></tr>
<tr><td>[core]</td><td>canNotBeGivenOrdersByPlayer</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>canOnlyBeAttackedByUnitsWithTags</td><td>"tag"(s)</td><td></td><td>[core]<del>canNotBeDirectlyAttacked:</del></td></tr>
<tr><td>[core]</td><td>disableDeathOnZeroHp</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>transportSlotsNeeded</td><td>"int"(>=0)</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>maxTransportingUnits</td><td>"int"(>=0)</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsRequireTag</td><td>"tag"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsRequireMovementType</td><td>NONE/LAND/BUILDING/HOVER/OVER_CLIFF/OVER_CLIFF_WATER/AIR/WATER(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsBlockAirAndWaterUnits</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsKeepBuiltUnits</td><td>"logicBoolean"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsCanUnloadUnits</td><td>"logicBoolean"</td><td>if not (self.isOverLiquid or self.isMoving)</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsAddUnloadOption</td><td>"bool"</td><td>true/false(if ${core.transportUnitsCanUnloadUnits} == false)</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsUnloadDelayBetweenEachUnit</td><td>"float"/"float"s</td><td>30</td><td>"float"s="float"*60</td></tr>
<tr><td>[core]</td><td>transportUnitsKillOnDeath</td><td>"logicBoolean"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsHealBy</td><td>"float"</td><td>0</td><td>hp/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>transportUnitsBlockOtherTransports</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>whileNeutralTransportAnyTeam</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>whileNeutralConvertToTransportedTeam</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>convertToNeutralIfNotTransporting</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>transportUnitsOnTeamChangeKeepCurrentTeam</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>resourceRate</td><td>"float"(>0)</td><td>0</td><td>[core]switchPriceWithStreamingCost:false;[core]<del>StreamingCost:</del></td></tr>
<tr><td>[core]</td><td>similarResourcesHaveTag</td><td>"tag"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>resourceMaxConcurrentReclaimingThis</td><td>"int"(>=0)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>reclaimPrice</td><td>"int"/"customResourceX"="float"(s)</td><td></td><td>"int" = credits="int";[global_resource_"customResourceX"]/[resource_"customResourceX"]</td></tr>
<tr><td>[core]</td><td>canReclaimResources</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>canReclaimResourcesNextSearchRange</td><td>"int"(>=0)</td><td>500</td><td></td></tr>
<tr><td>[core]</td><td>canReclaimResourcesOnlyWithTags</td><td>"tag"(s)</td><td></td><td></td></tr>
<tr><td>[core]</td><td>canReclaimUnitsOnlyWithTags</td><td>"tag"(s)</td><td></td><td>[core]canRepairBuildings:true/[core]canRepairUnits:true</td></tr>
<tr><td>[core]</td><td>resourceReclaimMultiplier</td><td>"float"</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>canRepairUnitsOnlyWithTags</td><td>"tag"(s)</td><td></td><td>[core]canRepairBuildings:true/[core]canRepairUnits:true</td></tr>
<tr><td>[core]</td><td>canRepairBuildings</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>canRepairUnits</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>autoRepair</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>nanoRange</td><td>"int"(>=0)</td><td>85</td><td></td></tr>
<tr><td>[core]</td><td>nanoRepairSpeed</td><td>"float"</td><td>0.2</td><td>hp/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>nanoBuildSpeed</td><td>"float"(>=0)</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>nanoUnbuildSpeed</td><td>"float"(>=0)</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>nanoReclaimSpeed</td><td>"float"(>=0)</td><td>${core.nanoRepairSpeed}*5.1</td><td>hp/s=("float"*60)/s</td></tr>
<tr><td>[core]</td><td>nanoRangeForRepairIsMelee</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>nanoRangeForReclaimIsMelee</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>nanoRangeForRepair</td><td>"int"(>=0)</td><td>${core.nanoRange}</td><td></td></tr>
<tr><td>[core]</td><td>nanoRangeForReclaim</td><td>"int"(>=0)</td><td>${core.nanoRange}</td><td></td></tr>
<tr><td>[core]</td><td>nanoFactorySpeed</td><td>"float"(>=0)</td><td>1</td><td></td></tr>
<tr><td>[core]</td><td>extraBuildRangeWhenBuildingThis</td><td>"int"</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>builtFrom_"#"_name</td><td>"unitName"(s)</td><td></td><td>"#" = "int"(>=0);"unitName" = ${core.name}</td></tr>
<tr><td>[core]</td><td>builtFrom_"#"_pos</td><td>"float"</td><td></td><td>"#" = "int"(>=0)</td></tr>
<tr><td>[core]</td><td>builtFrom_"#"_forceNano</td><td>"bool"</td><td>false</td><td>"#" = "int"(>=0)</td></tr>
<tr><td>[core]</td><td>builtFrom_"#"_isLocked</td><td>"logicBoolean"</td><td>false</td><td>"#" = "int"(>=0)</td></tr>
<tr><td>[core]</td><td>builtFrom_"#"_isLockedMessage</td><td>"string"/i:"localeKey"</td><td></td><td>"#" = "int"(>=0);/assets/translations/Strings.properties-->"localeKey"=xxx</td></tr>
<tr><td>[core]</td><td>exit_x</td><td>"float"</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>exit_y</td><td>"float"</td><td>9</td><td></td></tr>
<tr><td>[core]</td><td>exit_dirOffset</td><td>"float"</td><td>180(units)/0(buildings)</td><td></td></tr>
<tr><td>[core]</td><td>exit_heightOffset</td><td>"float"</td><td>0</td><td></td></tr>
<tr><td>[core]</td><td>exit_moveAwayAmount</td><td>"float"</td><td>70</td><td></td></tr>
<tr><td>[core]</td><td>exitHeightIgnoreParent</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>dieOnConstruct</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>dieOnZeroEnergy</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>numBitsOnDeath</td><td>"int"(>=0)</td><td>4(if ${core.mass} <= 30000)/8(if ${core.mass} > 30000)/7(buildings)</td><td></td></tr>
<tr><td>[core]</td><td>nukeOnDeath</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>nukeOnDeathRange</td><td>"float"(>=0)</td><td>250</td><td></td></tr>
<tr><td>[core]</td><td>nukeOnDeathDamage</td><td>"float"</td><td>5400</td><td></td></tr>
<tr><td>[core]</td><td>nukeOnDeathDisableWhenNoNuke</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>fireTurretXAtSelfOnDeath</td><td>"turretX"</td><td></td><td>[turret_"turretX"]</td></tr>
<tr><td>[core]</td><td>explodeOnDeath</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>explodeOnDeathGroundCollision</td><td>"bool"</td><td>true</td><td></td></tr>
<tr><td>[core]</td><td>explodeTypeOnDeath</td><td>verysmall/small/normal/large/largeUnit/building/buildingNoShockwaveOrSmoke/verylargeBuilding(s)</td><td>normal</td><td></td></tr>
<tr><td>[core]</td><td>effectOnDeath</td><td>smoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)</td><td></td><td>[effect_"customEffectX"]</td></tr>
<tr><td>[core]</td><td>effectOnDeathGroundCollision</td><td>smoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)</td><td></td><td>[effect_"customEffectX"]</td></tr>
<tr><td>[core]</td><td>unitsSpawnedOnDeath</td><td>"unitName"*"int"(>=0)(s)</td><td></td><td>"unitName" = ${core.name}</td></tr>
<tr><td>[core]</td><td>unitsSpawnedOnDeath_setToTeamOfLastAttacker</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>hideScorchMark</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>soundOnDeath</td><td>"built-inSound"/"filePath"(.ogg/.wav)(s)</td><td></td><td>\res\raw\"built-inSound".ogg(/.wav)</td></tr>
<tr><td>[core]</td><td>effectOnDeathIfUnbuilt</td><td>smoke/shockwave/small/medium/large/CUSTOM:"customEffectX"*"int"(>=0)(s)</td><td></td><td>[effect_"customEffectX"]</td></tr>
<tr><td>[core]</td><td>autoTriggerCooldownTime</td><td>"float"(>=5;<120;>=0,if ${core.autoTriggerCooldownTime_allowDangerousHighCPU} == true)/"float"s(>=${5/60}s;<2s;>=0s,if ${core.autoTriggerCooldownTime_allowDangerousHighCPU} == true)</td><td>60</td><td></td></tr>
<tr><td>[core]</td><td>autoTriggerCooldownTime_allowDangerousHighCPU</td><td>"bool"</td><td>false</td><td></td></tr>
<tr><td>[core]</td><td>autoTriggerCheckRate</td><td>everyFrame/every4Frames/every8Frames</td><td>everyFrame</td><td></td></tr>
</table>


=== 注释 ===
=== 书写建议 ===
规范书写是为了方便阅读,在你使用眼睛查找某个参数时心中越多的筛选条件你找的就会越快,而我们直觉上会对写过的代码进行功能上的归类,所以你节之间插入两个以上的空行,几行参数组合形成的功能块你也可以在它们上下各空一行与其他参数进行分隔;而参数名称和值之间只有冒号未免拥挤,你可以在冒号后加入一个空格。
注释即为对代码的解释和说明。清晰的注释有利于帮助理解代码的含义。铁锈战争的<code>.ini</code>文件语法在注释方面提供了三种方式:


(1)用<code>#</code>进行单行的注释

在行的开头加上符号<code>#</code>后,游戏程序会忽略这一行的内容,不将其作为代码解析。但编写这些的人类可以注意到这些。
<pre style="white-space:pre;overflow:auto;">
[projectile_1]
#directDamage: 20
#有人反映单发伤害太低,这里改成了30
directDamage: 30
</pre>
(2)用<code>"""</code>和<code>"""</code>的组合进行多行注释

在行头使用<code>"""</code>作为起始,在之后的行尾使用<code>"""</code>作为结束。在其之间的内容均会被游戏忽略。
<pre style="white-space:pre;overflow:auto;">
"""
这是三个英文引号
实际上这个组合还有个功能,就是用它引住key: value的value使value可以换行输入如:
builtFrom_1_name: airFactory
可以是
builtFrom_1_name: """airF
actory"""
可是有一种情况,你用多行注释注释掉了有换行输入的内容它显然就会混乱,也就是目前的情况
"""
</pre>
(3)用<code>[comment_NAME]</code>进行成节的注释

该节之后的行直到下一个节前一行均不会被加载。
<pre style="white-space:pre;overflow:auto;">
[comment_hiddenAction_1]
autoTriggerOnEvent: created
addGlobalTeamTags: 计时
[comment_1]
maxHp: 2000
[core]
#[comment_NAME]节下的东西是不会被加载的,去引用它会提示找不到任何key
@copyFromSection: comment_1
</pre>
== mod-info.txt文件 ==
== mod-info.txt文件 ==
纯文本文件。游戏通过mod文件夹根目录读取<code>mod-info.txt</code>这样命名的文件来获得mod作者提供的mod描述信息。
UTF-8纯文本文件。游戏通过读取位于mod文件夹根目录<code>mod-info.txt</code>这样命名的文件来获得mod作者提供的mod描述信息。


格式:
相关参数解释:
<pre style="white-space:pre;overflow:auto;">
<pre style="white-space:pre;overflow:auto;margin:0;padding:0;width:100%;">
#(必填)
[mod]
[mod]
#(选填)告诉游戏能够支持该mod运行的最低游戏版本。若不满足最低版本,提示后仍可加载,但除地图外不可用,同时不提供代码错误的报错提醒。
#告诉游戏能够支持该mod运行的最低游戏版本。若不满足要求的最低版本,提示后仍可加载,但除地图外不可用,同时不提供代码错误的报错提醒。
minVersion: v1.14
minVersion: 1.15p7
#(必填)该mod在游戏中显示的标题
#该mod在游戏中显示的标题
title: Mega Builders
title: Mega Builders
#(选填)该mod在游戏中显示的描述。使用"\n"使其在游戏中换行显示(pc版换行显示)
#该mod在游戏中显示的描述。使用"\n"使其在显示时换行(pc版换行显示)
description: Example mod which replaces builders with Mega Builders.
description: Example mod which replaces builders with Mega Builders.


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


#该文件支持单行注释
#该文件支持单行注释
"""
"""
多行
多行
注释"""
注释
"""
</pre>
</pre>

== all-units.template文件 ==
== all-units.template文件 ==
<code>all-units.template</code>也是INI格式的文件。文件中的代码会自动应用到模组内的所有单位中(效果与使用<code>core</code>节下的<code>copyFrom</code>一致)到同级及以下级文件夹的所有<code>.ini</code>文件中。若存在代码错误,报错不会指向其本身,而是其所应用的<code>.ini</code>文件。
UTF-8纯文本文件。内容格式与<code>.ini</code>文件一致。游戏程序会识别<code>all-units.template</code>这样命名的文件,将其内容自动应用到同级及以下级的所有<code>.ini</code>文件中(效果与使用<code>core</code>节下的<code>copyFrom</code>一致)。若存在代码错误,报错不会指向其本身,而是其所应用的<code>.ini</code>文件。另外,若两文件同一参数的值存在冲突,下级的<code>all-units.template</code>会覆盖上级的<code>all-units.template</code>

2023年8月5日 (六) 15:39的最新版本

.ini文件

UTF-8纯文本文件。游戏通过读取以.ini为扩展名的文件来获得某个单位的参数信息。其内容主要由节(Section)和参数(Parameter)两部分组成。

格式

#节由两个半角方括号包裹,单独占一行
[section]
#参数由它的名称和它的值构成,名称和值使用半角冒号分隔,通常单独占一行
name: value

*另有部分代码存在不同的书写格式,待到具体代码再作讲解。

参数从属于节,要想具体参数从属于具体节,需将节写在参数行的上方;不同参数的值有不同类型,且规定有取值区间。

节的类型

截至1.15版本,节的类型有:

[core]--基础节,涉及单位的名称、生命值、体积大小、是建筑与否等基本设置。
[canBuild_NAME]--可建造节,涉及单位能建造生产那些单位,建造方式和条件等设置。
[graphics]--图像节,涉及单位主体贴图等设置。
[attack]--攻击节,涉及单位能攻击与否、最大攻击范围等设置。
[turret_NAME]--炮塔节,涉及单位炮塔的贴图、旋转速度、攻击间隔等设置。
[projectile_NAME]--炮弹节,涉及单位炮塔发射的弹丸的贴图、寿命、飞行速度、伤害等设置。
[movement]--移动节,涉及单位的移动类型、速度、转向速度等设置。
[ai]--AI节,涉及AI玩家对该单位的建造、升级概率以及部分单位特性等设置。
[arm_#]--臂节,涉及单位臂装饰物的位置、贴图等设置。
[leg_#]--腿节,同上。
[attachment_NAME]--附属节,涉及单位的子附属单位的位置、能攻击与否等设置。
[action_NAME]--操作节,涉及单位的资源手动添加、手动升级按钮、添加路径点等设置。
[hiddenAction_NAME]--隐藏的操作节,同上。
[effect_NAME]--特效节,涉及单位炮塔开火,弹丸飞行、爆炸等生成的特效的设置。
[animation_NAME]--动画节,涉及单位移动、部署、攻击等时机播放的帧动画的设置。
[placementRule_NAME]--放置规则节,单位建造时放置的规则的设置。
[global_resource_NAME]--全局资源节,队伍内单位通用的自定义资源的名称、样式设置。
[resource_NAME]--资源节,具体单位自用的自定义资源的名称样式设置
[template_NAME]--模板节,节之间复制参数时选用。
[comment_NAME]--注释节,用于大篇幅注释。
[decal_NAME]--贴花节,单位身上的贴花、伪3D等设置。

部分节可以自行添加名称或序号,如上面的"NAME"要求填写名称,"#"要求填写序号(1-20),这样得到的同类型不同名称的节,在应用时是各自独立的;允许重复书写一个节使其分布在文档的不同位置。

参数的类型

参数是文档中真正起作用的部分,每行参数必然关联者一个功能;参数(行)必须跟随在某个节的后面,以从属该节;节会因缺少必要参数而报错;部分参数有默认值,即使不写出也会起作用。
有关具体参数的参考请移步至mod参数

书写建议

规范书写是为了方便阅读,在你使用眼睛查找某个参数时心中越多的筛选条件你找的就会越快,而我们直觉上会对写过的代码进行功能上的归类,所以你节之间插入两个以上的空行,几行参数组合形成的功能块你也可以在它们上下各空一行与其他参数进行分隔;而参数名称和值之间只有冒号未免拥挤,你可以在冒号后加入一个空格。

mod-info.txt文件

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

格式:

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

#在游戏中播放mod里的.ogg或.wav音频文件作为背景音乐
[music]
#填音乐文件夹的路径
sourceFolder: soundtrack
#当使用该mod的单位时特别播放该mod的音乐,填"true"或"false"
whenUsingUnitsFromThisMod_playExclusively: true
#加入音乐播放列表,填"true"或"false"
addToNormalPlaylist: false

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

all-units.template文件

UTF-8纯文本文件。内容格式与.ini文件一致。游戏程序会识别all-units.template这样命名的文件,将其内容自动应用到同级及以下级的所有.ini文件中(效果与使用core节下的copyFrom一致)。若存在代码错误,报错不会指向其本身,而是其所应用的.ini文件。另外,若两文件同一参数的值存在冲突,下级的all-units.template会覆盖上级的all-units.template