"name and attrib index"
{
"cloak is phase shift" // This attribute has class/slot restrictions to prevent broken gameplay from malformed custom weapons.
{
"index" "1001" // Sounds + Physics
"classes" // When the "classes" key is present, only classes listed here can use this attribute. Putting the attribute on a weapon for another class will simply have it be ignored when the weapon config is loaded. If it's a multi-class weapon, the attribute will only work on that class.
{
"spy" "4" // The number here is the slot it's available on. "-1,0,1,2,3,4,5" or "all" would make the attribute available for all slots. -1 means it's applied to the player instead of a weapon.
}
//"flags" "abcdefz" // Must have all of these admin flags.
//"weapons" "tf_weapon_invis" // Weapon classname must match this. Be warned that it's possible to give a scout a tf_weapon_sniperrifle. , commas to name multiple weapons.
}
"remove buffs on cloak" "1002" // HARDCODED - TODO: Support TFCond_Stealthed
"remove debuffs on cloak" "1003" // HARDCODED - TODO: Support TFCond_Stealthed
"remove particle effects during cloak" "1004" // - TODO: Support TFCond_Stealthed
"set remaining cloak after decloak" "1005" // Expected value is 0.0 - 100.0 // I could restrict this to spy watches, but it'll probably be harmless anyway (I won't be making a config trying to put this on a scout weapon at least)
"set invis change complete time" "1006" // Time in seconds // And the above attrib doesn't cause sound effects to play like "cloak is phase shift" does.
"set decloak next attack time" "1007" // Time in seconds
"set srifle init charge" "1008" // Expected value is 0.0 - 150.0
"srifle negative charge rate" "1009" // Srifle charge degenerates.
"meet the sniper combo" // %f %f %f - Multipliers for each hit in the combo (default is 0.35 0.6 3.0)
{
"index" "1010" // Sniper Rifle is "The Walkabout"
"classes"
{
"sniper" "0" // This spams sniper related noises and is very hardcoded, let's keep it on sniper rifles only.
}
"weapons" "tf_weapon_sniperrifle"
}
"rubber rockets"
{
"index" "1011" // %i %f Number of bounces before exploding, proximity for auto detonation
"classes"
{
"soldier" "0"
}
}
"set projectile movetype" "1012"
"set projectile gravity" "1013"
"set projectile model" "1014" // %f %s flModelScale (0.0 or higher) "model/path.mdl" | Do not use with the attribute below
"attach projectile model" "1015" // This version is double the entity, but keeps trail particles that were on the old entity
"set nade detonate timer"
{
"index" "1016" // Can set the detonation time of grenades to be shorter or longer
"weapons" "tf_weapon_grenadelauncher"
}
"set nade flash timer"
{
"index" "1017" // A small particle effect indicating the nade is primed / about to explode
"weapons" "tf_weapon_grenadelauncher"
}
"set sine bow"
{
"index" "1018" // Makes arrows move in a wave pattern.
"weapons" "tf_weapon_compound_bow"
}
"set projectile death" "1019" // Projectile dies after X seconds.
"dmg scales by projectile life" "1020" // Every second of the entity's life increases its damage. %f %f %f flBase flScale flMax
"infinite clip" "1021" // Gives your weapon infinite clip. Value determines what number the clip is set to.
"set medieval banner" // %f %f %f Distance, Duration, Damage // 450.0 10 480
{
"index" "1022" // The Battlefield Backpack
"weapons" "tf_weapon_buff_item"
}
"grordbort shield"
{
"index" "1023" // Shield attribs only apply to secondary slot. This controls charging in 'any direction' and blocking charge until you touch the ground again, if you hit 0% charge.
"classes"
{
"demoman" "1"
}
"weapons" "tf_wearable_demoshield"
}
"dmg resist while charging"
{
"index" "1024" // %f - direct multiplier to damage
"classes"
{
"demoman" "1"
}
}
"charge without full meter"
{
"index" "1025" // %f - how much charge is needed to charge
"classes"
{
"demoman" "1"
}
"weapons" "tf_wearable_demoshield"
}
"charge cancel adds charge"
{
"index" "1026" // %f amount of charge to add every time charge is canceled, can be negative, min/max | 0.0/100.0
"classes"
{
"demoman" "1"
}
"weapons" "tf_wearable_demoshield"
}
"attack2 cancels charge"
{
"index" "1027" // In addition to just attacking again
"classes"
{
"demoman" "1"
}
}
"urine trouble"
{
"index" "1028" // %f - One-Time Backstab damage reduction
"classes"
{
"sniper" "1"
}
"weapons" "tf_wearable"
}
"mediraydar" "1029" // %f %i %f %f // distance, healing, selfhealing, [UNUSED]->uber duration
"alt fire and death kamikaze" "1030" // %i %i %f %f %f // dmg, radius, fuse time, speed modifier while timebomb, gravity modifier while timebomb
}
And some code to traverse it that doesn't really work properly.
Spoiler
PHP Code:
new Handle:hKvFile = CreateKeyValues("arbitrarykeyvaluerootname"); if (!FileToKeyValues(hKvFile, szFullFilePath)) { LogError("broken config %s", szFullFilePath); CloseHandle(hDir); continue; }
decl String:szSection[64], String:szValue[64]; new bool:bFirst = true; do { if (KvGotoFirstSubKey(hKvFile, false)) { // Current key is a section.
if (!bFirst) // Without this, every sub-section other than "cloak is phase shift" gets completely skipped, but it does get all the single line key value pairs down to "alt fire and death kamikaze" { KvGoBack(hKvFile); } bFirst = false;
new iDefIndex = KvGetNum(hKvFile, "index", -1); if (iDefIndex == -1) { LogError("Attribute %s has no index assigned to it and its registration was skipped!", szSection); } else { IntToString(iDefIndex, szValue, sizeof(szValue)); LogMessage("%i %s %s", iDefIndex, szSection, szFileName);
if (KvJumpToKey(hKvFile, "classes")) { for (new iClass = 1; iClass < TF_MAX_CLASSES; iClass++) { switch (iClass) { case TFClass_Scout: KvGetString(hKvFile, "scout", szValue, sizeof(szValue)); case TFClass_Soldier: KvGetString(hKvFile, "soldier", szValue, sizeof(szValue)); case TFClass_Pyro: KvGetString(hKvFile, "pyro", szValue, sizeof(szValue)); case TFClass_DemoMan: KvGetString(hKvFile, "demoman", szValue, sizeof(szValue)); case TFClass_Heavy: KvGetString(hKvFile, "heavy", szValue, sizeof(szValue)); case TFClass_Engineer: KvGetString(hKvFile, "engineer", szValue, sizeof(szValue)); case TFClass_Medic: KvGetString(hKvFile, "medic", szValue, sizeof(szValue)); case TFClass_Sniper: KvGetString(hKvFile, "sniper", szValue, sizeof(szValue)); case TFClass_Spy: KvGetString(hKvFile, "spy", szValue, sizeof(szValue)); }
if (szValue[0] == '\0') { continue; }
LogMessage(szValue); } } } KvGoBack(hKvFile); } else { // Current key is a regular key, or an empty section. if (KvGetDataType(hKvFile, NULL_STRING) != KvData_None) { KvGetSectionName(hKvFile, szSection, sizeof(szSection)); KvGetString(hKvFile, NULL_STRING, szValue, sizeof(szValue)); LogMessage("oneline %s %s %s", szValue, szSection, szFileName); } else { // This part never ever fires no matter what I'm doing, which is expected. KvGetSectionName(hKvFile, szSection, sizeof(szSection)); LogMessage("lolwat %s %s", szSection, szFileName); } } } while (KvGotoNextKey(hKvFile, false));
CloseHandle(hKvFile);
The output looks like this:
Spoiler
Code:
L 06/25/2016 - 08:40:48: [basecommands.smx] "C:/hdata<9><[U:1:83288335]><>" console command (cmdline "sm plugins reload cw4")
L 06/25/2016 - 08:40:48: [cw4.smx] 1001 cloak is phase shift chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx] 4
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1002 remove buffs on cloak chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1003 remove debuffs on cloak chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1004 remove particle effects during cloak chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1005 set remaining cloak after decloak chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1006 set invis change complete time chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1007 set decloak next attack time chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1008 set srifle init charge chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1009 srifle negative charge rate chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] 1010 meet the sniper combo chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx] tf_weapon_sniperrifle
L 06/25/2016 - 08:40:48: [cw4.smx] 0
L 06/25/2016 - 08:40:48: [cw4.smx] 1011 rubber rockets chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx] 0
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1012 set projectile movetype chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1013 set projectile gravity chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1014 set projectile model chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] oneline 1015 attach projectile model chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx] 1016 set nade detonate timer chdata-attributes.smx
L 06/25/2016 - 08:40:48: [cw4.smx]
L 06/25/2016 - 08:40:48: [cw4.smx] tf_weapon_grenadelauncher
L 06/25/2016 - 08:40:48: [cw4.smx] [Custom Weapons] Custom Weapons loaded successfully with 47 weapons, 11 plugins 69 models 18 sounds.
Notice that it stops at "set nade detonate timer".
This is the first area in the config where multiple sub-sections in a row appear.
Also, if the first "keyvalue" isn't a sub-section, but is instead just a normal key value pair, it just doesn't read anything at all.
For example, if I put "test" "123" above "cloak is phase shift", LogMessage never fires. We just get this: