Rules.ini: Difference between revisions
m →Python 3: debug |
There should not be a MOD file description here, even if its encrypted file has been cracked or there are numerous unauthorized modifications |
||
(6 intermediate revisions by one other user not shown) | |||
Line 29: | Line 29: | ||
|{{tt|expandmd01.mix}} | |{{tt|expandmd01.mix}} | ||
|Called {{tt|rules'''md'''.ini}}, for '''m'''ission '''d'''isk. | |Called {{tt|rules'''md'''.ini}}, for '''m'''ission '''d'''isk. | ||
|} | |} | ||
== Script to Read UnitsIdCode in Rules.ini == | == Script to Read UnitsIdCode in Rules.ini == | ||
=== Python 3 === | === Python 3 === | ||
;ReadRulesCode.py | |||
This script will read the rules.ini and list the UnitType, SequenceNum, UnitIdCode, UnitUIName, UnitInternalName and Armor, and store these informations into a txt file. | This script will read the rules.ini and list the UnitType, SequenceNum, UnitIdCode, UnitUIName, UnitInternalName and Armor, and store these informations into a txt file. | ||
To get the CSF.ini that required in this script, please go to page [[CSF File Format#Decode Script|CSF File Format]]. | To get the CSF.ini that required in this script, please go to page [[CSF File Format#Decode Script|CSF File Format]]. | ||
{| | {| | ||
| style="text-align:right; line-height:1.3em;" |1<br/>2<br/>3<br/>4<br/>5<br/>6<br/>7<br/>8<br/>9<br/>10<br/>11<br/>12<br/>13<br/>14<br/>15<br/>16<br/>17<br/>18<br/>19<br/>20<br/>21<br/>22<br/>23<br/>24<br/>25<br/>26<br/>27<br/>28<br/>29<br/>30<br/>31<br/>32<br/>33<br/>34<br/>35<br/>36<br/>37<br/>38<br/>39<br/>40<br/>41<br/>42<br/>43<br/>44<br/>45<br/>46<br/>47<br/>48<br/>49<br/>50<br/>51<br/>52<br/>53<br/>54<br/>55<br/>56<br/>57<br/>58<br/>59<br/>60<br/>61<br/>62<br/>63<br/>64<br/>65<br/>66<br/>67<br/>68<br/>69<br/>70<br/>71<br/>72<br/>73<br/>74<br/>75<br/>76<br/>77 | | style="text-align:right; line-height:1.3em; font-family:Consolas,monospace,Courier,serif;" |1<br/>2<br/>3<br/>4<br/>5<br/>6<br/>7<br/>8<br/>9<br/>10<br/>11<br/>12<br/>13<br/>14<br/>15<br/>16<br/>17<br/>18<br/>19<br/>20<br/>21<br/>22<br/>23<br/>24<br/>25<br/>26<br/>27<br/>28<br/>29<br/>30<br/>31<br/>32<br/>33<br/>34<br/>35<br/>36<br/>37<br/>38<br/>39<br/>40<br/>41<br/>42<br/>43<br/>44<br/>45<br/>46<br/>47<br/>48<br/>49<br/>50<br/>51<br/>52<br/>53<br/>54<br/>55<br/>56<br/>57<br/>58<br/>59<br/>60<br/>61<br/>62<br/>63<br/>64<br/>65<br/>66<br/>67<br/>68<br/>69<br/>70<br/>71<br/>72<br/>73<br/>74<br/>75<br/>76<br/>77 | ||
| | | | ||
<div style="line-height:1.3em;"> | <div> | ||
<span style="line-height:1.3em; font-family:Consolas,monospace,Courier,serif;"># set the directory of rules.ini here | |||
# need to modify the rules.ini if there are any error reports during reading it by module configparser | # need to modify the rules.ini if there are any error reports during reading it by module configparser | ||
rules_dir=r"C:\Users\August\Documents\rulesmo_mod.ini" | rules_dir=r"C:\Users\August\Documents\rulesmo_mod.ini" | ||
Line 79: | Line 75: | ||
f.write(content) | f.write(content) | ||
def cut_ref(content: str) -> str: | def cut_ref(content: str) -> str: | ||
"""cut the reference in ini file""" | """cut out the reference in ini file""" | ||
if ";" in content: | if ";" in content: | ||
content= | content=content[:content.find(";")] | ||
return content. | return content.lstrip().rstrip()<br/> | ||
# clear the output file | # clear the output file | ||
clear_file(ofdir) | clear_file(ofdir) | ||
Line 119: | Line 115: | ||
os.startfile(ofdir) | os.startfile(ofdir) | ||
except: | except: | ||
pass | pass</span> | ||
</div> | |||
|} | |||
;CorrectRulesCode.py | |||
This script will correct the rules.ini with a large amount of duplicate definition and invalid codes, cut out the useless references line without "=", and write a new rules.ini to store the result, so that the module configparser in Python can read it. | |||
{| | |||
| style="text-align:right; line-height:1.3em; font-family:Consolas,monospace,Courier,serif;" |1<br/>2<br/>3<br/>4<br/>5<br/>6<br/>7<br/>8<br/>9<br/>10<br/>11<br/>12<br/>13<br/>14<br/>15<br/>16<br/>17<br/>18<br/>19<br/>20<br/>21<br/>22<br/>23<br/>24<br/>25<br/>26<br/>27<br/>28<br/>29<br/>30<br/>31<br/>32<br/>33<br/>34<br/>35<br/>36<br/>37<br/>38<br/>39<br/>40<br/>41<br/>42<br/>43<br/>44<br/>45<br/>46<br/>47<br/>48<br/>49 | |||
| | |||
<div> | |||
<span style="line-height:1.3em; font-family:Consolas,monospace,Courier,serif;"># set the directories of input and output files | |||
ifdir=r"C:\Users\August\Documents\rulesmo_mod0.ini" | |||
# ifdir=r"/storage/emulated/0/1/rulesmo_mod0.ini" | |||
ofdir=r"C:\Users\August\Documents\rulesmo_mod.ini" | |||
# ofdir=r"/storage/emulated/0/1/rulesmo_mod.ini" | |||
# read the input rules.ini | |||
with open(ifdir, "r", encoding="UTF-8") as f: | |||
content=f.read() | |||
# use str.replace() method to remove useless codes | |||
dic={"\t": "", " \n": "\n", "\n\n": "\n", " ;": ";", | |||
" =": "=", "= ": "="} | |||
for key in dic: | |||
while content.find(key)!=-1: | |||
content=content.replace(key, dic[key]) | |||
# split the content as a list by section header | |||
li=content.split("\n[") | |||
# remove not-section item in list | |||
if "]" not in li[0]: | |||
li=li[1:] | |||
# creat a dictionary to store the information | |||
dic=dict() | |||
# read content by sections | |||
for i in li: | |||
# split the section name and the option-value pairs | |||
sec, opt_s=i.split("]")[0], i.split("]")[1] | |||
# creat a dictionary to store the option-value pairs in this section | |||
dic[sec]=dict() | |||
# split the option-value pairs by line break between each of them | |||
opt_li_orig=opt_s.split("\n") | |||
# separate the useful line with "=" to cut out the lines only contain references | |||
opt_li=list() | |||
for opt_i in opt_li_orig: | |||
if "=" in opt_i: | |||
opt_li.append(opt_i) | |||
# seperate the option and value of the pairs | |||
for opt_i in opt_li: | |||
opt, val=opt_i.split("=")[0], opt_i.split("=")[1] | |||
# cut out the references behind the value | |||
if ";" in val: | |||
val=val[:val.find(";")] | |||
# store the option-value pairs | |||
dic[sec][opt]=val | |||
# write the output file as the ini format | |||
with open(ofdir, "w", encoding="UTF-8") as f: | |||
for sec in dic: | |||
f.write("["+sec+"]\n") | |||
for opt in dic[sec]: | |||
f.write(opt+"="+dic[sec][opt]+"\n") | |||
f.write("\n")</span> | |||
</div> | </div> | ||
|} | |} |
Latest revision as of 12:09, 8 November 2024
The rules.ini (naming variations for expansions) is the core file of C&C modding. As indicated by the name, it contains the "rules" of the game – the properties of every object, weapon, warhead, etc. in the game. For any C&C game from Red Alert to Yuri's Revenge, this is the main modification file. For Generals and everything else based on the SAGE engine, the INI-system is more complex and wide-spread.
Disregarding the side functions of the other various INI files (like ai.ini or art.ini), there is no way to make any changes to the game other than what the rules.ini allows for1. Not everything in the game is customizable. Features that cannot be modified are called "hardcoded" features.
File Locations
Game | Location | Notes |
---|---|---|
Red Alert | redalert.mix → local.mix | |
Tiberian Sun | tibsun.mix → local.mix | The patches add a new rules.ini to patch.mix |
Firestorm | expand01.mix | rules-equivalent is called firestrm.ini, the mix also contains a new rules.ini for regular TS. |
Red Alert 2 | ra2.mix → local.mix | |
Yuri's Revenge | expandmd01.mix | Called rulesmd.ini, for mission disk. |
Script to Read UnitsIdCode in Rules.ini
Python 3
- ReadRulesCode.py
This script will read the rules.ini and list the UnitType, SequenceNum, UnitIdCode, UnitUIName, UnitInternalName and Armor, and store these informations into a txt file.
To get the CSF.ini that required in this script, please go to page CSF File Format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# set the directory of rules.ini here
# need to modify the rules.ini if there are any error reports during reading it by module configparser
rules_dir=r"C:\Users\August\Documents\rulesmo_mod.ini"
# rules_dir=r"/storage/emulated/0/1/rulesmo_mod.ini"
# set the output file directory
ofdir=r"C:\Users\August\Documents\UnitCodes.txt"
# ofdir=r"/storage/emulated/0/1/UnitCodes.txt"
# set the directory of CSF.ini that decoded by ReadCsf.py
csf_ini_dir=r"C:\Users\August\Documents\CSF.ini"
# csf_ini_dir=r"/storage/emulated/0/1/CSF/CSF.ini"
|
- CorrectRulesCode.py
This script will correct the rules.ini with a large amount of duplicate definition and invalid codes, cut out the useless references line without "=", and write a new rules.ini to store the result, so that the module configparser in Python can read it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# set the directories of input and output files
ifdir=r"C:\Users\August\Documents\rulesmo_mod0.ini"
# ifdir=r"/storage/emulated/0/1/rulesmo_mod0.ini"
ofdir=r"C:\Users\August\Documents\rulesmo_mod.ini"
# ofdir=r"/storage/emulated/0/1/rulesmo_mod.ini"
# read the input rules.ini
with open(ifdir, "r", encoding="UTF-8") as f:
content=f.read()
# use str.replace() method to remove useless codes
dic={"\t": "", " \n": "\n", "\n\n": "\n", " ;": ";",
" =": "=", "= ": "="}
for key in dic:
while content.find(key)!=-1:
content=content.replace(key, dic[key])
# split the content as a list by section header
li=content.split("\n[")
# remove not-section item in list
if "]" not in li[0]:
li=li[1:]
# creat a dictionary to store the information
dic=dict()
# read content by sections
for i in li:
# split the section name and the option-value pairs
sec, opt_s=i.split("]")[0], i.split("]")[1]
# creat a dictionary to store the option-value pairs in this section
dic[sec]=dict()
# split the option-value pairs by line break between each of them
opt_li_orig=opt_s.split("\n")
# separate the useful line with "=" to cut out the lines only contain references
opt_li=list()
for opt_i in opt_li_orig:
if "=" in opt_i:
opt_li.append(opt_i)
# seperate the option and value of the pairs
for opt_i in opt_li:
opt, val=opt_i.split("=")[0], opt_i.split("=")[1]
# cut out the references behind the value
if ";" in val:
val=val[:val.find(";")]
# store the option-value pairs
dic[sec][opt]=val
# write the output file as the ini format
with open(ofdir, "w", encoding="UTF-8") as f:
for sec in dic:
f.write("["+sec+"]\n")
for opt in dic[sec]:
f.write(opt+"="+dic[sec][opt]+"\n")
f.write("\n")
|
Footnotes
1 ↑ An exception to this would be pd's RockPatch.
See Also
- Art.ini
- Sound.ini
- CSF
- Hardcoded features
- Rules(md).ini Sections
- Rules(md).ini Flags
- Lists of Applicable INI Flags