Skip to content

Commit e760917

Browse files
committedJun 13, 2017
Droid ranks are now a brain property and can be upgraded.
Droid ranks (levels) are now defined in the brain stats file, and can be different for each defined brain type. The required experience for increasing in rank, and the number of droids that a commander can control (base and multiplied by level both), are stored as upgrades, and can be modified from scripts. This can be used to implement for example research upgrades touching these stats. It is also possible to name ranks differently for each brain type. Adds new cheat 'bettertogether' that boosts the experience of selected droids. Adds new tech 'Command Turret Upgrade' that increases command limit of commanders by 20%, increases extra command limit per rank level by 50%, and reduces experience required per level for commanders by 10%. This should not imbalance commanders since they are still useless.
·
4.5.53.3.0-beta1
1 parent 4a64d9d commit e760917

File tree

11 files changed

+232
-49
lines changed

11 files changed

+232
-49
lines changed
 

‎data/base/stats/brain.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
"maxDroids": 6,
66
"maxDroidsMult": 2,
77
"name": "Command Turret",
8+
"ranks": [ "Rookie", "Green", "Trained", "Regular", "Professional", "Veteran", "Elite", "Special", "Hero" ],
9+
"thresholds": [ 0, 8, 16, 32, 64, 128, 256, 512, 1024 ],
810
"turret": "CommandTurret1"
911
},
1012
"ZNULLBRAIN": {
1113
"id": "ZNULLBRAIN",
1214
"name": "Z NULL BRAIN",
15+
"ranks": [ "Rookie", "Green", "Trained", "Regular", "Professional", "Veteran", "Elite", "Special", "Hero" ],
16+
"thresholds": [ 0, 4, 8, 16, 32, 64, 128, 256, 512 ],
1317
"turret": "ZNULLWEAPON"
1418
}
1519
}

