- MUCH easier for us to automatically create a config for all races every time we startup WITHOUT overwriting custom content
- Much easier for server operators to understand:
Code:
"Races"
{
"undead"
{
"<config key>" "<value>"
}
}
- Easily allow for races to register arbitrary values and defaults{
"undead"
{
"<config key>" "<value>"
}
}
- Probably a lot of other good things (best reason there!)
As the responses have been overwhelmingly positive I'm going to go into a bit more detail about the system I'm designing.
There will be either two or three configs (undecided about whether addons REALLY need their own config section, most of what they do can be done with a SMALL number of cvars, or additions on the race/item configs) one for items and one for races, each race/item will have a section named using their shortname along with a set of keys and values set by plugins.
The idea is to make everything as simple as possible and have almost everything be completely invisible to the plugin developer and easily modifiable by the server operator and to that end the natives I'm proposing are as follows:
Code:
// Easiest method - simply takes a raceID, converts it to a shortname then adds the default to the internal KV
native War3_SetRaceConfigDefault(raceID, String:key[], String:default[]);
// Takes a race shortname and adds the default to the internal KV
native War3_SetRaceConfigDefaultByName(String:shortname[], String:key[], String:default[]);
// Sets a default value for a raceID/key combination
native War3_SetRaceConfigCell(raceID, String:key[], any:default);
// Sets a default value for a shortname/key combination
native War3_SetRaceConfigCell(String:shortname[], String:key[], any:default);
// Takes a key and a value and applies it to all currently loaded races
native War3_SetGlobalRaceConfigDefault(String:key[], String:default[]);
// Gets a value for a raceID/key combination, returning a float/int/bool
native War3_GetRaceConfigCell(raceID, String:key[]);
// Gets a value for a shortname/key combination, returning a float/int/bool
native War3_GetRaceConfigCell(String:shortname[], String:key[]);
// Gets a value for a raceID/key combination, returning a float/int/bool
native War3_GetRaceConfigString(raceID, String:key[], String:value[], maxlen);
// Gets a value for a shortname/key combination, returning a float/int/bool
native War3_GetRaceConfigString(String:shortname[], String:key[], String:value[], maxlen);
native War3_SetRaceConfigDefault(raceID, String:key[], String:default[]);
// Takes a race shortname and adds the default to the internal KV
native War3_SetRaceConfigDefaultByName(String:shortname[], String:key[], String:default[]);
// Sets a default value for a raceID/key combination
native War3_SetRaceConfigCell(raceID, String:key[], any:default);
// Sets a default value for a shortname/key combination
native War3_SetRaceConfigCell(String:shortname[], String:key[], any:default);
// Takes a key and a value and applies it to all currently loaded races
native War3_SetGlobalRaceConfigDefault(String:key[], String:default[]);
// Gets a value for a raceID/key combination, returning a float/int/bool
native War3_GetRaceConfigCell(raceID, String:key[]);
// Gets a value for a shortname/key combination, returning a float/int/bool
native War3_GetRaceConfigCell(String:shortname[], String:key[]);
// Gets a value for a raceID/key combination, returning a float/int/bool
native War3_GetRaceConfigString(raceID, String:key[], String:value[], maxlen);
// Gets a value for a shortname/key combination, returning a float/int/bool
native War3_GetRaceConfigString(String:shortname[], String:key[], String:value[], maxlen);
Obviously the same thing for items.
The values set here would be kept in one KV (for speed during initial load, likely between OnPluginLoad and OnAllPluginsLoaded this is NOT written to disk, with one write during OnAllPluginsLoaded), whenever loading is finished or during later calls to SetDefault, the values set is then copied into a second keyvalue (the one actually used for lookups), at which point the actual config is loaded up and copied into that keyvalue, and the whole keyvalue is written to the main config (ensuring that all defaults will remain), then any map-specific configs are read and copied into that same keyvalue. This entire process should take just a few milliseconds, but if takes much longer than that I can definitely do a little bit of restructuring to make it faster (albeit harder to read and understand).
The config is also read during any map changes, to ensure that the latest version is always used and any map-specific configs are used
Note: This WILL completely replace the war3 var system.
Example usage:
Code:
/**
* File: War3Source_UndeadScourge.sp
* Description: The Undead Scourge race for War3Source.
* Author(s): Anthony Iacono, Necavi
*/
#pragma semicolon 1
#include <sourcemod>
#include "W3SIncs/War3Source_Interface"
public W3ONLY(){} //unload this?
// War3Source stuff
new thisRaceID;
// Chance/Data Arrays
new Float:SuicideBomberRadius[5]={0.0,250.0,290.0,310.0,333.0};
new Float:SuicideBomberDamage[5]={0.0,166.0,200.0,233.0,266.0};
new Float:SuicideBomberDamageTF[5]={0.0,133.0,175.0,250.0,300.0};
new Float:UnholySpeed[5]={1.0,1.05,1.10,1.15,1.20};
new Float:LevitationGravity[5]={1.0,0.85,0.7,0.6,0.5};
new Float:VampirePercent[5]={0.0,0.08,0.14,0.20,0.25};
new SKILL_LEECH,SKILL_SPEED,SKILL_LOWGRAV,SKILL_SUICIDE;
public Plugin:myinfo =
{
name = "Race - Undead Scourge",
author = "PimpinJuice, Necavi",
description = "The Undead Scourge race for War3Source.",
version = "1.0",
url = "http://war3source.com"
};
// War3Source Functions
public OnPluginStart()
{
LoadTranslations("w3s.race.undead.phrases");
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberRadius", SuicideBomberRadius);
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberDamage", SuicideBomberDamage);
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberDamageTF", SuicideBomberDamageTF);
War3_SetRaceConfigDefaultArray(thisRaceID, "UnholySpeed", UnholySpeed);
War3_SetRaceConfigDefaultArray(thisRaceID, "LevitationGravity", LevitationGravity);
War3_SetRaceConfigDefaultArray(thisRaceID, "VampirePercent", VampirePercent);
}
public OnWar3LoadRaceOrItemOrdered(num)
{
if(num==10)
{
thisRaceID=War3_CreateNewRaceT("undead");
SKILL_LEECH=War3_AddRaceSkillT(thisRaceID,"VampiricAura",false,4,"25%");
SKILL_SPEED=War3_AddRaceSkillT(thisRaceID,"UnholyAura",false,4,"20%");
SKILL_LOWGRAV=War3_AddRaceSkillT(thisRaceID,"Levitation",false,4,"0.5");
SKILL_SUICIDE=War3_AddRaceSkillT(thisRaceID,"SuicideBomber",true,4);
War3_CreateRaceEnd(thisRaceID);
}
}
public OnWar3ConfigLoaded()
{
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberRadius", SuicideBomberRadius, sizeof(SuicideBomberRadius));
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberDamage", SuicideBomberDamage, sizeof(SuicideBomberDamage));
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberDamageTF", SuicideBomberDamageTF, sizeof(SuicideBomberDamageTF));
War3_GetRaceConfigArray(thisRaceID, "UnholySpeed", UnholySpeed, sizeof(UnholySpeed));
War3_GetRaceConfigArray(thisRaceID, "LevitationGravity", LevitationGravity, sizeof(LevitationGravity));
War3_GetRaceConfigArray(thisRaceID, "VampirePercent", VampirePercent, sizeof(VampirePercent));
}
public OnUltimateCommand(client,race,bool:pressed)
{
if(pressed && War3_GetRace(client)==thisRaceID && IsPlayerAlive(client) && !Silenced(client))
{
new ult_level=War3_GetSkillLevel(client,race,SKILL_SUICIDE);
if(ult_level>0)
{
ForcePlayerSuicide(client);
}
else
{
//DP("undad ");
W3MsgUltNotLeveled(client);
}
}
}
public OnSkillLevelChanged(client,race,skill,newskilllevel)
{
InitPassiveSkills(client);
}
public InitPassiveSkills(client){
if(War3_GetRace(client)==thisRaceID)
{
new skilllevel_unholy=War3_GetSkillLevel(client,thisRaceID,SKILL_SPEED);
new Float:speed=UnholySpeed[skilllevel_unholy];
War3_SetBuff(client,fMaxSpeed,thisRaceID,speed);
new skilllevel_levi=War3_GetSkillLevel(client,thisRaceID,SKILL_LOWGRAV);
new Float:gravity=LevitationGravity[skilllevel_levi];
War3_SetBuff(client,fLowGravitySkill,thisRaceID,gravity);
new skilllevel_vampire=War3_GetSkillLevel(client,thisRaceID,SKILL_LEECH);
new Float:percent=VampirePercent[skilllevel_vampire];
War3_SetBuff(client,fVampirePercent,thisRaceID,percent);
}
}
public OnRaceChanged(client,oldrace,newrace)
{
if(newrace!=thisRaceID)
{
War3_SetBuff(client, fMaxSpeed, thisRaceID, 1.0);
War3_SetBuff(client, fLowGravitySkill, thisRaceID, 1.0);
War3_SetBuff(client, fVampirePercent, thisRaceID, 0.0);
}
else
{
if(IsPlayerAlive(client)){
InitPassiveSkills(client);
}
}
}
public OnWar3EventDeath(victim, attacker)
{
new race=W3GetVar(DeathRace);
new skill=War3_GetSkillLevel(victim,thisRaceID,SKILL_SUICIDE);
if(race==thisRaceID && skill>0 && !Hexed(victim))
{
decl Float:location[3];
GetClientAbsOrigin(victim,location);
if(War3_GetGame()==Game_TF)
{
War3_SuicideBomber(victim, location, SuicideBomberDamageTF[skill], SKILL_SUICIDE, SuicideBomberRadius[skill]);
} else {
War3_SuicideBomber(victim, location, SuicideBomberDamage[skill], SKILL_SUICIDE, SuicideBomberRadius[skill]);
}
}
}
public OnWar3EventSpawn(client)
{
new race=War3_GetRace(client);
if(race==thisRaceID)
{
InitPassiveSkills(client); //sets suicide
}
}
* File: War3Source_UndeadScourge.sp
* Description: The Undead Scourge race for War3Source.
* Author(s): Anthony Iacono, Necavi
*/
#pragma semicolon 1
#include <sourcemod>
#include "W3SIncs/War3Source_Interface"
public W3ONLY(){} //unload this?
// War3Source stuff
new thisRaceID;
// Chance/Data Arrays
new Float:SuicideBomberRadius[5]={0.0,250.0,290.0,310.0,333.0};
new Float:SuicideBomberDamage[5]={0.0,166.0,200.0,233.0,266.0};
new Float:SuicideBomberDamageTF[5]={0.0,133.0,175.0,250.0,300.0};
new Float:UnholySpeed[5]={1.0,1.05,1.10,1.15,1.20};
new Float:LevitationGravity[5]={1.0,0.85,0.7,0.6,0.5};
new Float:VampirePercent[5]={0.0,0.08,0.14,0.20,0.25};
new SKILL_LEECH,SKILL_SPEED,SKILL_LOWGRAV,SKILL_SUICIDE;
public Plugin:myinfo =
{
name = "Race - Undead Scourge",
author = "PimpinJuice, Necavi",
description = "The Undead Scourge race for War3Source.",
version = "1.0",
url = "http://war3source.com"
};
// War3Source Functions
public OnPluginStart()
{
LoadTranslations("w3s.race.undead.phrases");
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberRadius", SuicideBomberRadius);
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberDamage", SuicideBomberDamage);
War3_SetRaceConfigDefaultArray(thisRaceID, "SuicideBomberDamageTF", SuicideBomberDamageTF);
War3_SetRaceConfigDefaultArray(thisRaceID, "UnholySpeed", UnholySpeed);
War3_SetRaceConfigDefaultArray(thisRaceID, "LevitationGravity", LevitationGravity);
War3_SetRaceConfigDefaultArray(thisRaceID, "VampirePercent", VampirePercent);
}
public OnWar3LoadRaceOrItemOrdered(num)
{
if(num==10)
{
thisRaceID=War3_CreateNewRaceT("undead");
SKILL_LEECH=War3_AddRaceSkillT(thisRaceID,"VampiricAura",false,4,"25%");
SKILL_SPEED=War3_AddRaceSkillT(thisRaceID,"UnholyAura",false,4,"20%");
SKILL_LOWGRAV=War3_AddRaceSkillT(thisRaceID,"Levitation",false,4,"0.5");
SKILL_SUICIDE=War3_AddRaceSkillT(thisRaceID,"SuicideBomber",true,4);
War3_CreateRaceEnd(thisRaceID);
}
}
public OnWar3ConfigLoaded()
{
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberRadius", SuicideBomberRadius, sizeof(SuicideBomberRadius));
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberDamage", SuicideBomberDamage, sizeof(SuicideBomberDamage));
War3_GetRaceConfigArray(thisRaceID, "SuicideBomberDamageTF", SuicideBomberDamageTF, sizeof(SuicideBomberDamageTF));
War3_GetRaceConfigArray(thisRaceID, "UnholySpeed", UnholySpeed, sizeof(UnholySpeed));
War3_GetRaceConfigArray(thisRaceID, "LevitationGravity", LevitationGravity, sizeof(LevitationGravity));
War3_GetRaceConfigArray(thisRaceID, "VampirePercent", VampirePercent, sizeof(VampirePercent));
}
public OnUltimateCommand(client,race,bool:pressed)
{
if(pressed && War3_GetRace(client)==thisRaceID && IsPlayerAlive(client) && !Silenced(client))
{
new ult_level=War3_GetSkillLevel(client,race,SKILL_SUICIDE);
if(ult_level>0)
{
ForcePlayerSuicide(client);
}
else
{
//DP("undad ");
W3MsgUltNotLeveled(client);
}
}
}
public OnSkillLevelChanged(client,race,skill,newskilllevel)
{
InitPassiveSkills(client);
}
public InitPassiveSkills(client){
if(War3_GetRace(client)==thisRaceID)
{
new skilllevel_unholy=War3_GetSkillLevel(client,thisRaceID,SKILL_SPEED);
new Float:speed=UnholySpeed[skilllevel_unholy];
War3_SetBuff(client,fMaxSpeed,thisRaceID,speed);
new skilllevel_levi=War3_GetSkillLevel(client,thisRaceID,SKILL_LOWGRAV);
new Float:gravity=LevitationGravity[skilllevel_levi];
War3_SetBuff(client,fLowGravitySkill,thisRaceID,gravity);
new skilllevel_vampire=War3_GetSkillLevel(client,thisRaceID,SKILL_LEECH);
new Float:percent=VampirePercent[skilllevel_vampire];
War3_SetBuff(client,fVampirePercent,thisRaceID,percent);
}
}
public OnRaceChanged(client,oldrace,newrace)
{
if(newrace!=thisRaceID)
{
War3_SetBuff(client, fMaxSpeed, thisRaceID, 1.0);
War3_SetBuff(client, fLowGravitySkill, thisRaceID, 1.0);
War3_SetBuff(client, fVampirePercent, thisRaceID, 0.0);
}
else
{
if(IsPlayerAlive(client)){
InitPassiveSkills(client);
}
}
}
public OnWar3EventDeath(victim, attacker)
{
new race=W3GetVar(DeathRace);
new skill=War3_GetSkillLevel(victim,thisRaceID,SKILL_SUICIDE);
if(race==thisRaceID && skill>0 && !Hexed(victim))
{
decl Float:location[3];
GetClientAbsOrigin(victim,location);
if(War3_GetGame()==Game_TF)
{
War3_SuicideBomber(victim, location, SuicideBomberDamageTF[skill], SKILL_SUICIDE, SuicideBomberRadius[skill]);
} else {
War3_SuicideBomber(victim, location, SuicideBomberDamage[skill], SKILL_SUICIDE, SuicideBomberRadius[skill]);
}
}
}
public OnWar3EventSpawn(client)
{
new race=War3_GetRace(client);
if(race==thisRaceID)
{
InitPassiveSkills(client); //sets suicide
}
}
Configuration generated by this:
Code:
"Races"
{
"undead"
{
// Standard set of values applied to any race
"minlevel" "0"
"accessflag" "0"
"raceorder" "2200"
"flags" ""
"restrict_items" ""
"team1_limit" "99"
"team2_limit" "99"
"restrictclass" ""
"category" "default"
// Added by the race
"SuicideBomberRadius" "0.0 250.0 290.0 310.0 330.0"
"SuicideBomberDamage" "0.0 166.0 200.0 233.0 266.0"
"SuicideBomberDamageTF" "0.0 133.0 175.0 250.0 300.0"
"UnholySpeed" "1.0 1.05 1.10 1.15 1.20"
"LevitationGravity" "1.0 0.85 0.7 0.6 0.5"
"VampirePercent" "0.0 0.08 0.14 0.20 0.25"
}
}
I believe that during a config reload I will call the OnConfigReloaded function ONLY on plugins that are actually affected, to prevent an absurd amount of array copying.
Note: I will be writing the array parsing from scratch anyway, so the format is maleable at this point, I merely copied the current system used for colors/vectors, but I can switch the arrays to comma separated lists or anything.




Logged








DarkEnergy