‎data/mp/multiplay/skirmish/rules.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ function eventResearched(research, structure, player)
339339
for (var i = 0; i < research.results.length; i++)
340340
{
341341
var v = research.results[i];
342-
//debug(" RESULT : class=" + v['class'] + " parameter=" + v['parameter'] + " value=" + v['value'] + " filter=" + v['filterParameter'] + " filterparam=" + v['filterParameter']);
342+
//debug(" RESULT : class=" + v['class'] + " parameter=" + v['parameter'] + " value=" + v['value'] + " filter=" + v['filterParameter'] + " filterval=" + v['filterValue']);
343343
for (var cname in Upgrades[player][v['class']]) // iterate over all components of this type
344344
{
345345
var parameter = v['parameter'];
@@ -349,7 +349,17 @@ function eventResearched(research, structure, player)
349349
{
350350
continue;
351351
}
352-
if (Stats[ctype][cname][parameter] > 0) // only applies if stat has above zero value already
352+
if (Stats[ctype][cname][parameter] instanceof Array)
353+
{
354+
var dst = Upgrades[player][ctype][cname][parameter].slice()
355+
for (var x = 0; x < dst.length; x++)
356+
{
357+
dst[x] += Math.ceil(Stats[ctype][cname][parameter][x] * v['value'] / 100);
358+
}
359+
Upgrades[player][ctype][cname][parameter] = dst
360+
//debug(" upgraded to " + dst);
361+
}
362+
else if (Stats[ctype][cname][parameter] > 0) // only applies if stat has above zero value already
353363
{
354364
Upgrades[player][ctype][cname][parameter] += Math.ceil(Stats[ctype][cname][parameter] * v['value'] / 100);
355365
//debug(" upgraded " + cname + " to " + Upgrades[player][ctype][cname][parameter] + " by " + Math.ceil(Stats[ctype][cname][parameter] * v['value'] / 100));
@@ -365,6 +375,21 @@ function eventCheatMode(entered)
365375

366376
function eventChat(from, to, message)
367377
{
378+
if (message == "bettertogether" && cheatmode)
379+
{
380+
for (var i in Upgrades[from].Brain)
381+
{
382+
if (Upgrades[from].Brain[i].BaseCommandLimit > 0) // is commander
383+
{
384+
Upgrades[from].Brain[i].BaseCommandLimit += 4;
385+
Upgrades[from].Brain[i].CommandLimitByLevel += 2;
386+
// you must set the thresholds this way, as an array, because of the clunky
387+
// way that this is implemented behind the scenes
388+
Upgrades[from].Brain[i].RankThresholds = [ 0, 2, 4, 8, 16, 24, 32, 48, 64 ];
389+
}
390+
}
391+
console("Made player " + from + "'s commanders SUPERIOR!");
392+
}
368393
if (message == "makesuperior" && cheatmode)
369394
{
370395
for (var i in Upgrades[from].Body)

‎data/mp/stats/research.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,38 @@
1515
],
1616
"statID": "CommandBrain01"
1717
},
18+
"R-Comp-CommandTurret02": {
19+
"iconID": "IMAGE_RES_COMPUTERTECH",
20+
"id": "R-Comp-CommandTurret02",
21+
"msgName": "RES_C_CT2",
22+
"name": "Command Turret Upgrade",
23+
"requiredResearch": [
24+
"R-Comp-CommandTurret01",
25+
"R-Struc-Research-Upgrade07"
26+
],
27+
"researchPoints": 5000,
28+
"researchPower": 450,
29+
"results": [
30+
{
31+
"class": "Brain",
32+
"parameter": "BaseCommandLimit",
33+
"value": 20
34+
},
35+
{
36+
"class": "Brain",
37+
"parameter": "CommandLimitByLevel",
38+
"value": 50
39+
},
40+
{
41+
"class": "Brain",
42+
"filterParameter": "Id",
43+
"filterValue": "CommandBrain01",
44+
"parameter": "RankThresholds",
45+
"value": -10
46+
}
47+
],
48+
"statID": "CommandBrain01"
49+
},
1850
"R-Comp-SynapticLink": {
1951
"iconID": "IMAGE_RES_COMPUTERTECH",
2052
"id": "R-Comp-SynapticLink",

‎po/custom/fromJson.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,15 @@ _("NEXUS Resistance Circuits Mk2")
995995
_("NEXUS Resistance Circuits Mk3")
996996
_("NEXUS Wall")
997997
_("No Place To Hide")
998+
NP_("rank", "Elite")
999+
NP_("rank", "Green")
1000+
NP_("rank", "Hero")
1001+
NP_("rank", "Professional")
1002+
NP_("rank", "Regular")
1003+
NP_("rank", "Rookie")
1004+
NP_("rank", "Special")
1005+
NP_("rank", "Trained")
1006+
NP_("rank", "Veteran")
9981007
_("NullBot")
9991008
_("Oil Derrick")
10001009
_("Oil Drum")

‎po/parseJson.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@
22

33
def printString(s, begin, end):
44
if not re.match(r'^(\*.*\*|CAM[0-9] .*|Z ?NULL.*)$', s):
5-
sys.stdout.write('{}_({}){}'.format(begin, json.dumps(s, ensure_ascii=False), end))
5+
sys.stdout.write('{}{}){}'.format(begin, json.dumps(s, ensure_ascii=False), end))
66

77
def parse(obj):
88
if isinstance(obj, dict):
99
for k, v in obj.items():
1010
parse(v)
1111
if k == 'name' and isinstance(v, str):
12-
printString(v, '', '\n')
13-
elif k == 'text' and isinstance(v, list):
12+
printString(v, '_(', '\n')
13+
elif k in ['text', 'ranks'] and isinstance(v, list):
1414
for s in v:
1515
if isinstance(s, str):
16-
printString(s, '', '\n')
16+
if k == 'text':
17+
printString(s, '_(', '\n')
18+
elif k == 'ranks':
19+
printString(s, 'NP_("rank", ', '\n')
1720
elif isinstance(obj, list):
1821
for v in obj:
1922
parse(v)

‎src/cmddroid.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ SDWORD cmdDroidGetIndex(DROID *psCommander)
153153
/** This function returns the maximum group size of the command droid.*/
154154
unsigned int cmdDroidMaxGroup(const DROID *psCommander)
155155
{
156-
return getDroidLevel(psCommander) * getBrainStats(const_cast<DROID *>(psCommander))->maxDroidsMult
157-
+ getBrainStats(const_cast<DROID *>(psCommander))->maxDroids;
156+
const BRAIN_STATS *psStats = getBrainStats(psCommander);
157+
return getDroidLevel(psCommander) * psStats->upgrade[psCommander->player].maxDroidsMult + psStats->upgrade[psCommander->player].maxDroids;
158158
}
159159

160160
/** This function adds experience to the command droid of the psKiller's command group.*/

‎src/droid.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,41 +2130,26 @@ struct rankMap
21302130
const char *name; // name of this rank
21312131
};
21322132

2133-
static const struct rankMap arrRank[] =
2134-
{
2135-
{0, 0, N_("Rookie")},
2136-
{4, 8, NP_("rank", "Green")},
2137-
{8, 16, N_("Trained")},
2138-
{16, 32, N_("Regular")},
2139-
{32, 64, N_("Professional")},
2140-
{64, 128, N_("Veteran")},
2141-
{128, 256, N_("Elite")},
2142-
{256, 512, N_("Special")},
2143-
{512, 1024, N_("Hero")}
2144-
};
2145-
21462133
unsigned int getDroidLevel(const DROID *psDroid)
21472134
{
2148-
bool isCommander = (psDroid->droidType == DROID_COMMAND ||
2149-
psDroid->droidType == DROID_SENSOR) ? true : false;
21502135
unsigned int numKills = psDroid->experience / 65536;
21512136
unsigned int i;
21522137

21532138
// Search through the array of ranks until one is found
21542139
// which requires more kills than the droid has.
21552140
// Then fall back to the previous rank.
2156-
for (i = 1; i < ARRAY_SIZE(arrRank); ++i)
2141+
const BRAIN_STATS *psStats = getBrainStats(psDroid);
2142+
auto &vec = psStats->upgrade[psDroid->player].rankThresholds;
2143+
for (i = 1; i < vec.size(); ++i)
21572144
{
2158-
const unsigned int requiredKills = isCommander ? arrRank[i].commanderKills : arrRank[i].kills;
2159-
2160-
if (numKills < requiredKills)
2145+
if (numKills < vec.at(i))
21612146
{
21622147
return i - 1;
21632148
}
21642149
}
21652150

21662151
// If the criteria of the last rank are met, then select the last one
2167-
return ARRAY_SIZE(arrRank) - 1;
2152+
return vec.size() - 1;
21682153
}
21692154

21702155
UDWORD getDroidEffectiveLevel(DROID *psDroid)
@@ -2184,18 +2169,10 @@ UDWORD getDroidEffectiveLevel(DROID *psDroid)
21842169
return MAX(level, cmdLevel);
21852170
}
21862171

2187-
2188-
const char *getDroidNameForRank(UDWORD rank)
2189-
{
2190-
ASSERT_OR_RETURN(PE_("rank", "invalid"), rank < (sizeof(arrRank) / sizeof(struct rankMap)),
2191-
"given rank number (%d) out of bounds, we only have %lu ranks", rank, (unsigned long)(sizeof(arrRank) / sizeof(struct rankMap)));
2192-
2193-
return PE_("rank", arrRank[rank].name);
2194-
}
2195-
21962172
const char *getDroidLevelName(DROID *psDroid)
21972173
{
2198-
return (getDroidNameForRank(getDroidLevel(psDroid)));
2174+
const BRAIN_STATS *psStats = getBrainStats(psDroid);
2175+
return PE_("rank", psStats->rankNames[getDroidLevel(psDroid)].c_str());
21992176
}
22002177

22012178
UDWORD getNumDroidsForLevel(UDWORD level)

‎src/qtscriptdebug.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,30 +410,42 @@ QStandardItemList componentToString(const QString &name, const COMPONENT_STATS *
410410
else if (psStats->compType == COMP_BRAIN)
411411
{
412412
const BRAIN_STATS *psBrain = (const BRAIN_STATS *)psStats;
413-
key->appendRow(QStandardItemList{ new QStandardItem("^Max droids"), new QStandardItem(QString::number(psBrain->maxDroids)) });
414-
key->appendRow(QStandardItemList{ new QStandardItem("^Extra droids/level"), new QStandardItem(QString::number(psBrain->maxDroidsMult)) });
413+
QStringList ranks;
414+
for (const std::string &s : psBrain->rankNames)
415+
{
416+
ranks.append(QString::fromStdString(s));
417+
}
418+
QStringList thresholds;
419+
for (int t : psBrain->upgrade[player].rankThresholds)
420+
{
421+
thresholds.append(QString::number(t));
422+
}
423+
key->appendRow(QStandardItemList{ new QStandardItem("^Base command limit"), new QStandardItem(QString::number(psBrain->upgrade[player].maxDroids)) });
424+
key->appendRow(QStandardItemList{ new QStandardItem("^Extra command limit by level"), new QStandardItem(QString::number(psBrain->upgrade[player].maxDroidsMult)) });
425+
key->appendRow(QStandardItemList{ new QStandardItem("^Rank names"), new QStandardItem(ranks.join(", ")) });
426+
key->appendRow(QStandardItemList{ new QStandardItem("^Rank thresholds"), new QStandardItem(thresholds.join(", ")) });
415427
}
416428
else if (psStats->compType == COMP_REPAIRUNIT)
417429
{
418430
const REPAIR_STATS *psRepair = (const REPAIR_STATS *)psStats;
419431
key->appendRow(QStandardItemList{ new QStandardItem("^Repair time"), new QStandardItem(QString::number(psRepair->time)) });
420-
key->appendRow(QStandardItemList{ new QStandardItem("^Base repair points"), new QStandardItem(QString::number(psRepair->base.repairPoints)) });
432+
key->appendRow(QStandardItemList{ new QStandardItem("^Base repair points"), new QStandardItem(QString::number(psRepair->upgrade[player].repairPoints)) });
421433
}
422434
else if (psStats->compType == COMP_ECM)
423435
{
424436
const ECM_STATS *psECM = (const ECM_STATS *)psStats;
425-
key->appendRow(QStandardItemList{ new QStandardItem("^Base range"), new QStandardItem(QString::number(psECM->base.range)) });
437+
key->appendRow(QStandardItemList{ new QStandardItem("^Base range"), new QStandardItem(QString::number(psECM->upgrade[player].range)) });
426438
}
427439
else if (psStats->compType == COMP_SENSOR)
428440
{
429441
const SENSOR_STATS *psSensor = (const SENSOR_STATS *)psStats;
430442
key->appendRow(QStandardItemList{ new QStandardItem("^Sensor type"), new QStandardItem(QString::number(psSensor->type)) });
431-
key->appendRow(QStandardItemList{ new QStandardItem("^Base range"), new QStandardItem(QString::number(psSensor->base.range)) });
443+
key->appendRow(QStandardItemList{ new QStandardItem("^Base range"), new QStandardItem(QString::number(psSensor->upgrade[player].range)) });
432444
}
433445
else if (psStats->compType == COMP_CONSTRUCT)
434446
{
435447
const CONSTRUCT_STATS *psCon = (const CONSTRUCT_STATS *)psStats;
436-
key->appendRow(QStandardItemList{ new QStandardItem("^Base construct points"), new QStandardItem(QString::number(psCon->base.constructPoints)) });
448+
key->appendRow(QStandardItemList{ new QStandardItem("^Base construct points"), new QStandardItem(QString::number(psCon->upgrade[player].constructPoints)) });
437449
}
438450
return QStandardItemList { key, value };
439451
}

0 commit comments

Comments
 (0)
Please sign in to comment.