Convert functions.txt to handle upgrades from within javascript and research.ini.

hackChangeMe() can no longer take -1, instead add new receiveAllEvents(bool) function
for that purpose. Campaign upgrades are not yet converted. All 'Power' settings in
ini files are changed, since they used meaningless values, to 'PowerLevel' with 0..2
values that correspond to button settings.
master
per 2013-05-05 13:34:59 +02:00
parent 9fbf38f82b
commit 545832358b
62 changed files with 1645 additions and 3638 deletions

View File

@ -16,7 +16,7 @@
;resultComponents = <comma-separated list>
;redStructures = <comma-separated list>
;requiredStructures = <comma-separated list>
;resultFunctions = <comma-separated list>
;results = <comma-separated list of hints to rules.js>
;replacedComponents = <comma-separated list of items <oldComponentID:newComponentID>>
[R-Vehicle-Prop-Tracks]

View File

@ -16,7 +16,7 @@
;resultComponents = <comma-separated list>
;redStructures = <comma-separated list>
;requiredStructures = <comma-separated list>
;resultFunctions = <comma-separated list>
;results = <comma-separated list of hints to rules.js>
;replacedComponents = <comma-separated list of items <oldComponentID:newComponentID>>
[R-Wpn-Rocket01-LtAT]

View File

@ -16,7 +16,7 @@
;resultComponents = <comma-separated list>
;redStructures = <comma-separated list>
;requiredStructures = <comma-separated list>
;resultFunctions = <comma-separated list>
;results = <comma-separated list of hints to rules.js>
;replacedComponents = <comma-separated list of items <oldComponentID:newComponentID>>
[R-Wpn-Rocket01-LtAT]

View File

@ -23,7 +23,7 @@ radiusDamage = 0
radiusLife = 0
flightSpeed = 1
fireOnMove = 0
weaponClass = MISC
weaponClass = KINETIC
weaponSubClass = "MACHINE GUN"
movement = DIRECT
weaponEffect = "ANTI PERSONNEL"

View File

@ -11,7 +11,6 @@ file SWEAPON "weapons.ini"
file SSENSOR "sensor.ini"
file SECM "ecm.ini"
file SREPAIR "repair.ini"
file SFUNC "functions.txt"
file SSTRUCT "structure.ini"
directory "multiplay/script"
file SCRIPT "multilim.slo"

View File

@ -22,7 +22,6 @@ file SWEAPSND "weaponsounds.ini"
file SWEAPMOD "weaponmodifier.ini"
file STEMPL "templates.txt"
file STEMPWEAP "assignweapons.txt"
file SFUNC "functions.txt"
file SSTRUCT "structure.ini"
file SSTRMOD "structuremodifier.ini"
file SFEAT "features.txt"

View File

@ -5,7 +5,7 @@ Map = "Sk-HighGround"
MaxPlayers = 2
Scavengers = true
Bases = 3
Power = 700
PowerLevel = 1
Description = "A level that players should be able to beat before playing online. The AI starts with a good defense."
[player_1]

View File

@ -5,7 +5,7 @@ Map = "Sk-MizaMaze"
MaxPlayers = 8
Scavengers = false
Bases = 2
Power = 700
PowerLevel = 1
Description = "Stay behind your AI allies and beat the enemy in close quarters, man-to-man combat."
version = 2

View File

@ -5,7 +5,7 @@ Map = "Sk-MizaMaze"
MaxPlayers = 8
Scavengers = false
Bases = 2
Power = 700
PowerLevel = 1
AllowPositionChange = true
Description = "You've got seven AI players on your tail. There's nowhere to run, nowhere to hide."

View File

@ -310,6 +310,7 @@ ZNULLECM "Z NULL ECM"
ECM1PylonMk1 _("Jammer Tower")
ECM1TurretMk1 _("Jammer Turret")
R-Sys-ECM-Upgrade01 _("Electronic Countermeasures")
R-Sys-ECM-Upgrade02 _("Electronic Countermeasures Mk2")
/* SENSORS */
ZNULLSENSOR "Z NULL SENSOR"

View File

@ -7,9 +7,12 @@
// /////////////////////////////////////////////////////////////////
var lastHitTime = 0;
var cheatmode = false;
function eventGameInit()
{
receiveAllEvents(true);
if (tilesetType != "ARIZONA")
{
setSky("texpages/page-25-sky-urban.png", 0.5, 10000.0);
@ -18,14 +21,23 @@ function eventGameInit()
hackNetOff();
for (var playnum = 0; playnum < maxPlayers; playnum++)
{
if (powerType == 0)
{
setPowerModifier(85, playnum);
}
else if (powerType == 2)
{
setPowerModifier(125, playnum);
}
// insane difficulty is meant to be insane...
if (playerData[playnum].difficulty == INSANE)
{
setPowerModifier(200, playnum);
setPowerModifier(200 + 15 * game.power, playnum);
}
else if (playerData[playnum].difficulty == EASY)
{
setPowerModifier(75, playnum);
setPowerModifier(70 + 5 * game.power, playnum);
}
setDroidLimit(playnum, 150, DROID_ANY);
@ -287,3 +299,93 @@ function eventDestroyed(victim)
setDesign(false); // and disallow design
}
}
function eventResearched(research, structure, player)
{
//debug("RESEARCH : " + research.fullname + "(" + research.name + ") for " + player + " results=" + research.results);
for (var v = 0; v < research.results.length; v++)
{
var s = research.results[v].split(":");
if (['Droids', 'Cyborgs'].indexOf(s[0]) >= 0) // research result applies to droids and cyborgs
{
for (var i in Upgrades[player].Body) // loop over all bodies
{
if (Stats.Body[i].BodyClass === s[0]) // if match against hint in ini file, change it
{
// eg Upgrades[0].Body['Tiger']['Armour']
Upgrades[player].Body[i][s[1]] += Math.ceil(Stats.Body[i][s[1]] * s[2] / 100);
//debug(" upgraded " + i + " to " + Upgrades[player].Body[i][s[1]] + " by " + Math.ceil(Stats.Body[i][s[1]] * s[2] / 100));
}
}
}
else if (['ResearchPoints', 'ProductionPoints', 'PowerPoints', 'RepairPoints', 'RearmPoints'].indexOf(s[0]) >= 0)
{
for (var i in Upgrades[player].Building)
{
if (Stats.Building[i][s[0]] > 0) // only applies if building has this stat already
{
Upgrades[player].Building[i][s[0]] += Math.ceil(Stats.Building[i][s[0]] * s[1] / 100);
//debug(" upgraded " + i + " to " + Upgrades[player].Building[i][s[0]] + " by " + Math.ceil(Stats.Building[i][s[0]] * s[1] / 100));
}
}
}
else if (['Wall', 'Structure'].indexOf(s[0]) >= 0)
{
for (var i in Upgrades[player].Building)
{
if (Stats.Building[i].Type === s[0]) // applies to specific building type
{
Upgrades[player].Building[i][s[1]] += Math.ceil(Stats.Building[i][s[1]] * s[2] / 100);
//debug(" upgraded " + i + " to " + Upgrades[player].Building[i][s[1]] + " by " + Math.ceil(Stats.Building[i][s[1]] * s[2] / 100));
}
}
}
else if (['ECM', 'Sensor', 'Repair', 'Construct'].indexOf(s[0]) >= 0)
{
for (var i in Upgrades[player][s[0]])
{
// Upgrades.player.type.buildingName.parameter ... hard to read but short and flexible
Upgrades[player][s[0]][i][s[1]] += Math.ceil(Stats[s[0]][i][s[1]] * s[2] / 100);
//debug(" upgraded " + i + " to " + Upgrades[player][s[0]][i][s[1]] + " by " + Math.ceil(Stats[s[0]][i][s[1]] * s[2] / 100));
}
}
else if (Stats.WeaponClass.indexOf(s[0]) >= 0) // if first field is a weapon class
{
for (var i in Upgrades[player].Weapon)
{
if (Stats.Weapon[i][s[1]] > 0 && Stats.Weapon[i].ImpactClass === s[0])
{
Upgrades[player].Weapon[i][s[1]] += Math.ceil(Stats.Weapon[i][s[1]] * s[2] / 100);
//debug(" upgraded " + i + " to " + Upgrades[player].Weapon[i][s[1]] + " by " + Math.ceil(Stats.Weapon[i][s[1]] * s[2] / 100));
}
}
}
else
{
debug("(error) Unrecognized research hint=" + s[0]);
}
}
}
function eventCheatMode(entered)
{
cheatmode = entered; // remember this setting
}
function eventChat(from, to, message)
{
if (message == "makesuperior" && cheatmode)
{
for (var i in Upgrades[from].Body)
{
if (Upgrades[from].Body[i].bodyClass === 'Droids' || Upgrades[from].Body[i].bodyClass === 'Cyborgs')
{
Upgrades[from].Body[i].HitPoints += 500;
Upgrades[from].Body[i].Armour += 500;
Upgrades[from].Body[i].Thermal += 500;
Upgrades[from].Body[i].Power += 500;
}
}
console("Made player " + from + "'s units SUPERIOR!");
}
}

View File

@ -14,6 +14,7 @@ designable = 0
[TransporterBody]
name = "Transport Body"
class = "Transports"
size = MEDIUM
buildPower = 325
buildPoints = 637
@ -29,6 +30,7 @@ droidType = TRANSPORTER
[SuperTransportBody]
name = "Super Transport Body"
class = "Transports"
size = HEAVY
buildPower = 500
buildPoints = 625
@ -58,6 +60,7 @@ designable = 0
[FireBody]
name = "*Fire Engine Body*"
class = "Babas"
size = LIGHT
buildPower = 4
buildPoints = 75
@ -72,6 +75,7 @@ designable = 0
[CybRotMgGrd]
name = "Cyborg Assault Gun"
class = "Cyborgs"
size = LIGHT
buildPower = 21
buildPoints = 75
@ -87,6 +91,7 @@ droidType = CYBORG
[CyborgRkt1Ground]
name = "Cyborg Rocket"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -102,6 +107,7 @@ droidType = CYBORG
[CyborgFlamerGrd]
name = "Cyborg Flamer"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -117,6 +123,7 @@ droidType = CYBORG
[CyborgChain1Ground]
name = "Cyborg Chaingun"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -132,6 +139,7 @@ droidType = CYBORG
[CyborgCannonGrd]
name = "Cyborg Cannon"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -147,6 +155,7 @@ droidType = CYBORG
[Cyb-Hvybod-TK]
name = "Super Tank-Killer Cyborg"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -162,6 +171,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-RailGunner]
name = "Super Rail-Gunner"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -177,6 +187,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-PulseLsr]
name = "Super Pulse Laser Cyborg"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -192,6 +203,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-Mcannon]
name = "Super Heavy-Gunner"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -207,6 +219,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-HPV]
name = "Super HPV Cyborg"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -222,6 +235,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-Acannon]
name = "Super Auto-Cannon Cyborg"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -237,6 +251,7 @@ droidType = CYBORG_SUPER
[Cyb-Hvybod-A-T]
name = "Super Scourge Cyborg"
class = "Cyborgs"
size = LIGHT
buildPower = 50
buildPoints = 205
@ -252,6 +267,7 @@ droidType = CYBORG_SUPER
[Cyb-Bod-Thermite]
name = "Cyborg Thermite"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -267,6 +283,7 @@ droidType = CYBORG
[Cyb-Bod-Rail1]
name = "Cyborg Railgun"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -282,6 +299,7 @@ droidType = CYBORG
[Cyb-Bod-Mechanic]
name = "Cyborg Mechanic"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -297,6 +315,7 @@ droidType = CYBORG_REPAIR
[Cyb-Bod-Las1]
name = "Cyborg Laser"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -312,6 +331,7 @@ droidType = CYBORG
[Cyb-Bod-Grenade]
name = "Cyborg Grenadier"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -327,6 +347,7 @@ droidType = CYBORG
[Cyb-Bod-ComEng]
name = "Combat Engineer"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -342,6 +363,7 @@ droidType = CYBORG_CONSTRUCT
[Cyb-Bod-Atmiss]
name = "Cyborg Anti-Tank"
class = "Cyborgs"
size = LIGHT
buildPower = 25
buildPoints = 95
@ -357,6 +379,7 @@ droidType = CYBORG
[BusBody]
name = "*School Bus Body*"
class = "Babas"
size = LIGHT
buildPower = 4
buildPoints = 75
@ -371,6 +394,7 @@ designable = 0
[Body9REC]
name = "Tiger"
class = "Droids"
size = HEAVY
buildPower = 71
buildPoints = 420
@ -386,6 +410,7 @@ designable = 1
[Body8MBT]
name = "Scorpion"
class = "Droids"
size = MEDIUM
buildPower = 39
buildPoints = 250
@ -401,6 +426,7 @@ designable = 1
[Body7ABT]
name = "Retribution"
class = "Droids"
size = MEDIUM
buildPower = 100
buildPoints = 600
@ -416,6 +442,7 @@ designable = 1
[Body6SUPP]
name = "Panther"
class = "Droids"
size = MEDIUM
buildPower = 57
buildPoints = 300
@ -431,6 +458,7 @@ designable = 1
[Body5REC]
name = "Cobra"
class = "Droids"
size = MEDIUM
buildPower = 46
buildPoints = 250
@ -446,6 +474,7 @@ designable = 1
[Body4ABT]
name = "Bug"
class = "Droids"
size = LIGHT
buildPower = 25
buildPoints = 100
@ -461,6 +490,7 @@ designable = 1
[Body3MBT]
name = "Retaliation"
class = "Droids"
size = LIGHT
buildPower = 68
buildPoints = 400
@ -476,6 +506,7 @@ designable = 1
[Body2SUP]
name = "Leopard"
class = "Droids"
size = LIGHT
buildPower = 41
buildPoints = 220
@ -491,6 +522,7 @@ designable = 1
[Body1REC]
name = "Viper"
class = "Droids"
size = LIGHT
buildPower = 30
buildPoints = 150
@ -506,6 +538,7 @@ designable = 1
[Body14SUP]
name = "Dragon"
class = "Droids"
size = HEAVY
buildPower = 182
buildPoints = 1000
@ -521,6 +554,7 @@ designable = 1
[Body13SUP]
name = "Wyvern"
class = "Droids"
size = HEAVY
buildPower = 156
buildPoints = 900
@ -536,6 +570,7 @@ designable = 1
[Body12SUP]
name = "Mantis"
class = "Droids"
size = HEAVY
buildPower = 52
buildPoints = 350
@ -566,6 +601,7 @@ designable = 1
[Body10MBT]
name = "Vengeance"
class = "Droids"
size = HEAVY
buildPower = 130
buildPoints = 800
@ -581,6 +617,7 @@ designable = 1
[B4body-sml-trike01]
name = "*Trike Body*"
class = "Babas"
size = LIGHT
buildPower = 2
buildPoints = 65
@ -595,6 +632,7 @@ designable = 0
[B3bodyRKbuggy01]
name = "*Rocket Buggy Body*"
class = "Babas"
size = LIGHT
buildPower = 3
buildPoints = 80
@ -609,6 +647,7 @@ designable = 0
[B3body-sml-buggy01]
name = "*Buggy Body*"
class = "Babas"
size = LIGHT
buildPower = 3
buildPoints = 80
@ -623,6 +662,7 @@ designable = 0
[B2RKJeepBody]
name = "*Rocket Jeep Body*"
class = "Babas"
size = LIGHT
buildPower = 4
buildPoints = 75
@ -637,6 +677,7 @@ designable = 0
[B2JeepBody]
name = "*Jeep Body*"
class = "Babas"
size = LIGHT
buildPower = 4
buildPoints = 75
@ -651,6 +692,7 @@ designable = 0
[B1BaBaPerson01]
name = "*BaBa Body*"
class = "Babas"
size = LIGHT
buildPower = 1
buildPoints = 20

View File

@ -1,298 +0,0 @@
Production,FacProd1,LIGHT,10
Production,FacMod1,LIGHT,10
Production,BaBaFacProd,LIGHT,10
Research Upgrade,Struc-Research-Upgrade01,30
Research Upgrade,Struc-Research-Upgrade02,60
Research Upgrade,Struc-Research-Upgrade03,90
Research Upgrade,Struc-Research-Upgrade04,120
Research Upgrade,Struc-Research-Upgrade05,150
Research Upgrade,Struc-Research-Upgrade06,180
Research Upgrade,Struc-Research-Upgrade07,210
Research Upgrade,Struc-Research-Upgrade08,240
Research Upgrade,Struc-Research-Upgrade09,270
Repair Droid,RepairFacilityFunc,40
Power Generator,PowGen1,0,55,0,0,0,0
Power Generator,BaBaPowGen,400,50,0,0,0,0
Power Generator,PowerModule,0,28,0,0,0,0
Resource,Resource,12500
Production Upgrade,Struc-Factory-Upgrade01,1,0,0,30
Production Upgrade,Struc-Factory-Upgrade02,1,0,0,60
Production Upgrade,Struc-Factory-Upgrade03,1,0,0,90
Production Upgrade,Struc-Factory-Upgrade04,1,0,0,120
Production Upgrade,Struc-Factory-Upgrade05,1,0,0,150
Production Upgrade,Struc-Factory-Upgrade06,1,0,0,180
Production Upgrade,Struc-Factory-Cyborg-Upgrade01,0,1,0,30
Production Upgrade,Struc-Factory-Cyborg-Upgrade02,0,1,0,60
Production Upgrade,Struc-Factory-Cyborg-Upgrade03,0,1,0,90
Production Upgrade,Struc-Factory-Cyborg-Upgrade04,0,1,0,120
Production Upgrade,Struc-Factory-Cyborg-Upgrade05,0,1,0,150
Production Upgrade,Struc-Factory-Cyborg-Upgrade06,0,1,0,180
Production Upgrade,Struc-VTOLFactory-Upgrade01,0,0,1,30
Production Upgrade,Struc-VTOLFactory-Upgrade02,0,0,1,60
Production Upgrade,Struc-VTOLFactory-Upgrade03,0,0,1,90
Production Upgrade,Struc-VTOLFactory-Upgrade04,0,0,1,120
Production Upgrade,Struc-VTOLFactory-Upgrade05,0,0,1,180
Production Upgrade,Struc-VTOLFactory-Upgrade06,0,0,1,240
Production Upgrade,Struc-Factory-Upgrade07,1,0,0,210
Production Upgrade,Struc-Factory-Upgrade08,1,0,0,240
Production Upgrade,Struc-Factory-Upgrade09,1,0,0,270
Production Upgrade,Struc-Factory-Cyborg-Upgrade07,0,1,0,210
Production Upgrade,Struc-Factory-Cyborg-Upgrade08,0,1,0,240
Production Upgrade,Struc-Factory-Cyborg-Upgrade09,0,1,0,270
Production Upgrade,Struc-VTOLFactory-Upgrade07,0,0,1,210
Production Upgrade,Struc-VTOLFactory-Upgrade08,0,0,1,240
Production Upgrade,Struc-VTOLFactory-Upgrade09,0,0,1,270
Weapon Upgrade,Wpn-Cannon-Accuracy01,CANNON,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Cannon-Damage01,CANNON,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-Cannon-Damage02,CANNON,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-Cannon-Damage03,CANNON,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-Cannon-ROF01,CANNON,10,0,0,0,0,0,0
Weapon Upgrade,Wpn-Cannon-ROF02,CANNON,20,0,0,0,0,0,0
Weapon Upgrade,Wpn-Cannon-ROF03,CANNON,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Flamer-Damage01,FLAME,0,0,0,25,0,25,0
Weapon Upgrade,Wpn-Flamer-Damage02,FLAME,0,0,0,50,0,50,0
Weapon Upgrade,Wpn-Flamer-Damage03,FLAME,0,0,0,75,0,75,0
Weapon Upgrade,Wpn-Flamer-ROF01,FLAME,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Flamer-ROF02,FLAME,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Flamer-ROF03,FLAME,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-MG-Damage01,MACHINE GUN,0,0,0,25,0,0,0
Weapon Upgrade,Wpn-MG-Damage02,MACHINE GUN,0,0,0,50,0,0,0
Weapon Upgrade,Wpn-MG-Damage03,MACHINE GUN,0,0,0,75,0,0,0
Weapon Upgrade,Wpn-MG-ROF01,MACHINE GUN,17,0,0,0,0,0,0
Weapon Upgrade,Wpn-MG-ROF02,MACHINE GUN,34,0,0,0,0,0,0
Weapon Upgrade,Wpn-MG-ROF03,MACHINE GUN,50,0,0,0,0,0,0
Weapon Upgrade,Wpn-Artillery-Damage01,MORTARS,0,0,0,25,25,25,0
Weapon Upgrade,Wpn-Artillery-Damage02,MORTARS,0,0,0,50,50,50,0
Weapon Upgrade,Wpn-Artillery-Damage03,MORTARS,0,0,0,75,75,75,0
Weapon Upgrade,Wpn-Artillery-ROF01,MORTARS,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Artillery-ROF02,MORTARS,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Artillery-ROF03,MORTARS,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Damage01,ROCKET,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-Rocket-Damage02,ROCKET,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-Rocket-Damage03,ROCKET,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-Rocket-ROF01,ROCKET,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rocket-ROF02,ROCKET,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rocket-ROF03,ROCKET,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-MG-Damage04,MACHINE GUN,0,0,0,100,0,0,0
Weapon Upgrade,Wpn-MG-Damage05,MACHINE GUN,0,0,0,125,0,0,0
Weapon Upgrade,Wpn-MG-Damage06,MACHINE GUN,0,0,0,150,0,0,0
Weapon Upgrade,Wpn-Cannon-Damage04,CANNON,0,0,0,100,100,0,0
Weapon Upgrade,Wpn-Cannon-Damage05,CANNON,0,0,0,125,125,0,0
Weapon Upgrade,Wpn-Cannon-Damage06,CANNON,0,0,0,150,150,0,0
Weapon Upgrade,Wpn-Cannon-Damage07,CANNON,0,0,0,175,175,0,0
Weapon Upgrade,Wpn-Cannon-Damage08,CANNON,0,0,0,200,200,0,0
Weapon Upgrade,Wpn-Cannon-Damage09,CANNON,0,0,0,225,225,0,0
Weapon Upgrade,Wpn-Cannon-ROF04,CANNON,40,0,0,0,0,0,0
Weapon Upgrade,Wpn-Cannon-ROF05,CANNON,50,0,0,0,0,0,0
Weapon Upgrade,Wpn-Cannon-ROF06,CANNON,60,0,0,0,0,0,0
Weapon Upgrade,Wpn-Cannon-Accuracy02,CANNON,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Cannon-Accuracy03,CANNON,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-AAGun-Accuracy01,A-A GUN,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-AAGun-Accuracy02,A-A GUN,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-AAGun-Accuracy03,A-A GUN,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-AAGun-Damage01,A-A GUN,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-AAGun-Damage02,A-A GUN,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-AAGun-Damage03,A-A GUN,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-AAGun-Damage04,A-A GUN,0,0,0,100,100,0,0
Weapon Upgrade,Wpn-AAGun-Damage05,A-A GUN,0,0,0,125,125,0,0
Weapon Upgrade,Wpn-AAGun-Damage06,A-A GUN,0,0,0,150,150,0,0
Weapon Upgrade,Wpn-AAGun-ROF01,A-A GUN,10,0,0,0,0,0,0
Weapon Upgrade,Wpn-AAGun-ROF02,A-A GUN,20,0,0,0,0,0,0
Weapon Upgrade,Wpn-AAGun-ROF03,A-A GUN,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-AAGun-ROF04,A-A GUN,40,0,0,0,0,0,0
Weapon Upgrade,Wpn-AAGun-ROF05,A-A GUN,50,0,0,0,0,0,0
Weapon Upgrade,Wpn-AAGun-ROF06,A-A GUN,60,0,0,0,0,0,0
Weapon Upgrade,Wpn-Bomb-Accuracy01,BOMB,0,0,0,25,25,25,0
Weapon Upgrade,Wpn-Bomb-Accuracy02,BOMB,0,0,0,50,50,50,0
Weapon Upgrade,Wpn-Bomb-Accuracy03,BOMB,0,0,0,75,75,75,0
Weapon Upgrade,Wpn-Flamer-Damage04,FLAME,0,0,0,100,0,100,0
Weapon Upgrade,Wpn-Flamer-Damage05,FLAME,0,0,0,125,0,125,0
Weapon Upgrade,Wpn-Flamer-Damage06,FLAME,0,0,0,150,0,150,0
Weapon Upgrade,Wpn-Howitzer-Accuracy01,HOWITZERS,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-Accuracy02,HOWITZERS,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-Accuracy03,HOWITZERS,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-Damage01,HOWITZERS,0,0,0,25,25,25,0
Weapon Upgrade,Wpn-Howitzer-Damage02,HOWITZERS,0,0,0,50,50,50,0
Weapon Upgrade,Wpn-Howitzer-Damage03,HOWITZERS,0,0,0,75,75,75,0
Weapon Upgrade,Wpn-Howitzer-Damage04,HOWITZERS,0,0,0,100,100,100,0
Weapon Upgrade,Wpn-Howitzer-Damage05,HOWITZERS,0,0,0,125,125,125,0
Weapon Upgrade,Wpn-Howitzer-Damage06,HOWITZERS,0,0,0,150,150,150,0
Weapon Upgrade,Wpn-Howitzer-ROF01,HOWITZERS,10,0,0,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-ROF02,HOWITZERS,20,0,0,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-ROF03,HOWITZERS,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Howitzer-ROF04,HOWITZERS,50,0,0,0,0,0,0
Weapon Upgrade,Wpn-Energy-Accuracy01,ENERGY,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Energy-Accuracy02,ENERGY,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Energy-Accuracy03,ENERGY,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-Energy-Damage01,ENERGY,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-Energy-Damage02,ENERGY,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-Energy-Damage03,ENERGY,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-Energy-ROF01,ENERGY,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Energy-ROF02,ENERGY,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Energy-ROF03,ENERGY,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-MG-Damage07,MACHINE GUN,0,0,0,175,0,0,0
Weapon Upgrade,Wpn-MG-Damage08,MACHINE GUN,0,0,0,200,0,0,0
Weapon Upgrade,Wpn-MG-Damage09,MACHINE GUN,0,0,0,225,0,0,0
Weapon Upgrade,Wpn-Missile-Accuracy01,MISSILE,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Missile-Accuracy02,MISSILE,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Missile-Damage01,MISSILE,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-Missile-Damage02,MISSILE,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-Missile-Damage03,MISSILE,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-Missile-ROF01,MISSILE,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Missile-ROF02,MISSILE,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Missile-ROF03,MISSILE,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-MissileSlow-Damage01,SLOW MISSILE,0,0,0,25,0,0,0
Weapon Upgrade,Wpn-MissileSlow-Damage02,SLOW MISSILE,0,0,0,50,0,0,0
Weapon Upgrade,Wpn-MissileSlow-Damage03,SLOW MISSILE,0,0,0,75,0,0,0
Weapon Upgrade,Wpn-MissileSlow-ROF01,SLOW MISSILE,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Mortar-Acc01,MORTARS,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Mortar-Acc02,MORTARS,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Mortar-Acc03,MORTARS,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-Mortar-Damage01,MORTARS,0,0,0,25,25,25,0
Weapon Upgrade,Wpn-Mortar-Damage02,MORTARS,0,0,0,50,50,50,0
Weapon Upgrade,Wpn-Mortar-Damage03,MORTARS,0,0,0,75,75,75,0
Weapon Upgrade,Wpn-Mortar-Damage04,MORTARS,0,0,0,100,100,100,0
Weapon Upgrade,Wpn-Mortar-Damage05,MORTARS,0,0,0,125,125,125,0
Weapon Upgrade,Wpn-Mortar-Damage06,MORTARS,0,0,0,150,150,150,0
Weapon Upgrade,Wpn-Mortar-ROF01,MORTARS,10,0,0,0,0,0,0
Weapon Upgrade,Wpn-Mortar-ROF02,MORTARS,20,0,0,0,0,0,0
Weapon Upgrade,Wpn-Mortar-ROF03,MORTARS,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Mortar-ROF04,MORTARS,40,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rail-Accuracy01,GAUSS,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Rail-Damage01,GAUSS,0,0,0,25,25,0,0
Weapon Upgrade,Wpn-Rail-Damage02,GAUSS,0,0,0,50,50,0,0
Weapon Upgrade,Wpn-Rail-Damage03,GAUSS,0,0,0,75,75,0,0
Weapon Upgrade,Wpn-Rail-ROF01,GAUSS,15,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rail-ROF02,GAUSS,30,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rail-ROF03,GAUSS,45,0,0,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Accuracy01,ROCKET,0,10,10,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Accuracy02,ROCKET,0,20,20,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Accuracy03,ROCKET,0,30,30,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Accuracy04,ROCKET,0,40,40,0,0,0,0
Weapon Upgrade,Wpn-Rocket-Damage04,ROCKET,0,0,0,100,100,0,0
Weapon Upgrade,Wpn-Rocket-Damage05,ROCKET,0,0,0,125,125,0,0
Weapon Upgrade,Wpn-Rocket-Damage06,ROCKET,0,0,0,150,150,0,0
Weapon Upgrade,Wpn-Rocket-Damage07,ROCKET,0,0,0,175,175,0,0
Weapon Upgrade,Wpn-Rocket-Damage08,ROCKET,0,0,0,200,200,0,0
Weapon Upgrade,Wpn-Rocket-Damage09,ROCKET,0,0,0,225,225,0,0
Weapon Upgrade,Wpn-Flamer-Damage07,FLAME,0,0,0,175,0,175,0
Weapon Upgrade,Wpn-Flamer-Damage08,FLAME,0,0,0,200,0,200,0
Weapon Upgrade,Wpn-Flamer-Damage09,FLAME,0,0,0,225,0,225,0
Wall Function,Basic Wall Function,A0BabaCornerWall,31
Wall Function,Hardcrete Wall1,A0HardcreteMk1CWall,69
Wall Function,baba Wall Function,A0BabaCornerWall,73
Wall Function,TankTrapFunc,TankTrapC,187
Wall Function,Collective Wall1,CollectiveCWall,231
Wall Function,NEXUS Wall1,NEXUSCWall,232
Structure Upgrade,Struc-Materials01,35,30,0
Structure Upgrade,Struc-Materials02,70,60,0
Structure Upgrade,Struc-Materials03,105,90,0
Structure Upgrade,Sys-Resistance-Upgrade01,0,0,60
Structure Upgrade,Sys-Resistance-Upgrade02,0,0,120
Structure Upgrade,Sys-Resistance-Upgrade03,0,0,300
Structure Upgrade,Struc-Materials04,140,120,0
Structure Upgrade,Struc-Materials05,175,150,0
Structure Upgrade,Struc-Materials06,210,180,0
Structure Upgrade,Struc-Materials07,245,210,0
Structure Upgrade,Struc-Materials08,270,240,0
Structure Upgrade,Struc-Materials09,305,270,0
Structure Upgrade,Struc-Materials10,340,300,0
Structure Upgrade,Sys-Resistance-Upgrade0,0,0,10
WallDefence Upgrade,Defense-WallUpgrade01,35,30
WallDefence Upgrade,Defense-WallUpgrade02,70,60
WallDefence Upgrade,Defense-WallUpgrade03,105,90
WallDefence Upgrade,Defense-WallUpgrade04,140,120
WallDefence Upgrade,Defense-WallUpgrade05,175,150
WallDefence Upgrade,Defense-WallUpgrade06,205,180
WallDefence Upgrade,Defense-WallUpgrade07,240,210
WallDefence Upgrade,Defense-WallUpgrade08,275,240
WallDefence Upgrade,Defense-WallUpgrade09,305,270
WallDefence Upgrade,Defense-WallUpgrade10,340,300
WallDefence Upgrade,Defense-WallUpgrade11,375,330
WallDefence Upgrade,Defense-WallUpgrade12,410,360
Research,Research Facility,14
Research,Research Module,12
Repair Upgrade,RepairFacility-Upgrade01,10
Repair Upgrade,RepairFacility-Upgrade02,20
Repair Upgrade,RepairFacility-Upgrade03,30
Repair Upgrade,Struc-RprFac-Upgrade01,50
Repair Upgrade,Struc-RprFac-Upgrade02,100
Repair Upgrade,Struc-RprFac-Upgrade03,150
Repair Upgrade,Struc-RprFac-Upgrade04,200
Repair Upgrade,Struc-RprFac-Upgrade05,250
Repair Upgrade,Struc-RprFac-Upgrade06,300
Power Upgrade,Struc-PowerModuleMk1,25
Power Upgrade,Struc-Power Upgrade01,50
Power Upgrade,Struc-Power Upgrade02,130
Power Upgrade,Struc-Power Upgrade03,160
Power Upgrade,Struc-Power-Cam2,30
Power Upgrade,Struc-Power Upgrade01b,75
Power Upgrade,Struc-Power Upgrade01c,100
Power Upgrade,Struc-Power Upgrade03a,190
VehicleBody Upgrade,Vehicle-Engine01,5,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine02,10,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Metals01,0,30,30,0,1,0
VehicleBody Upgrade,Vehicle-Metals02,0,60,60,0,1,0
VehicleBody Upgrade,Vehicle-Metals03,0,90,90,0,1,0
VehicleBody Upgrade,Cyborg-Metals01,0,35,35,0,0,1
VehicleBody Upgrade,Cyborg-Metals02,0,70,70,0,0,1
VehicleBody Upgrade,Cyborg-Metals03,0,105,105,0,0,1
VehicleBody Upgrade,Vehicle-Engine03,15,0,0,0,1,0
VehicleBody Upgrade,Cyborg-Metals04,0,140,140,0,0,1
VehicleBody Upgrade,Cyborg-Metals05,0,175,175,0,0,1
VehicleBody Upgrade,Cyborg-Metals06,0,210,210,0,0,1
VehicleBody Upgrade,Cyborg-Metals07,0,245,245,0,0,1
VehicleBody Upgrade,Cyborg-Metals08,0,280,270,0,0,1
VehicleBody Upgrade,Cyborg-Metals09,0,315,305,0,0,1
VehicleBody Upgrade,Cyborg-Metals10,0,350,340,0,0,1
VehicleBody Upgrade,Vehicle-Metals04,0,120,120,0,1,0
VehicleBody Upgrade,Vehicle-Metals05,0,150,150,0,1,0
VehicleBody Upgrade,Vehicle-Metals06,0,180,180,0,1,0
VehicleBody Upgrade,Vehicle-Metals07,0,210,210,0,1,0
VehicleBody Upgrade,Vehicle-Metals08,0,240,240,0,1,0
VehicleBody Upgrade,Vehicle-Metals09,0,270,270,0,1,0
VehicleBody Upgrade,Vehicle-Metals10,0,300,300,0,1,0
VehicleBody Upgrade,Vehicle-Engine04,20,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine05,25,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine06,30,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine07,35,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine08,42,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine09,50,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Engine10,60,0,0,0,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat01,0,0,0,40,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat02,0,0,0,80,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat03,0,0,0,120,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat04,0,0,0,160,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat05,0,0,0,200,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat06,0,0,0,240,1,0
VehicleBody Upgrade,Cyborg-Armor-Heat01,0,0,0,45,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat02,0,0,0,90,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat03,0,0,0,135,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat04,0,0,0,170,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat05,0,0,0,215,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat06,0,0,0,260,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat07,0,0,0,305,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat08,0,0,0,350,0,1
VehicleBody Upgrade,Cyborg-Armor-Heat09,0,0,0,395,0,1
VehicleBody Upgrade,Vehicle-Armor-Heat07,0,0,0,280,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat08,0,0,0,320,1,0
VehicleBody Upgrade,Vehicle-Armor-Heat09,0,0,0,360,1,0
VehicleConst Upgrade,Sys-Engineering-Upgrade01,10
VehicleConst Upgrade,Sys-Engineering-Upgrade02,30
VehicleConst Upgrade,Sys-Engineering-Upgrade03,50
VehicleECM Upgrade,Sys-ECM-Upgrade01,10
VehicleECM Upgrade,Sys-ECM-Upgrade02,20
VehicleECM Upgrade,Sys-ECM-Upgrade03,30
VehicleRepair Upgrade,Sys-Autorepair-Vehicle-Upgrade01,10
VehicleRepair Upgrade,Sys-Autorepair-Vehicle-Upgrade02,20
VehicleSensor Upgrade,Sys-Sensor-Upgrade01,0,25
VehicleSensor Upgrade,Sys-Sensor-Upgrade02,0,40
VehicleSensor Upgrade,Sys-Sensor-Upgrade03,0,50
ReArm,ReArm,10
ReArm Upgrade,ReArmUpgrade,1
ReArm Upgrade,Struc-VTOLPad-Upgrade01,30
ReArm Upgrade,Struc-VTOLPad-Upgrade02,60
ReArm Upgrade,Struc-VTOLPad-Upgrade03,90
ReArm Upgrade,Struc-VTOLPad-Upgrade04,120
ReArm Upgrade,Struc-VTOLPad-Upgrade05,150
ReArm Upgrade,Struc-VTOLPad-Upgrade06,180

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ radiusDamage = 0
radiusLife = 0
flightSpeed = 1
fireOnMove = 0
weaponClass = MISC
weaponClass = KINETIC
weaponSubClass = "MACHINE GUN"
movement = DIRECT
weaponEffect = "ANTI PERSONNEL"

View File

@ -22,7 +22,6 @@ file SWEAPSND "weaponsounds.ini"
file SWEAPMOD "weaponmodifier.ini"
file STEMPL "templates.txt"
file STEMPWEAP "assignweapons.txt"
file SFUNC "functions.txt"
file SSTRUCT "structure.ini"
file SSTRMOD "structuremodifier.ini"
file SFEAT "features.txt"

View File

@ -69,8 +69,6 @@ noinst_HEADERS = \
fpath.h \
frend.h \
frontend.h \
functiondef.h \
function.h \
game.h \
gateway.h \
geometry.h \
@ -195,7 +193,6 @@ warzone2100_SOURCES = \
feature.cpp \
fpath.cpp \
frontend.cpp \
function.cpp \
game.cpp \
gateway.cpp \
geometry.cpp \

View File

@ -176,15 +176,15 @@ static bool actionInAttackRange(DROID *psDroid, BASE_OBJECT *psObj, int weapon_s
ASSERT_OR_RETURN( false, compIndex < numWeaponStats, "Invalid range referenced for numWeaponStats, %d > %d", compIndex, numWeaponStats);
psStats = asWeaponStats + compIndex;
longRange = proj_GetLongRange(psStats);
longRange = proj_GetLongRange(psStats, psDroid->player);
rangeSq = longRange * longRange;
/* check max range */
if ( radSq <= rangeSq )
{
/* check min range */
rangeSq = psStats->minRange * psStats->minRange;
if ( radSq >= rangeSq || !proj_Direct( psStats ) )
const int minrange = psStats->upgrade[psDroid->player].minRange;
if (radSq >= minrange * minrange || !proj_Direct(psStats))
{
return true;
}
@ -217,15 +217,15 @@ bool actionInRange(DROID *psDroid, BASE_OBJECT *psObj, int weapon_slot)
radSq = dx*dx + dy*dy;
longRange = proj_GetLongRange(psStats);
longRange = proj_GetLongRange(psStats, psDroid->player);
rangeSq = longRange * longRange;
/* check max range */
if ( radSq <= rangeSq )
{
/* check min range */
rangeSq = psStats->minRange * psStats->minRange;
if ( radSq >= rangeSq || !proj_Direct( psStats ) )
const int minrange = psStats->upgrade[psDroid->player].minRange;
if (radSq >= minrange * minrange || !proj_Direct(psStats))
{
return true;
}
@ -259,7 +259,7 @@ static bool actionInsideMinRange(DROID *psDroid, BASE_OBJECT *psObj, WEAPON_STAT
radSq = dx*dx + dy*dy;
minRange = (SDWORD)psStats->minRange;
minRange = psStats->upgrade[psDroid->player].minRange;
rangeSq = minRange * minRange;
// check min range
@ -416,7 +416,7 @@ bool actionTargetTurret(BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, WEAPON *
onTarget = abs(angleDelta(targetRotation - (tRotation + psAttacker->rot.direction))) <= rotationTolerance;
/* Set muzzle pitch if not repairing or outside minimum range */
if (!bRepair && objPosDiffSq(psAttacker, psTarget) > psWeapStats->minRange * psWeapStats->minRange)
if (!bRepair && objPosDiffSq(psAttacker, psTarget) > psWeapStats->upgrade[psAttacker->player].minRange * psWeapStats->upgrade[psAttacker->player].minRange)
{
/* get target distance */
Vector3i delta = psTarget->pos - attackerMuzzlePos;
@ -1202,7 +1202,7 @@ void actionUpdateDroid(DROID *psDroid)
// in case psWeapStats is still NULL
else if (psWeapStats)
{ // if the vtol is far enough away head for the target again
if (rangeSq > (SDWORD)(psWeapStats->longRange * psWeapStats->longRange))
if (rangeSq > psWeapStats->upgrade[psDroid->player].maxRange * psWeapStats->upgrade[psDroid->player].maxRange)
{
// don't do another attack run if already heading for the target
const Vector2i diff = psDroid->sMove.destination - removeZ(psDroid->psActionTarget[0]->pos);
@ -1715,7 +1715,7 @@ void actionUpdateDroid(DROID *psDroid)
(order->psObj->type != OBJ_STRUCTURE))
{
Vector2i diff = removeZ(psDroid->pos - order->psObj->pos);
int rangeSq = asWeaponStats[psDroid->asWeaps[0].nStat].longRange / 2; // move close to sensor
int rangeSq = asWeaponStats[psDroid->asWeaps[0].nStat].upgrade[psDroid->player].maxRange / 2; // move close to sensor
rangeSq = rangeSq * rangeSq;
if (diff*diff < rangeSq)
{

View File

@ -77,12 +77,12 @@ PlayerMask alliancebits[MAX_PLAYER_SLOTS];
/// A bitfield for the satellite uplink
PlayerMask satuplinkbits;
static int aiObjRange(DROID *psDroid, int weapon_slot)
static int aiDroidRange(DROID *psDroid, int weapon_slot)
{
int32_t longRange;
if (psDroid->droidType == DROID_SENSOR)
{
longRange = psDroid->sensorRange;
longRange = objSensorRange(psDroid);
}
else if (psDroid->numWeaps == 0 || psDroid->asWeaps[0].nStat == 0)
{
@ -92,7 +92,7 @@ static int aiObjRange(DROID *psDroid, int weapon_slot)
else
{
WEAPON_STATS *psWStats = psDroid->asWeaps[weapon_slot].nStat + asWeaponStats;
longRange = proj_GetLongRange(psWStats);
longRange = proj_GetLongRange(psWStats, psDroid->player);
}
return longRange;
@ -109,13 +109,13 @@ static bool aiStructHasRange(STRUCTURE *psStruct, BASE_OBJECT *psTarget, int wea
WEAPON_STATS *psWStats = psStruct->asWeaps[weapon_slot].nStat + asWeaponStats;
int longRange = proj_GetLongRange(psWStats);
int longRange = proj_GetLongRange(psWStats, psStruct->player);
return objPosDiffSq(psStruct, psTarget) < longRange*longRange && lineOfFire(psStruct, psTarget, weapon_slot, true);
}
static bool aiDroidHasRange(DROID *psDroid, BASE_OBJECT *psTarget, int weapon_slot)
{
int32_t longRange = aiObjRange(psDroid, weapon_slot);
int32_t longRange = aiDroidRange(psDroid, weapon_slot);
return objPosDiffSq(psDroid, psTarget) < longRange*longRange;
}
@ -163,10 +163,10 @@ bool aiShutdown(void)
/** Search the global list of sensors for a possible target for psObj. */
static BASE_OBJECT *aiSearchSensorTargets(BASE_OBJECT *psObj, int weapon_slot, WEAPON_STATS *psWStats, UWORD *targetOrigin)
{
int longRange = proj_GetLongRange(psWStats);
int longRange = proj_GetLongRange(psWStats, psObj->player);
int tarDist = longRange * longRange;
bool foundCB = false;
int minDist = psWStats->minRange * psWStats->minRange;
int minDist = psWStats->upgrade[psObj->player].minRange * psWStats->upgrade[psObj->player].minRange;
BASE_OBJECT *psSensor, *psTarget = NULL;
if (targetOrigin)
@ -330,10 +330,10 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
bEmpWeap = (attackerWeapon->weaponSubClass == WSC_EMP);
int dist = iHypot(removeZ(psAttacker->pos - psTarget->pos));
bool tooClose = dist <= attackerWeapon->minRange;
bool tooClose = dist <= attackerWeapon->upgrade[psAttacker->player].minRange;
if (tooClose)
{
dist = psAttacker->sensorRange; // If object is too close to fire at, consider it to be at maximum range.
dist = objSensorRange(psAttacker); // If object is too close to fire at, consider it to be at maximum range.
}
/* Calculate attack weight */
@ -394,7 +394,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
/* Now calculate the overall weight */
attackWeight = asWeaponModifier[weaponEffect][(asPropulsionStats + targetDroid->asBits[COMP_PROPULSION].nStat)->propulsionType] // Our weapon's effect against target
+ asWeaponModifierBody[weaponEffect][(asBodyStats + targetDroid->asBits[COMP_BODY].nStat)->size]
+ WEIGHT_DIST_TILE_DROID * psAttacker->sensorRange/TILE_UNITS
+ WEIGHT_DIST_TILE_DROID * objSensorRange(psAttacker) / TILE_UNITS
- WEIGHT_DIST_TILE_DROID * dist/TILE_UNITS // farther droids are less attractive
+ WEIGHT_HEALTH_DROID * damageRatio/100 // we prefer damaged droids
+ targetTypeBonus; // some droid types have higher priority
@ -436,7 +436,7 @@ static SDWORD targetAttackWeight(BASE_OBJECT *psTarget, BASE_OBJECT *psAttacker,
/* Now calculate the overall weight */
attackWeight = asStructStrengthModifier[weaponEffect][targetStructure->pStructureType->strength] // Our weapon's effect against target
+ WEIGHT_DIST_TILE_STRUCT * psAttacker->sensorRange/TILE_UNITS
+ WEIGHT_DIST_TILE_STRUCT * objSensorRange(psAttacker) / TILE_UNITS
- WEIGHT_DIST_TILE_STRUCT * dist/TILE_UNITS // farther structs are less attractive
+ WEIGHT_HEALTH_STRUCT * damageRatio/100 // we prefer damaged structures
+ targetTypeBonus; // some structure types have higher priority
@ -550,7 +550,7 @@ int aiBestNearestTarget(DROID *psDroid, BASE_OBJECT **ppsObj, int weapon_slot, i
electronic = electronicDroid(psDroid);
// Range was previously 9*TILE_UNITS. Increasing this doesn't seem to help much, though. Not sure why.
int droidRange = std::min(aiObjRange(psDroid, weapon_slot) + extraRange, psDroid->sensorRange + 6*TILE_UNITS);
int droidRange = std::min(aiDroidRange(psDroid, weapon_slot) + extraRange, objSensorRange(psDroid) + 6*TILE_UNITS);
static GridList gridList; // static to avoid allocations.
gridList = gridStartIterate(psDroid->pos.x, psDroid->pos.y, droidRange);
@ -839,7 +839,7 @@ bool aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot
ASSERT(((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0, "no weapons on structure");
psWStats = ((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat + asWeaponStats;
int longRange = proj_GetLongRange(psWStats);
int longRange = proj_GetLongRange(psWStats, psObj->player);
// see if there is a target from the command droids
psTarget = NULL;

View File

@ -103,11 +103,8 @@ struct BASE_OBJECT : public SIMPLE_OBJECT
UDWORD body; ///< Hit points with lame name
UDWORD periodicalDamageStart; ///< When the object entered the fire
UDWORD periodicalDamage; ///< How much damage has been done since the object entered the fire
SDWORD sensorRange; ///< Range of sensor
SDWORD ECMMod; ///< Ability to conceal others from sensors
bool bTargetted; ///< Whether object is targetted by a selectedPlayer droid sensor (quite the hack)
TILEPOS *watchedTiles; ///< Variable size array of watched tiles, NULL for features
UDWORD armour[WC_NUM_WEAPON_CLASSES];
NEXTOBJ psNext; ///< Pointer to the next object in the object list
NEXTOBJ psNextFunc; ///< Pointer to the next object in the function list

View File

@ -72,7 +72,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
unsigned fireTime = gameTime - deltaGameTime + 1; // Can fire earliest at the start of the tick.
// See if reloadable weapon.
if (psStats->reloadTime)
if (psStats->upgrade[psAttacker->player].reloadTime)
{
unsigned reloadTime = psWeap->lastFired + weaponReloadTime(psStats, psAttacker->player);
if (psWeap->ammo == 0) // Out of ammo?
@ -87,7 +87,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
if (reloadTime <= fireTime)
{
//reset the ammo level
psWeap->ammo = psStats->numRounds;
psWeap->ammo = psStats->upgrade[psAttacker->player].numRounds;
}
}
@ -135,7 +135,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
/* Now see if the target is in range - also check not too near */
int dist = iHypot(removeZ(deltaPos));
longRange = proj_GetLongRange(psStats);
longRange = proj_GetLongRange(psStats, psAttacker->player);
int min_angle = 0;
// Calculate angle for indirect shots
@ -158,7 +158,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
}
int baseHitChance = 0;
if (dist <= longRange && dist >= psStats->minRange)
if (dist <= longRange && dist >= psStats->upgrade[psAttacker->player].minRange)
{
// get weapon chance to hit in the long range
baseHitChance = weaponLongHit(psStats,psAttacker->player);
@ -210,7 +210,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
psWeap->lastFired = fireTime;
/* reduce ammo if salvo */
if (psStats->reloadTime)
if (psStats->upgrade[psAttacker->player].reloadTime)
{
psWeap->ammo--;
}
@ -227,7 +227,7 @@ bool combFire(WEAPON *psWeap, BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget, in
DROID *psDroid = castDroid(psTarget);
int32_t flightTime;
if (proj_Direct(psStats) || dist <= psStats->minRange)
if (proj_Direct(psStats) || dist <= psStats->upgrade[psAttacker->player].minRange)
{
flightTime = dist * GAME_TICKS_PER_SEC / psStats->flightSpeed;
}
@ -340,6 +340,28 @@ void counterBatteryFire(BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
}
}
int objArmour(BASE_OBJECT *psObj, WEAPON_CLASS weaponClass)
{
int armour = 0;
if (psObj->type == OBJ_DROID)
{
armour = ((DROID *)psObj)->armour[weaponClass];
}
else if (psObj->type == OBJ_STRUCTURE && weaponClass == WC_KINETIC && ((STRUCTURE *)psObj)->status != SS_BEING_BUILT)
{
armour = ((STRUCTURE *)psObj)->pStructureType->upgrade[psObj->player].armour;
}
else if (psObj->type == OBJ_STRUCTURE && weaponClass == WC_HEAT && ((STRUCTURE *)psObj)->status != SS_BEING_BUILT)
{
armour = ((STRUCTURE *)psObj)->pStructureType->upgrade[psObj->player].thermal;
}
else if (psObj->type == OBJ_FEATURE && weaponClass == WC_KINETIC)
{
armour = ((FEATURE *)psObj)->psStats->armourValue;
}
return armour;
}
/* Deals damage to an object
* \param psObj object to deal damage to
* \param damage amount of damage to deal
@ -349,7 +371,8 @@ void counterBatteryFire(BASE_OBJECT *psAttacker, BASE_OBJECT *psTarget)
*/
int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAPON_CLASS weaponClass, WEAPON_SUBCLASS weaponSubClass, bool isDamagePerSecond)
{
int actualDamage, armour, level = 1, lastHit = psObj->timeLastHit;
int actualDamage, level = 1, lastHit = psObj->timeLastHit;
int armour = objArmour(psObj, weaponClass);
// If the previous hit was by an EMP cannon and this one is not:
// don't reset the weapon class and hit time
@ -369,14 +392,8 @@ int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAP
// apply game difficulty setting
damage = modifyForDifficultyLevel(damage, psObj->player != selectedPlayer);
armour = psObj->armour[weaponClass];
if (psObj->type == OBJ_STRUCTURE || psObj->type == OBJ_DROID)
{
if (psObj->type == OBJ_STRUCTURE && ((STRUCTURE *)psObj)->status == SS_BEING_BUILT)
{
armour = 0;
}
// Force sending messages, even if messages were turned off, since a non-synchronised script will execute here. (Aaargh!)
bool bMultiMessagesBackup = bMultiMessages;
bMultiMessages = bMultiPlayer;
@ -450,7 +467,7 @@ int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAP
unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BASE_OBJECT *psTarget)
{
unsigned int damage;
int actualDamage, armour = 0, level = 1;
int actualDamage, armour, level = 1;
if (psTarget == NULL)
return 0; // Hard to destroy the ground. The armour on the mud is very strong and blocks all damage.
@ -465,8 +482,7 @@ unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BA
// apply game difficulty setting
damage = modifyForDifficultyLevel(damage, psTarget->player != selectedPlayer);
armour = MAX(armour, psTarget->armour[psStats->weaponClass]);
armour = objArmour(psTarget, psStats->weaponClass);
if (psTarget->type == OBJ_DROID)
{
@ -475,10 +491,6 @@ unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BA
// Retrieve highest, applicable, experience level
level = getDroidEffectiveLevel(psDroid);
}
else if (psTarget->type == OBJ_STRUCTURE && ((STRUCTURE *)psTarget)->status == SS_BEING_BUILT)
{
armour = 0;
}
//debug(LOG_ATTACK, "objGuessFutureDamage(%d): body %d armour %d damage: %d", psObj->id, psObj->body, armour, damage);
// Reduce damage taken by EXP_REDUCE_DAMAGE % for each experience level

View File

@ -52,4 +52,6 @@ int32_t objDamage(BASE_OBJECT *psObj, unsigned damage, unsigned originalhp, WEAP
unsigned int objGuessFutureDamage(WEAPON_STATS *psStats, unsigned int player, BASE_OBJECT *psTarget);
int objArmour(BASE_OBJECT *psObj, WEAPON_CLASS weaponClass);
#endif // __INCLUDED_SRC_COMBAT_H__

View File

@ -101,7 +101,7 @@ bool loadConfig()
game.hash.setZero();
game.maxPlayers = 4;
game.power = ini.value("power", LEV_MED).toInt();
game.power = ini.value("powerLevel", LEV_MED).toInt();
game.base = ini.value("base", CAMP_BASE).toInt();
game.alliance = ini.value("alliance", NO_ALLIANCES).toInt();
game.scavengers = ini.value("scavengers", false).toBool();
@ -206,7 +206,7 @@ bool saveConfig()
ini.setValue("mapName", game.map); // map name
ini.setValue("mapHash", game.hash.toString().c_str()); // map hash
ini.setValue("maxPlayers", game.maxPlayers); // maxPlayers
ini.setValue("power", game.power); // power
ini.setValue("powerLevel", game.power); // power
ini.setValue("base", game.base); // size of base
ini.setValue("alliance", game.alliance); // allow alliances
ini.setValue("scavengers", game.scavengers);
@ -267,7 +267,7 @@ bool reloadMPConfig(void)
game.hash.setZero();
game.maxPlayers = 4;
ini.setValue("power", game.power); // power
ini.setValue("powerLevel", game.power); // power
ini.setValue("base", game.base); // size of base
ini.setValue("alliance", game.alliance); // allow alliances
return true;
@ -286,7 +286,7 @@ bool reloadMPConfig(void)
game.hash.setZero();
game.maxPlayers = 4;
game.power = ini.value("power", LEV_MED).toInt();
game.power = ini.value("powerLevel", LEV_MED).toInt();
game.base = ini.value("base", CAMP_BASE).toInt();
game.alliance = ini.value("alliance", NO_ALLIANCES).toInt();

View File

@ -41,7 +41,6 @@
#include "data.h"
#include "droid.h"
#include "feature.h"
#include "function.h"
#include "mechanics.h"
#include "message.h"
#include "multiplay.h"
@ -429,30 +428,6 @@ static void dataSFEATRelease(WZ_DECL_UNUSED void *pData)
featureStatsShutDown();
}
/* Load the Functions stats */
static bool bufferSFUNCLoad(const char *pBuffer, UDWORD size, void **ppData)
{
calcDataHash((uint8_t *)pBuffer, size, DATA_SFUNC);
if (!loadFunctionStats(pBuffer, size))
{
return false;
}
//adjust max values of stats used in the design screen due to any possible upgrades
adjustMaxDesignStats();
// set a dummy value so the release function gets called
*ppData = (void *)1;
return true;
}
// release the function stats
static void dataSFUNCRelease(WZ_DECL_UNUSED void *pData)
{
FunctionShutDown();
}
// release the research stats
static void dataRESCHRelease(WZ_DECL_UNUSED void *pData)
{
@ -916,7 +891,6 @@ static const RES_TYPE_MIN_BUF BufferResourceTypes[] =
{"STEMPL", bufferSTEMPLLoad, dataSTEMPLRelease}, //template and associated files
{"STEMPWEAP", bufferSTEMPWEAPLoad, NULL},
{"SFEAT", bufferSFEATLoad, dataSFEATRelease}, //feature stats file
{"SFUNC", bufferSFUNCLoad, dataSFUNCRelease}, //function stats file
{"SMSG", bufferSMSGLoad, dataSMSGRelease},
{"IMD", dataIMDBufferLoad, (RES_FREE)iV_IMDRelease},
};

View File

@ -47,7 +47,6 @@
#include "edit3d.h"
#include "structure.h"
#include "research.h"
#include "function.h"
#include "lib/gamelib/gtime.h"
#include "hci.h"
#include "stats.h"
@ -2323,7 +2322,7 @@ static void intSetWeaponStats(WEAPON_STATS *psStats)
(psStats->ref < REF_WEAPON_START + REF_RANGE), "stats ref is out of range");
/* range */
widgSetBarSize(psWScreen, IDDES_WEAPRANGE, proj_GetLongRange(psStats));
widgSetBarSize(psWScreen, IDDES_WEAPRANGE, proj_GetLongRange(psStats, selectedPlayer));
/* rate of fire */
widgSetBarSize(psWScreen, IDDES_WEAPROF, weaponROF(psStats, (SBYTE)selectedPlayer));
/* damage */
@ -2344,7 +2343,7 @@ static void intSetWeaponShadowStats(WEAPON_STATS *psStats)
if (psStats)
{
/* range */
widgSetMinorBarSize(psWScreen, IDDES_WEAPRANGE, proj_GetLongRange(psStats));
widgSetMinorBarSize(psWScreen, IDDES_WEAPRANGE, proj_GetLongRange(psStats, selectedPlayer));
/* rate of fire */
widgSetMinorBarSize(psWScreen, IDDES_WEAPROF, weaponROF(psStats, (SBYTE)selectedPlayer));
/* damage */
@ -2378,12 +2377,11 @@ static void intSetBodyStats(BODY_STATS *psStats)
/* armour */
//do kinetic armour
widgSetBarSize(psWScreen, IDDES_BODYARMOUR_K, bodyArmour(psStats, selectedPlayer, DROID_BODY_UPGRADE, WC_KINETIC));
widgSetBarSize(psWScreen, IDDES_BODYARMOUR_K, bodyArmour(psStats, selectedPlayer, WC_KINETIC));
//do heat armour
widgSetBarSize(psWScreen, IDDES_BODYARMOUR_H, bodyArmour(psStats, selectedPlayer, DROID_BODY_UPGRADE, WC_HEAT));
widgSetBarSize(psWScreen, IDDES_BODYARMOUR_H, bodyArmour(psStats, selectedPlayer, WC_HEAT));
/* power */
//widgSetBarSize(psWScreen, IDDES_BODYPOWER, psStats->powerOutput);
widgSetBarSize(psWScreen, IDDES_BODYPOWER, bodyPower(psStats, selectedPlayer, DROID_BODY_UPGRADE));
widgSetBarSize(psWScreen, IDDES_BODYPOWER, bodyPower(psStats, selectedPlayer));
/* weight */
widgSetBarSize(psWScreen, IDDES_BODYWEIGHT, psStats->weight);
@ -2406,11 +2404,11 @@ static void intSetBodyShadowStats(BODY_STATS *psStats)
if (psStats)
{
/* armour - kinetic*/
widgSetMinorBarSize(psWScreen, IDDES_BODYARMOUR_K, bodyArmour(psStats, selectedPlayer, DROID_BODY_UPGRADE, WC_KINETIC));
widgSetMinorBarSize(psWScreen, IDDES_BODYARMOUR_K, bodyArmour(psStats, selectedPlayer, WC_KINETIC));
//armour - heat
widgSetMinorBarSize(psWScreen, IDDES_BODYARMOUR_H, bodyArmour(psStats, selectedPlayer, DROID_BODY_UPGRADE, WC_HEAT));
widgSetMinorBarSize(psWScreen, IDDES_BODYARMOUR_H, bodyArmour(psStats, selectedPlayer, WC_HEAT));
/* power */
widgSetMinorBarSize(psWScreen, IDDES_BODYPOWER, bodyPower(psStats, selectedPlayer, DROID_BODY_UPGRADE));
widgSetMinorBarSize(psWScreen, IDDES_BODYPOWER, bodyPower(psStats, selectedPlayer));
/* weight */
widgSetMinorBarSize(psWScreen, IDDES_BODYWEIGHT, psStats->weight);
}
@ -2638,7 +2636,7 @@ static void intSetTemplateBodyShadowStats(COMPONENT_STATS *psStats)
//add weapon HP
body += weaponBody1 + weaponBody2 + weaponBody3;
body += (body * asBodyUpgrade[selectedPlayer]->body / 100);
body += (body * asBodyStats[sCurrDesign.asParts[COMP_BODY]].upgrade[selectedPlayer].body / 100);
widgSetMinorBarSize(psWScreen, IDDES_BODYPOINTS, body);
}

View File

@ -1601,7 +1601,7 @@ static void dealWithLMBDroid(DROID* psDroid, SELECTION_TYPE selection)
CONPRINTF(ConsoleString, (ConsoleString, "(Enemy!) %s - Damage %d%% - ID %d - experience %f, %s - order %s - action %s - sensor range %d - ECM %d - pitch %.0f",
droidGetName(psDroid), 100 - clip(PERCENT(psDroid->body, psDroid->originalBody), 0, 100), psDroid->id,
psDroid->experience/65536.f, getDroidLevelName(psDroid), getDroidOrderName(psDroid->order.type), getDroidActionName(psDroid->action),
droidSensorRange(psDroid), droidConcealment(psDroid), UNDEG(psDroid->rot.pitch)));
droidSensorRange(psDroid), droidJammerPower(psDroid), UNDEG(psDroid->rot.pitch)));
FeedbackOrderGiven();
}
#endif
@ -1750,7 +1750,7 @@ static void dealWithLMBDroid(DROID* psDroid, SELECTION_TYPE selection)
droidGetName(psDroid),
100 - clip(PERCENT(psDroid->body, psDroid->originalBody), 0, 100), psDroid->id,
psDroid->experience/65536.f, getDroidLevelName(psDroid), getDroidOrderName(psDroid->order.type), getDroidActionName(psDroid->action),
droidSensorRange(psDroid), droidConcealment(psDroid), UNDEG(psDroid->rot.pitch), psDroid->lastFrustratedTime));
droidSensorRange(psDroid), droidJammerPower(psDroid), UNDEG(psDroid->rot.pitch), psDroid->lastFrustratedTime));
FeedbackOrderGiven();
}
else
@ -1807,7 +1807,7 @@ static void dealWithLMBStructure(STRUCTURE* psStructure, SELECTION_TYPE selectio
if (getDebugMappingStatus())
{
CONPRINTF(ConsoleString, (ConsoleString, "(Enemy!) %s, ref: %d, ID: %d Damage %d%%", psStructure->pStructureType->pName, psStructure->pStructureType->ref,
psStructure->id, 100 - clip(PERCENT(psStructure->body, psStructure->pStructureType->bodyPoints), 0, 100)));
psStructure->id, 100 - clip(PERCENT(psStructure->body, psStructure->pStructureType->upgrade[psStructure->player].hitpoints), 0, 100)));
}
#endif
orderSelectedObjAdd(selectedPlayer, (BASE_OBJECT*)psStructure, ctrlShiftDown());
@ -2246,7 +2246,7 @@ static void dealWithRMB( void )
droidGetName(psDroid),
100 - clip(PERCENT(psDroid->body, psDroid->originalBody), 0, 100), psDroid->id,
psDroid->experience/65536.f, getDroidLevelName(psDroid), getDroidOrderName(psDroid->order.type), getDroidActionName(psDroid->action),
droidSensorRange(psDroid), droidConcealment(psDroid)));
droidSensorRange(psDroid), droidJammerPower(psDroid)));
FeedbackOrderGiven();
}
else

View File

@ -3864,26 +3864,23 @@ static void showWeaponRange(BASE_OBJECT *psObj)
{
uint32_t weaponRange;
uint32_t minRange;
int compIndex;
WEAPON_STATS *psStats;
if (psObj->type == OBJ_DROID)
{
WEAPON_STATS *psStats = NULL;
DROID *psDroid = (DROID*)psObj;
compIndex = psDroid->asWeaps[0].nStat; //weapon_slot
const int compIndex = psDroid->asWeaps[0].nStat; // weapon_slot
ASSERT_OR_RETURN( , compIndex < numWeaponStats, "Invalid range referenced for numWeaponStats, %d > %d", compIndex, numWeaponStats);
psStats = asWeaponStats + compIndex;
weaponRange = psStats->longRange;
minRange = psStats->minRange;
}
else
{
STRUCTURE *psStruct = (STRUCTURE*)psObj;
if(psStruct->pStructureType->numWeaps == 0) return;
weaponRange = psStruct->pStructureType->psWeapStat[0]->longRange;
minRange = psStruct->pStructureType->psWeapStat[0]->minRange;
if (psStruct->pStructureType->numWeaps == 0) return;
psStats = psStruct->pStructureType->psWeapStat[0];
}
weaponRange = psStats->upgrade[psObj->player].maxRange;
minRange = psStats->upgrade[psObj->player].minRange;
showEffectCircle(psObj->pos, weaponRange, 40, EFFECT_EXPLOSION, EXPLOSION_TYPE_SMALL);
if (minRange > 0)
{
@ -3893,7 +3890,7 @@ static void showWeaponRange(BASE_OBJECT *psObj)
static void showSensorRange2(BASE_OBJECT *psObj)
{
showEffectCircle(psObj->pos, psObj->sensorRange, 80, EFFECT_EXPLOSION, EXPLOSION_TYPE_LASER);
showEffectCircle(psObj->pos, objSensorRange(psObj), 80, EFFECT_EXPLOSION, EXPLOSION_TYPE_LASER);
showWeaponRange(psObj);
}

View File

@ -58,7 +58,6 @@
#include "display.h"
#include "console.h"
#include "component.h"
#include "function.h"
#include "lighting.h"
#include "multiplay.h"
#include "warcam.h"
@ -156,8 +155,10 @@ int droidReloadBar(BASE_OBJECT *psObj, WEAPON *psWeap, int weapon_slot)
psStats = asWeaponStats + psWeap->nStat;
/* Justifiable only when greater than a one second reload or intra salvo time */
bSalvo = (psStats->numRounds > 1);
if ((bSalvo && psStats->reloadTime > GAME_TICKS_PER_SEC) || psStats->firePause > GAME_TICKS_PER_SEC || (psObj->type == OBJ_DROID && isVtolDroid((DROID *)psObj)))
bSalvo = (psStats->upgrade[psObj->player].numRounds > 1);
if ((bSalvo && psStats->upgrade[psObj->player].reloadTime > GAME_TICKS_PER_SEC)
|| psStats->upgrade[psObj->player].firePause > GAME_TICKS_PER_SEC
|| (psObj->type == OBJ_DROID && isVtolDroid((DROID *)psObj)))
{
if (psObj->type == OBJ_DROID && isVtolDroid((DROID *)psObj))
{
@ -1276,7 +1277,7 @@ bool droidUpdateRestore( DROID *psDroid )
ASSERT_OR_RETURN(false, psDroid->action == DACTION_RESTORE, "unit is not restoring");
psStruct = (STRUCTURE *)psDroid->order.psObj;
ASSERT_OR_RETURN(false, psStruct->type == OBJ_STRUCTURE, "target is not a structure");
ASSERT_OR_RETURN(false, psStruct->pStructureType->resistance != 0, "invalid structure for EW");
ASSERT_OR_RETURN(false, psStruct->pStructureType->upgrade[psStruct->player].resistance != 0, "invalid structure for EW");
ASSERT_OR_RETURN(false, psDroid->asWeaps[0].nStat > 0, "droid doesn't have any weapons");
@ -1601,7 +1602,7 @@ UDWORD calcTemplateBody(DROID_TEMPLATE *psTemplate, UBYTE player)
}
//add on any upgrade value that may need to be applied
body += (body * asBodyUpgrade[player]->body / 100);
body += body * psStats->upgrade[player].body / 100;
return body;
}
@ -1655,14 +1656,13 @@ UDWORD calcDroidBaseSpeed(DROID_TEMPLATE *psTemplate, UDWORD weight, UBYTE playe
speed = (asPropulsionTypes[(asPropulsionStats + psTemplate->
asParts[COMP_PROPULSION])->propulsionType].powerRatioMult *
bodyPower(asBodyStats + psTemplate->asParts[COMP_BODY],
player, CYBORG_BODY_UPGRADE)) / MAX(1, weight);
player)) / MAX(1, weight);
}
else
{
speed = (asPropulsionTypes[(asPropulsionStats + psTemplate->
asParts[COMP_PROPULSION])->propulsionType].powerRatioMult *
bodyPower(asBodyStats + psTemplate->asParts[COMP_BODY],
player, DROID_BODY_UPGRADE)) / MAX(1, weight);
bodyPower(asBodyStats + psTemplate->asParts[COMP_BODY], player)) / MAX(1, weight);
}
// reduce the speed of medium/heavy VTOLs
@ -1678,8 +1678,8 @@ UDWORD calcDroidBaseSpeed(DROID_TEMPLATE *psTemplate, UDWORD weight, UBYTE playe
}
}
// Wateremelon:applies the engine output bonus if output > weight
if ( (asBodyStats + psTemplate->asParts[COMP_BODY])->powerOutput > weight )
// applies the engine output bonus if output > weight
if ((asBodyStats + psTemplate->asParts[COMP_BODY])->base.power > weight)
{
speed = speed * 3 / 2;
}
@ -1892,15 +1892,12 @@ DROID *reallyBuildDroid(DROID_TEMPLATE *pTemplate, Position pos, UDWORD player,
initDroidMovement(psDroid);
//allocate 'easy-access' data!
objSensorCache((BASE_OBJECT *)psDroid, asSensorStats + pTemplate->asParts[COMP_SENSOR]);
objEcmCache((BASE_OBJECT *)psDroid, asECMStats + pTemplate->asParts[COMP_ECM]);
psDroid->body = calcTemplateBody(pTemplate, (UBYTE)player); // Redundant? (Is set in droidSetBits, too.)
psDroid->originalBody = psDroid->body; // Redundant? (Is set in droidSetBits, too.)
for (inc = 0; inc < WC_NUM_WEAPON_CLASSES; inc++)
{
psDroid->armour[inc] = bodyArmour(asBodyStats + pTemplate->asParts[COMP_BODY], player,
cyborgDroid(psDroid) ? CYBORG_BODY_UPGRADE : DROID_BODY_UPGRADE, (WEAPON_CLASS)inc);
psDroid->armour[inc] = bodyArmour(asBodyStats + pTemplate->asParts[COMP_BODY], player, (WEAPON_CLASS)inc);
}
/* Set droid's initial illumination */
@ -1989,7 +1986,7 @@ void droidSetBits(DROID_TEMPLATE *pTemplate,DROID *psDroid)
if (inc < pTemplate->numWeaps)
{
psDroid->asWeaps[inc].nStat = pTemplate->asWeaps[inc];
psDroid->asWeaps[inc].ammo = (asWeaponStats + psDroid->asWeaps[inc].nStat)->numRounds;
psDroid->asWeaps[inc].ammo = (asWeaponStats + psDroid->asWeaps[inc].nStat)->upgrade[psDroid->player].numRounds;
}
psDroid->asWeaps[inc].usedAmmo = 0;
}
@ -3090,26 +3087,16 @@ bool allVtolsRearmed(DROID *psDroid)
/*returns a count of the base number of attack runs for the weapon attached to the droid*/
//adds int weapon_slot
UWORD getNumAttackRuns(DROID *psDroid, int weapon_slot)
{
UWORD numAttackRuns;
ASSERT_OR_RETURN(0, isVtolDroid(psDroid), "not a VTOL Droid");
/*if weapon attached to the droid is a salvo weapon, then number of shots that
can be fired = vtolAttackRuns*numRounds */
if (asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].reloadTime)
// if weapon is a salvo weapon, then number of shots that can be fired = vtolAttackRuns * numRounds
if (asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].upgrade[psDroid->player].reloadTime)
{
numAttackRuns = (UWORD)(asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].numRounds *
asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].vtolAttackRuns);
return asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].upgrade[psDroid->player].numRounds
* asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].vtolAttackRuns;
}
else
{
numAttackRuns = asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].vtolAttackRuns;
}
return numAttackRuns;
return asWeaponStats[psDroid->asWeaps[weapon_slot].nStat].vtolAttackRuns;
}
/*Checks a vtol for being fully armed and fully repaired to see if ready to
@ -3364,25 +3351,11 @@ DROID *giftSingleDroid(DROID *psD, UDWORD to)
/*calculates the electronic resistance of a droid based on its experience level*/
SWORD droidResistance(DROID *psDroid)
{
unsigned resistance;
CHECK_DROID(psDroid);
resistance = psDroid->experience / (65536/DROID_RESISTANCE_FACTOR);
//ensure base minimum in MP before the upgrade effect
if (bMultiPlayer)
{
//ensure resistance is a base minimum
resistance = MAX(resistance, DROID_RESISTANCE_FACTOR);
}
//structure resistance upgrades are passed on to droids
resistance = resistance + resistance*asStructureUpgrade[psDroid->player].resistance / 100;
//ensure resistance is a base minimum
resistance = MAX(resistance, DROID_RESISTANCE_FACTOR);
BODY_STATS *psStats = asBodyStats + psDroid->asBits[COMP_BODY].nStat;
int resistance = psDroid->experience / (65536 / MAX(1, psStats->upgrade[psDroid->player].resistance));
// ensure resistance is a base minimum
resistance = MAX(resistance, psStats->upgrade[psDroid->player].resistance);
return MIN(resistance, INT16_MAX);
}

View File

@ -346,11 +346,6 @@ static inline int droidJammerPower(const DROID* psDroid)
return objJammerPower((const BASE_OBJECT*)psDroid);
}
static inline int droidConcealment(const DROID* psDroid)
{
return objConcealment((const BASE_OBJECT*)psDroid);
}
/*
* Component stat helper functions
*/

View File

@ -131,6 +131,7 @@ struct DROID : public BASE_OBJECT
UDWORD lastFrustratedTime; ///< Set when eg being stuck; used for eg firing indiscriminately at map features to clear the way
SWORD resistance; ///< used in Electronic Warfare
UDWORD armour[WC_NUM_WEAPON_CLASSES];
UDWORD numWeaps; ///< Watermelon:Re-enabled this,I need this one in droid.c
WEAPON asWeaps[DROID_MAXWEAPS];

View File

@ -162,7 +162,7 @@ int32_t featureDamage(FEATURE *psFeature, unsigned damage, WEAPON_CLASS weaponCl
ASSERT_OR_RETURN(0, psFeature != NULL, "Invalid feature pointer");
debug(LOG_ATTACK, "feature (id %d): body %d armour %d damage: %d",
psFeature->id, psFeature->body, psFeature->armour[weaponClass], damage);
psFeature->id, psFeature->body, psFeature->psStats->armourValue, damage);
relativeDamage = objDamage(psFeature, damage, psFeature->psStats->body, weaponClass, weaponSubClass, isDamagePerSecond);
@ -243,17 +243,10 @@ FEATURE * buildFeature(FEATURE_STATS *psStats, UDWORD x, UDWORD y,bool FromSave)
psFeature->body = psStats->body;
psFeature->periodicalDamageStart = 0;
psFeature->periodicalDamage = 0;
objSensorCache(psFeature, NULL);
objEcmCache(psFeature, NULL);
// it has never been drawn
psFeature->sDisplay.frameNumber = 0;
for (int j = 0; j < WC_NUM_WEAPON_CLASSES; j++)
{
psFeature->armour[j] = psFeature->psStats->armourValue;
}
memset(psFeature->seenThisTick, 0, sizeof(psFeature->seenThisTick));
memset(psFeature->visible, 0, sizeof(psFeature->visible));

File diff suppressed because it is too large Load Diff

View File

@ -1,66 +0,0 @@
/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2013 Warzone 2100 Project
Warzone 2100 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Warzone 2100 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
* Definitions for the Structure Functions.
*/
#ifndef __INCLUDED_SRC_FUNCTION_H__
#define __INCLUDED_SRC_FUNCTION_H__
#include "objectdef.h"
//holder for all functions
extern FUNCTION **asFunctions;
extern UDWORD numFunctions;
extern bool loadFunctionStats(const char *pFunctionData, UDWORD bufferSize);
extern void productionUpgrade(FUNCTION *pFunction, UBYTE player);
extern void researchUpgrade(FUNCTION *pFunction, UBYTE player);
extern void powerUpgrade(FUNCTION *pFunction, UBYTE player);
extern void reArmUpgrade(FUNCTION *pFunction, UBYTE player);
extern void repairFacUpgrade(FUNCTION *pFunction, UBYTE player);
extern void weaponUpgrade(FUNCTION *pFunction, UBYTE player);
extern void structureUpgrade(FUNCTION *pFunction, UBYTE player);
extern void wallDefenceUpgrade(FUNCTION *pFunction, UBYTE player);
extern void structureBodyUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding);
extern void structureArmourUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding);
extern void structureResistanceUpgrade(FUNCTION *pFunction, STRUCTURE *psBuilding);
extern void structureProductionUpgrade(STRUCTURE *psBuilding);
extern void structureResearchUpgrade(STRUCTURE *psBuilding);
extern void structurePowerUpgrade(STRUCTURE *psBuilding);
extern void structureRepairUpgrade(STRUCTURE *psBuilding);
extern void structureSensorUpgrade(STRUCTURE *psBuilding);
extern void structureReArmUpgrade(STRUCTURE *psBuilding);
extern void structureECMUpgrade(STRUCTURE *psBuilding);
extern void sensorUpgrade(FUNCTION *pFunction, UBYTE player);
extern void repairUpgrade(FUNCTION *pFunction, UBYTE player);
extern void ecmUpgrade(FUNCTION *pFunction, UBYTE player);
extern void constructorUpgrade(FUNCTION *pFunction, UBYTE player);
extern void bodyUpgrade(FUNCTION *pFunction, UBYTE player);
extern void droidSensorUpgrade(DROID *psDroid);
extern void droidECMUpgrade(DROID *psDroid);
extern void droidBodyUpgrade(FUNCTION *pFunction, DROID *psDroid);
extern void upgradeTransporterDroids(DROID *psTransporter,
void(*pUpgradeFunction)(DROID *psDroid));
extern bool FunctionShutDown(void);
#endif // __INCLUDED_SRC_FUNCTION_H__

View File

@ -1,180 +0,0 @@
/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2013 Warzone 2100 Project
Warzone 2100 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Warzone 2100 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** \file
* Definitions for functions.
*/
#ifndef __INCLUDED_FUNCTIONDEF_H__
#define __INCLUDED_FUNCTIONDEF_H__
#include "statsdef.h"
enum FUNCTION_TYPE
{
PRODUCTION_TYPE,
PRODUCTION_UPGRADE_TYPE,
RESEARCH_TYPE,
RESEARCH_UPGRADE_TYPE,
POWER_GEN_TYPE,
RESOURCE_TYPE,
REPAIR_DROID_TYPE,
WEAPON_UPGRADE_TYPE,
WALL_TYPE,
STRUCTURE_UPGRADE_TYPE,
WALLDEFENCE_UPGRADE_TYPE,
POWER_UPGRADE_TYPE,
REPAIR_UPGRADE_TYPE,
DROIDREPAIR_UPGRADE_TYPE,
DROIDECM_UPGRADE_TYPE,
DROIDBODY_UPGRADE_TYPE,
DROIDSENSOR_UPGRADE_TYPE,
DROIDCONST_UPGRADE_TYPE,
REARM_TYPE,
REARM_UPGRADE_TYPE,
/* The number of function types */
NUMFUNCTIONS,
};
/*Common stats for all Structure Functions*/
/*Common struct for all functions*/
struct FUNCTION : public BASE_STATS
{
FUNCTION_TYPE type; ///< The type of Function
};
/*To repair droids that enter the repair facility*/
struct REPAIR_DROID_FUNCTION : public FUNCTION
{
UDWORD repairPoints; /*The number of repair points used to reduce
damage to the droid. These repair points can
restore even destroyed droid components*/
};
/*To generate and supply power to other structures*/
struct POWER_GEN_FUNCTION : public FUNCTION
{
UDWORD powerOutput; /*How much power is generated per power cycle*/
UDWORD powerMultiplier; /*Multiplies the output - upgradeable*/
};
/*function used by walls to define which corner to use*/
struct WALL_FUNCTION : public FUNCTION
{
char *pStructName; //storage space for the name so can work out
//which stat when structs are loaded in
struct STRUCTURE_STATS * pCornerStat; ///< pointer to which stat to use as a corner wall
};
/*function used by Resource Extractor to indicate how much resource is available*/
struct RESOURCE_FUNCTION : public FUNCTION
{
};
/*To increase a production facilities output*/
struct PRODUCTION_UPGRADE_FUNCTION : public FUNCTION
{
UBYTE outputModifier; /*The amount added to a facility's Output*/
UBYTE factory; /*flag to indicate upgrades standard factories*/
UBYTE cyborgFactory; /*flag to indicate upgrades cyborg factories*/
UBYTE vtolFactory; /*flag to indicate upgrades vtol factories*/
};
/*To manufacture droids designed previously*/
struct PRODUCTION_FUNCTION : public FUNCTION
{
BODY_SIZE capacity; // The max size of body the factory can produce
int productionOutput; // Droid Build Points Produced Per Build Cycle
};
/*To research topics available*/
struct RESEARCH_FUNCTION : public FUNCTION
{
UDWORD researchPoints; /*The number of research points added per
research cycle*/
};
/*To rearm VTOLs*/
struct REARM_FUNCTION : public FUNCTION
{
UDWORD reArmPoints; /*The number of reArm points added per cycle*/
};
struct UPGRADE_FUNCTION : public FUNCTION
{
uint16_t upgradePoints; ///< The % to add to the action points
};
typedef UPGRADE_FUNCTION RESEARCH_UPGRADE_FUNCTION;
typedef UPGRADE_FUNCTION REPAIR_UPGRADE_FUNCTION;
typedef UPGRADE_FUNCTION POWER_UPGRADE_FUNCTION;
typedef UPGRADE_FUNCTION REARM_UPGRADE_FUNCTION;
/*Upgrade the weapon ROF and accuracy for the weapons of a particular class*/
struct WEAPON_UPGRADE_FUNCTION : public FUNCTION
{
WEAPON_SUBCLASS subClass; /*which weapons are affected */
UBYTE firePause; /*The % to decrease the fire pause or reload time */
UWORD longHit; /*The % to increase the long range accuracy */
UWORD damage; /*The % to increase the damage*/
UWORD radiusDamage; /*The % to increase the radius damage*/
UWORD periodicalDamage; /*The % to increase the periodical damage*/
UWORD radiusHit; /*The % to increase the chance to hit in blast radius*/
};
/*Upgrade the structure stats for all non wall and defence structures*/
struct STRUCTURE_UPGRADE_FUNCTION : public FUNCTION
{
UWORD armour; /*The % to increase the armour value*/
UWORD body; /*The % to increase the body points*/
UWORD resistance; /*The % to increase the resistance*/
};
/*Upgrade the structure stats for all wall and defence structures*/
struct WALLDEFENCE_UPGRADE_FUNCTION : public FUNCTION
{
UWORD armour; /*The % to increase the armour value*/
UWORD body; /*The % to increase the body points*/
};
typedef UPGRADE_FUNCTION DROIDREPAIR_UPGRADE_FUNCTION;
typedef UPGRADE_FUNCTION DROIDECM_UPGRADE_FUNCTION;
typedef UPGRADE_FUNCTION DROIDCONSTR_UPGRADE_FUNCTION;
struct DROIDBODY_UPGRADE_FUNCTION : public UPGRADE_FUNCTION
{
UWORD body; //The % to increase the whole vehicle body points by*/
UWORD armourValue[WC_NUM_WEAPON_CLASSES];
UBYTE cyborg; //flag to specify the upgrade is valid for cyborgs
UBYTE droid; /*flag to specify the upgrade is valid
for droids (non cyborgs!)*/
};
struct DROIDSENSOR_UPGRADE_FUNCTION : public UPGRADE_FUNCTION
{
UWORD range; // % to increase range by
};
#endif // __INCLUDED_FUNCTIONDEF_H__

View File

@ -4935,7 +4935,6 @@ static bool loadSaveStructure2(const char *pFileName, STRUCTURE **ppList)
break;
case REF_REARM_PAD:
psReArmPad = ((REARM_PAD *)psStructure->pFunctionality);
psReArmPad->reArmPoints = ini.value("Rearm/reArmPoints", psReArmPad->reArmPoints).toInt();
psReArmPad->timeStarted = ini.value("Rearm/timeStarted", psReArmPad->timeStarted).toInt();
psReArmPad->timeLastUpdated = ini.value("Rearm/timeLastUpdated", psReArmPad->timeLastUpdated).toInt();
break;
@ -5168,7 +5167,6 @@ bool writeStructFile(const char *pFileName)
else if (psCurr->pStructureType->type == REF_REARM_PAD)
{
REARM_PAD *psReArmPad = ((REARM_PAD *)psCurr->pFunctionality);
ini.setValue("Rearm/reArmPoints", psReArmPad->reArmPoints);
ini.setValue("Rearm/timeStarted", psReArmPad->timeStarted);
ini.setValue("Rearm/timeLastUpdated", psReArmPad->timeLastUpdated);
if (psReArmPad->psObj)

View File

@ -3199,8 +3199,7 @@ static bool intAddObjectWindow(BASE_OBJECT *psObjects, BASE_OBJECT *psSelected,
case REF_FACTORY:
case REF_CYBORG_FACTORY:
case REF_VTOL_FACTORY:
sBarInit2.size = (UWORD)((FACTORY *)Structure->
pFunctionality)->productionOutput; // Need to scale?
sBarInit2.size = getBuildingProductionPoints(Structure);
if (sBarInit2.size > WBAR_SCALE)
{
sBarInit2.size = WBAR_SCALE;
@ -3211,8 +3210,7 @@ static bool intAddObjectWindow(BASE_OBJECT *psObjects, BASE_OBJECT *psSelected,
break;
case REF_RESEARCH:
sBarInit2.size = (UWORD)((RESEARCH_FACILITY *)Structure->
pFunctionality)->researchPoints; // Need to scale?
sBarInit2.size = getBuildingResearchPoints(Structure);
if (sBarInit2.size > WBAR_SCALE)
{
sBarInit2.size = WBAR_SCALE;

View File

@ -62,7 +62,6 @@
#include "edit3d.h"
#include "structure.h"
#include "research.h"
#include "function.h"
#include "hci.h"
#include "stats.h"
#include "game.h"
@ -238,7 +237,7 @@ void intUpdateProgressBar(WIDGET *psWidget, W_CONTEXT *psContext)
{
// Started production. Set the colour of the bar to yellow.
int buildPointsTotal = FactoryGetTemplate(Manufacture)->buildPoints;
int buildRate = Manufacture->timeStartHold == 0 ? Manufacture->productionOutput : 0;
int buildRate = Manufacture->timeStartHold == 0 ? getBuildingProductionPoints(Structure) : 0;
formatTime(BarGraph, buildPointsTotal - Manufacture->buildPointsRemaining, buildPointsTotal, buildRate, _("Construction Progress"));
}
else
@ -259,7 +258,7 @@ void intUpdateProgressBar(WIDGET *psWidget, W_CONTEXT *psContext)
}
if (currentPoints != 0)
{
int researchRate = Research->timeStartHold == 0 ? Research->researchPoints : 0;
int researchRate = Research->timeStartHold == 0 ? getBuildingResearchPoints(Structure) : 0;
formatTime(BarGraph, currentPoints, Research->psSubject->researchPoints, researchRate, _("Research Progress"));
}
else

View File

@ -769,13 +769,6 @@ static void startGameLoop(void)
debug( LOG_FATAL, "Shutting down after failure" );
exit(EXIT_FAILURE);
}
//and check the structure stats are valid
if (!checkStructureStats())
{
debug( LOG_FATAL, "Invalid Structure Stats" );
debug( LOG_FATAL, "Shutting down after failure" );
exit(EXIT_FAILURE);
}
screen_StopBackDrop();

View File

@ -2732,16 +2732,9 @@ static void loadMapSettings1()
game.scavengers = ini.value("scavengers", game.scavengers).toBool();
game.base = ini.value("bases", game.base).toInt();
game.alliance = ini.value("alliances", game.alliance).toInt();
if (ini.contains("power"))
if (ini.contains("powerLevel"))
{
game.power = ini.value("power", game.power).toInt();
switch (game.power)
{
case 0 : game.power = LEV_LOW; break;
case 1 : game.power = LEV_MED; break;
default: debug(LOG_ERROR, "Illegal power level : %d", game.power); // fall through
case 2 : game.power = LEV_HI; break;
}
game.power = ini.value("powerLevel", game.power).toInt();
}
ini.endGroup();
}
@ -3772,7 +3765,7 @@ bool startMultiOptions(bool bReenter)
game.alliance = ALLIANCES_TEAMS;
netPlayersUpdated = true;
mapDownloadProgress = 100;
game.power = ini.value("Power", game.power).toInt();
game.power = ini.value("powerLevel", game.power).toInt();
game.base = ini.value("Bases", game.base + 1).toInt() - 1; // count from 1 like the humans do
sstrcpy(game.name, ini.value("name").toString().toUtf8().constData());
locked.position = ini.value("AllowPositionChange", locked.position).toBool();

View File

@ -111,9 +111,9 @@ extern UBYTE bDisplayMultiJoiningStatus; // draw load progress?
#define PING_LIMIT 4000 // If ping is bigger than this, then worry and panic, and don't even try showing the ping.
#define LEV_LOW 400 // how many points to allocate for res levels???
#define LEV_MED 700
#define LEV_HI 1000
#define LEV_LOW 0
#define LEV_MED 1
#define LEV_HI 2
#define DIFF_SLIDER_STOPS 20 //max number of stops for the multiplayer difficulty slider

View File

@ -27,7 +27,6 @@
#include "lib/framework/frame.h"
#include "lib/ivis_opengl/pietypes.h"
#include "functiondef.h"
#include "movedef.h"
#include "statsdef.h"
#include "researchdef.h"

View File

@ -32,7 +32,6 @@
#include "ai.h"
#include "move.h"
#include "function.h"
#include "stats.h"
/* Initialise the object system */

View File

@ -164,15 +164,14 @@ static void printWeaponInfo(const WEAPON_STATS* psStats)
printComponentInfo((COMPONENT_STATS *)psStats);
CONPRINTF(ConsoleString,(ConsoleString," lRng %d mRng %d %s\n"
" lHt %d pause %d dam %d\n",
proj_GetLongRange(psStats), psStats->minRange,
proj_GetLongRange(psStats, selectedPlayer), psStats->upgrade[selectedPlayer].minRange,
proj_Direct(psStats) ? "direct" : "indirect",
weaponLongHit(psStats,
(UBYTE)selectedPlayer), weaponFirePause(psStats,(UBYTE)selectedPlayer),
weaponDamage(psStats, (UBYTE)selectedPlayer)));
CONPRINTF(ConsoleString,(ConsoleString," rad %d radHt %d radDam %d\n"
weaponLongHit(psStats, selectedPlayer), weaponFirePause(psStats, selectedPlayer),
weaponDamage(psStats, selectedPlayer)));
CONPRINTF(ConsoleString,(ConsoleString," rad %d radDam %d\n"
" inTime %d inDam %d inRad %d\n",
psStats->radius, psStats->radiusHit, psStats->radiusDamage,
psStats->periodicalDamageTime, psStats->periodicalDamage, psStats->periodicalDamageRadius));
psStats->upgrade[selectedPlayer].radius, psStats->upgrade[selectedPlayer].radiusDamage,
psStats->upgrade[selectedPlayer].periodicalDamageTime, psStats->upgrade[selectedPlayer].periodicalDamage, psStats->upgrade[selectedPlayer].periodicalDamageRadius));
CONPRINTF(ConsoleString,(ConsoleString," flSpd %d %s\n",
psStats->flightSpeed, psStats->fireOnMove ? "fireOnMove" : "not fireOnMove"));
CONPRINTF(ConsoleString,(ConsoleString," %s %s %s\n", pWC, pWSC, pMM));
@ -197,7 +196,7 @@ void printDroidInfo(const DROID* psDroid)
printBaseObjInfo((BASE_OBJECT *)psDroid);
CONPRINTF(ConsoleString,(ConsoleString," wt %d bSpeed %d sRng %d ECM %d bdy %d\n",
psDroid->weight, psDroid->baseSpeed, droidSensorRange(psDroid), droidConcealment(psDroid), psDroid->body));
psDroid->weight, psDroid->baseSpeed, droidSensorRange(psDroid), droidJammerPower(psDroid), psDroid->body));
if (psDroid->asWeaps[0].nStat > 0)
{

View File

@ -54,7 +54,7 @@
bool powerCalculated;
/* Updates the current power based on the extracted power and a Power Generator*/
static void updateCurrentPower(POWER_GEN *psPowerGen, UDWORD player, int ticks);
static void updateCurrentPower(STRUCTURE *psStruct, UDWORD player, int ticks);
static int64_t updateExtractedPower(STRUCTURE *psBuilding);
//returns the relevant list based on OffWorld or OnWorld
@ -276,7 +276,7 @@ void updatePlayerPower(int player, int ticks)
{
if (psStruct->pStructureType->type == REF_POWER_GEN && psStruct->status == SS_BUILT)
{
updateCurrentPower((POWER_GEN *)psStruct->pFunctionality, player, ticks);
updateCurrentPower(psStruct, player, ticks);
}
}
syncDebug("updatePlayerPower%u %"PRId64"->%"PRId64"", player, powerBefore, asPower[player].currentPower);
@ -285,8 +285,9 @@ void updatePlayerPower(int player, int ticks)
}
/* Updates the current power based on the extracted power and a Power Generator*/
static void updateCurrentPower(POWER_GEN *psPowerGen, UDWORD player, int ticks)
static void updateCurrentPower(STRUCTURE *psStruct, UDWORD player, int ticks)
{
POWER_GEN *psPowerGen = (POWER_GEN *)psStruct->pFunctionality;
int i;
int64_t extractedPower;
@ -310,9 +311,10 @@ static void updateCurrentPower(POWER_GEN *psPowerGen, UDWORD player, int ticks)
}
}
syncDebug("updateCurrentPower%d = %"PRId64",%u", player, extractedPower, psPowerGen->multiplier);
int multiplier = getBuildingPowerPoints(psStruct);
syncDebug("updateCurrentPower%d = %"PRId64",%u", player, extractedPower, multiplier);
asPower[player].currentPower += (extractedPower * psPowerGen->multiplier) / 100 * ticks;
asPower[player].currentPower += (extractedPower * multiplier) / 100 * ticks;
ASSERT(asPower[player].currentPower >= 0, "negative power");
if (asPower[player].currentPower > MAX_POWER*FP_ONE)
{

View File

@ -891,8 +891,9 @@ static void proj_InFlightFunc(PROJECTILE *psProj)
return;
}
if (currentDistance*100u >= psStats->longRange * psStats->distanceExtensionFactor) // We've travelled our maximum range.
if (currentDistance*100u >= psStats->upgrade[psProj->player].maxRange * psStats->distanceExtensionFactor)
{
// We've travelled our maximum range.
psProj->state = PROJ_IMPACT;
setProjectileDestination(psProj, NULL); /* miss registered if NULL target */
return;
@ -910,14 +911,14 @@ static void proj_InFlightFunc(PROJECTILE *psProj)
{
case WSC_FLAME:
posFlip.z -= 8; // Why?
effectGiveAuxVar(PERCENT(currentDistance, psStats->longRange));
effectGiveAuxVar(PERCENT(currentDistance, psStats->upgrade[psProj->player].maxRange));
addEffect(&posFlip, EFFECT_EXPLOSION, EXPLOSION_TYPE_FLAMETHROWER, false, NULL, 0, effectTime);
break;
case WSC_COMMAND:
case WSC_ELECTRONIC:
case WSC_EMP:
posFlip.z -= 8; // Why?
effectGiveAuxVar(PERCENT(currentDistance, psStats->longRange)/2);
effectGiveAuxVar(PERCENT(currentDistance, psStats->upgrade[psProj->player].maxRange)/2);
addEffect(&posFlip, EFFECT_EXPLOSION, EXPLOSION_TYPE_LASER, false, NULL, 0, effectTime);
break;
case WSC_ROCKET:
@ -979,13 +980,13 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
}
/* Shouldn't need to do this check but the stats aren't all at a value yet... */ // FIXME
if (psStats->periodicalDamageRadius && psStats->periodicalDamageTime)
if (psStats->upgrade[psObj->player].periodicalDamageRadius != 0 && psStats->upgrade[psObj->player].periodicalDamageTime != 0)
{
position.x = psObj->pos.x;
position.z = psObj->pos.y; // z = y [sic] intentional
position.y = map_Height(position.x, position.z);
effectGiveAuxVar(psStats->periodicalDamageRadius);
effectGiveAuxVarSec(psStats->periodicalDamageTime);
effectGiveAuxVar(psStats->upgrade[psObj->player].periodicalDamageRadius);
effectGiveAuxVarSec(psStats->upgrade[psObj->player].periodicalDamageTime);
addEffect(&position, EFFECT_FIRE, FIRE_TYPE_LOCALISED, false, NULL, 0, psObj->time);
}
@ -1003,18 +1004,18 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
}
}
if (psStats->periodicalDamageRadius != 0 && psStats->periodicalDamageTime != 0)
if (psStats->upgrade[psObj->player].periodicalDamageRadius && psStats->upgrade[psObj->player].periodicalDamageTime)
{
tileSetFire(psObj->pos.x, psObj->pos.y, psStats->periodicalDamageTime);
tileSetFire(psObj->pos.x, psObj->pos.y, psStats->upgrade[psObj->player].periodicalDamageTime);
}
// Set the effects position and radius
position.x = psObj->pos.x;
position.z = psObj->pos.y; // z = y [sic] intentional
position.y = psObj->pos.z; // y = z [sic] intentional
scatter.x = psStats->radius;
scatter.x = psStats->upgrade[psObj->player].radius;
scatter.y = 0;
scatter.z = psStats->radius;
scatter.z = psStats->upgrade[psObj->player].radius;
// If the projectile missed its target (or the target died)
if (psObj->psDest == NULL)
@ -1142,13 +1143,13 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
setProjectileDestination(psObj, temp);
// If the projectile does no splash damage and does not set fire to things
if ((psStats->radius == 0) && (psStats->periodicalDamageTime == 0) )
if (psStats->upgrade[psObj->player].radius == 0 && psStats->upgrade[psObj->player].periodicalDamageTime == 0)
{
psObj->state = PROJ_INACTIVE;
return;
}
if (psStats->radius != 0)
if (psStats->upgrade[psObj->player].radius != 0)
{
/* An area effect bullet */
psObj->state = PROJ_POSTIMPACT;
@ -1157,7 +1158,7 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
psObj->born = gameTime;
static GridList gridList; // static to avoid allocations.
gridList = gridStartIterate(psObj->pos.x, psObj->pos.y, psStats->radius);
gridList = gridStartIterate(psObj->pos.x, psObj->pos.y, psStats->upgrade[psObj->player].radius);
for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi)
{
BASE_OBJECT *psCurr = *gi;
@ -1197,15 +1198,10 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
{
continue; // Target in air, and can't shoot at air, or target on ground, and can't shoot at ground.
}
if (useSphere && !Vector3i_InSphere(psCurr->pos, psObj->pos, psStats->radius))
if (useSphere && !Vector3i_InSphere(psCurr->pos, psObj->pos, psStats->upgrade[psObj->player].radius))
{
continue; // Target out of range.
}
unsigned hitProbability = weaponRadiusHit(psStats, psObj->player);
if (hitProbability < 100u && hitProbability <= gameRand(100)) // Avoid unneeded gameRand(100) calls when probability is 100%.
{
continue; // Target was lucky, and the tank or structure somehow managed to dodge the explosion.
}
// The psCurr will get damaged, at this point.
unsigned damage = calcDamage(weaponRadDamage(psStats, psObj->player), psStats->weaponEffect, psCurr);
debug(LOG_ATTACK, "Damage to object %d, player %d : %u", psCurr->id, psCurr->player, damage);
@ -1218,7 +1214,7 @@ static void proj_ImpactFunc( PROJECTILE *psObj )
}
}
if (psStats->periodicalDamageTime != 0)
if (psStats->upgrade[psObj->player].periodicalDamageTime != 0)
{
/* Periodical damage round */
/* Periodical damage gets done in the bullet update routine */
@ -1242,14 +1238,14 @@ static void proj_PostImpactFunc( PROJECTILE *psObj )
int age = gameTime - psObj->born;
/* Time to finish postimpact effect? */
if (age > (SDWORD)psStats->radiusLife && age > (SDWORD)psStats->periodicalDamageTime)
if (age > psStats->radiusLife && age > psStats->upgrade[psObj->player].periodicalDamageTime)
{
psObj->state = PROJ_INACTIVE;
return;
}
/* Periodical damage effect */
if (psStats->periodicalDamageTime > 0)
if (psStats->upgrade[psObj->player].periodicalDamageTime > 0)
{
/* See if anything is in the fire and damage it periodically */
proj_checkPeriodicalDamage(psObj);
@ -1343,7 +1339,7 @@ static void proj_checkPeriodicalDamage(PROJECTILE *psProj)
WEAPON_STATS *psStats = psProj->psWStats;
static GridList gridList; // static to avoid allocations.
gridList = gridStartIterate(psProj->pos.x, psProj->pos.y, psStats->periodicalDamageRadius);
gridList = gridStartIterate(psProj->pos.x, psProj->pos.y, psStats->upgrade[psProj->player].periodicalDamageRadius);
for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi)
{
BASE_OBJECT *psCurr = *gi;
@ -1405,9 +1401,9 @@ bool proj_Direct(const WEAPON_STATS* psStats)
/***************************************************************************/
// return the maximum range for a weapon
SDWORD proj_GetLongRange(const WEAPON_STATS* psStats)
int proj_GetLongRange(const WEAPON_STATS *psStats, int player)
{
return psStats->longRange;
return psStats->upgrade[player].maxRange;
}

View File

@ -71,7 +71,7 @@ bool proj_SendProjectileAngled(WEAPON *psWeap, SIMPLE_OBJECT *psAttacker, int pl
bool proj_Direct(const WEAPON_STATS* psStats);
/** Return the maximum range for a weapon. */
SDWORD proj_GetLongRange(const WEAPON_STATS* psStats);
int proj_GetLongRange(const WEAPON_STATS* psStats, int player);
extern UDWORD calcDamage(UDWORD baseDamage, WEAPON_EFFECT weaponEffect, BASE_OBJECT *psTarget);
extern bool gfxVisible(PROJECTILE *psObj);

View File

@ -552,6 +552,8 @@ QScriptEngine *loadPlayerScript(QString path, int player, int difficulty)
engine->globalObject().setProperty("scavengerPlayer", scavengerPlayer(), QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[isMultiplayer] If the current game is a online multiplayer game or not. (3.2+ only)
engine->globalObject().setProperty("isMultiplayer", NetPlay.bComms, QScriptValue::ReadOnly | QScriptValue::Undeletable);
// un-documented placeholder variable
engine->globalObject().setProperty("isReceivingAllEvents", false, QScriptValue::ReadOnly | QScriptValue::Undeletable);
// Regular functions
QFileInfo basename(path);
@ -902,7 +904,8 @@ bool triggerEvent(SCRIPT_TRIGGER_TYPE trigger, BASE_OBJECT *psObj)
if (psObj)
{
int player = engine->globalObject().property("me").toInt32();
if (player != psObj->player && player != -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (player != psObj->player && !receiveAll)
{
continue;
}
@ -1013,7 +1016,8 @@ bool triggerEventDroidBuilt(DROID *psDroid, STRUCTURE *psFactory)
{
QScriptEngine *engine = scripts.at(i);
int player = engine->globalObject().property("me").toInt32();
if (player == psDroid->player || player == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (player == psDroid->player || receiveAll)
{
QScriptValueList args;
args += convDroid(psDroid, engine);
@ -1037,7 +1041,8 @@ bool triggerEventStructBuilt(STRUCTURE *psStruct, DROID *psDroid)
{
QScriptEngine *engine = scripts.at(i);
int player = engine->globalObject().property("me").toInt32();
if (player == psStruct->player || player == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (player == psStruct->player || receiveAll)
{
QScriptValueList args;
args += convStructure(psStruct, engine);
@ -1061,7 +1066,8 @@ bool triggerEventStructureReady(STRUCTURE *psStruct)
{
QScriptEngine *engine = scripts.at(i);
int player = engine->globalObject().property("me").toInt32();
if (player == psStruct->player || player == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (player == psStruct->player || receiveAll)
{
QScriptValueList args;
args += convStructure(psStruct, engine);
@ -1107,13 +1113,15 @@ bool triggerEventAttacked(BASE_OBJECT *psVictim, BASE_OBJECT *psAttacker, int la
//__ parameter is set if the research comes from a research lab owned by the
//__ current player. If an ally does the research, the structure parameter will
//__ be set to null. The player parameter gives the player it is called for.
bool triggerEventResearched(RESEARCH *psResearch, STRUCTURE *psStruct, int player)
// trigger - to prevent spam to AI scripts from loading games
bool triggerEventResearched(RESEARCH *psResearch, STRUCTURE *psStruct, int player, bool trigger)
{
for (int i = 0; i < scripts.size() && psStruct; ++i)
for (int i = 0; i < scripts.size(); ++i)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == player || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if ((me == player && trigger) || receiveAll)
{
QScriptValueList args;
args += convResearch(psResearch, engine, player);
@ -1174,7 +1182,8 @@ bool triggerEventSeen(BASE_OBJECT *psViewer, BASE_OBJECT *psSeen)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == psViewer->player || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (me == psViewer->player || receiveAll)
{
QScriptValueList args;
args += convMax(psViewer, engine);
@ -1196,7 +1205,8 @@ bool triggerEventObjectTransfer(BASE_OBJECT *psObj, int from)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == psObj->player || me == from || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (me == psObj->player || me == from || receiveAll)
{
QScriptValueList args;
args += convMax(psObj, engine);
@ -1217,13 +1227,15 @@ bool triggerEventChat(int from, int to, const char *message)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == to || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (me == to || (receiveAll && to == from))
{
QScriptValueList args;
args += QScriptValue(from);
args += QScriptValue(to);
args += QScriptValue(message);
callFunction(engine, "eventChat", args);
break; // only call once
}
}
return true;
@ -1239,7 +1251,8 @@ bool triggerEventBeacon(int from, int to, const char *message, int x, int y)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == to || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (me == to || receiveAll)
{
QScriptValueList args;
args += QScriptValue(map_coord(x));
@ -1265,7 +1278,8 @@ bool triggerEventBeaconRemoved(int from, int to)
{
QScriptEngine *engine = scripts.at(i);
int me = engine->globalObject().property("me").toInt32();
if (me == to || me == -1)
bool receiveAll = engine->globalObject().property("isReceivingAllEvents").toBool();
if (me == to || receiveAll)
{
QScriptValueList args;
args += QScriptValue(from);

View File

@ -97,7 +97,7 @@ bool triggerEvent(SCRIPT_TRIGGER_TYPE trigger, BASE_OBJECT *psObj = NULL);
// For each trigger with function parameters, a function to trigger it here
bool triggerEventDroidBuilt(DROID *psDroid, STRUCTURE *psFactory);
bool triggerEventAttacked(BASE_OBJECT *psVictim, BASE_OBJECT *psAttacker, int lastHit);
bool triggerEventResearched(RESEARCH *psResearch, STRUCTURE *psStruct, int player);
bool triggerEventResearched(RESEARCH *psResearch, STRUCTURE *psStruct, int player, bool trigger);
bool triggerEventStructBuilt(STRUCTURE *psStruct, DROID *psDroid);
bool triggerEventDroidIdle(DROID *psDroid);
bool triggerEventDestroyed(BASE_OBJECT *psVictim);

View File

@ -34,6 +34,7 @@
#include <QtGui/QStandardItemModel>
#include "action.h"
#include "combat.h"
#include "console.h"
#include "design.h"
#include "display3d.h"
@ -68,6 +69,16 @@
#define ALLIES -2
#define ENEMIES -3
#define SCRCB_RES (COMP_NUMCOMPONENTS + 0)
#define SCRCB_REP (COMP_NUMCOMPONENTS + 1)
#define SCRCB_POW (COMP_NUMCOMPONENTS + 2)
#define SCRCB_CON (COMP_NUMCOMPONENTS + 3)
#define SCRCB_REA (COMP_NUMCOMPONENTS + 4)
#define SCRCB_ARM (COMP_NUMCOMPONENTS + 5)
#define SCRCB_HEA (COMP_NUMCOMPONENTS + 6)
#define SCRCB_ELW (COMP_NUMCOMPONENTS + 7)
#define SCRCB_HIT (COMP_NUMCOMPONENTS + 8)
// TODO, move this stuff into a script common subsystem
#include "scriptfuncs.h"
extern bool structDoubleCheck(BASE_STATS *psStat,UDWORD xx,UDWORD yy, SDWORD maxBlockingTiles);
@ -300,6 +311,12 @@ QScriptValue convResearch(RESEARCH *psResearch, QScriptEngine *engine, int playe
value.setProperty("name", psResearch->pName); // will be changed to contain fullname
value.setProperty("id", psResearch->pName);
value.setProperty("type", SCRIPT_RESEARCH);
QScriptValue results = engine->newArray(psResearch->resultStrings.size());
for (int i = 0; i < psResearch->resultStrings.size(); i++)
{
results.setProperty(i, psResearch->resultStrings[i]);
}
value.setProperty("results", results);
return value;
}
@ -337,7 +354,7 @@ QScriptValue convStructure(STRUCTURE *psStruct, QScriptEngine *engine)
aa = aa || psWeap->surfaceToAir & SHOOT_IN_AIR;
ga = ga || psWeap->surfaceToAir & SHOOT_ON_GROUND;
indirect = indirect || psWeap->movementModel == MM_INDIRECT || psWeap->movementModel == MM_HOMINGINDIRECT;
range = MAX((int)psWeap->longRange, range);
range = MAX((int)psWeap->upgrade[psStruct->player].maxRange, range);
}
}
QScriptValue value = convObj(psStruct, engine);
@ -493,7 +510,7 @@ QScriptValue convDroid(DROID *psDroid, QScriptEngine *engine)
aa = aa || psWeap->surfaceToAir & SHOOT_IN_AIR;
ga = ga || psWeap->surfaceToAir & SHOOT_ON_GROUND;
indirect = indirect || psWeap->movementModel == MM_INDIRECT || psWeap->movementModel == MM_HOMINGINDIRECT;
range = MAX((int)psWeap->longRange, range);
range = MAX((int)psWeap->upgrade[psDroid->player].maxRange, range);
}
}
DROID_TYPE type = psDroid->droidType;
@ -585,8 +602,8 @@ QScriptValue convObj(BASE_OBJECT *psObj, QScriptEngine *engine)
value.setProperty("y", map_coord(psObj->pos.y), QScriptValue::ReadOnly);
value.setProperty("z", map_coord(psObj->pos.z), QScriptValue::ReadOnly);
value.setProperty("player", psObj->player, QScriptValue::ReadOnly);
value.setProperty("armour", psObj->armour[WC_KINETIC], QScriptValue::ReadOnly);
value.setProperty("thermal", psObj->armour[WC_HEAT], QScriptValue::ReadOnly);
value.setProperty("armour", objArmour(psObj, WC_KINETIC), QScriptValue::ReadOnly);
value.setProperty("thermal", objArmour(psObj, WC_HEAT), QScriptValue::ReadOnly);
value.setProperty("type", psObj->type, QScriptValue::ReadOnly);
value.setProperty("selected", psObj->selected, QScriptValue::ReadOnly);
value.setProperty("name", objInfo(psObj), QScriptValue::ReadOnly);
@ -836,8 +853,7 @@ bool writeLabels(const char *filename)
// All script functions should be prefixed with "js_" then followed by same name as in script.
//-- \subsection{getWeaponInfo(weapon id)}
//-- Return information about a particular weapon type.
// TODO, add more and document
//-- Return information about a particular weapon type. DEPRECATED - query the Stats object instead.
static QScriptValue js_getWeaponInfo(QScriptContext *context, QScriptEngine *engine)
{
QString id = context->argument(0).toString();
@ -848,8 +864,8 @@ static QScriptValue js_getWeaponInfo(QScriptContext *context, QScriptEngine *eng
info.setProperty("id", id);
info.setProperty("name", getStatName(psStats));
info.setProperty("impactClass", psStats->weaponClass == WC_KINETIC ? "KINETIC" : "HEAT");
info.setProperty("damage", psStats->damage);
info.setProperty("firePause", psStats->firePause);
info.setProperty("damage", psStats->base.damage);
info.setProperty("firePause", psStats->base.firePause);
info.setProperty("fireOnMove", psStats->fireOnMove);
return QScriptValue(info);
}
@ -2895,10 +2911,23 @@ static QScriptValue js_hackGetObj(QScriptContext *context, QScriptEngine *engine
static QScriptValue js_hackChangeMe(QScriptContext *context, QScriptEngine *engine)
{
int me = context->argument(0).toInt32();
SCRIPT_ASSERT_PLAYER(context, me);
engine->globalObject().setProperty("me", me);
return QScriptValue();
}
//-- \subsection{receiveAllEvents(bool)}
//-- Make the current script receive all events, even those not meant for 'me'.
static QScriptValue js_receiveAllEvents(QScriptContext *context, QScriptEngine *engine)
{
if (context->argumentCount() > 0)
{
bool value = context->argument(0).toBool();
engine->globalObject().setProperty("isReceivingAllEvents", value, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
return engine->globalObject().property("isReceivingAllEvents");
}
//-- \subsection{hackAssert(condition, message...)}
//-- Function to perform unit testing. It will throw a script error and a game assert.
static QScriptValue js_hackAssert(QScriptContext *context, QScriptEngine *engine)
@ -3474,8 +3503,6 @@ static QScriptValue js_getDroidProduction(QScriptContext *context, QScriptEngine
droidSetBits(psTemp, psDroid);
psDroid->weight = calcDroidWeight(psTemp);
psDroid->baseSpeed = calcDroidBaseSpeed(psTemp, psDroid->weight, player);
objSensorCache((BASE_OBJECT *)psDroid, asSensorStats + psTemp->asParts[COMP_SENSOR]);
objEcmCache((BASE_OBJECT *)psDroid, asECMStats + psTemp->asParts[COMP_ECM]);
return convDroid(psDroid, engine);
}
@ -3838,6 +3865,237 @@ void prepareLabels()
updateLabelModel();
}
static void droidBodyUpgrade(DROID *psDroid)
{
BODY_STATS *psStats = getBodyStats(psDroid);
int increase = psStats->upgrade[psDroid->player].body;
int prevBaseBody = psDroid->originalBody;
int base = calcDroidBaseBody(psDroid);
int newBaseBody = base + (base * increase) / 100;
if (newBaseBody > prevBaseBody)
{
psDroid->body = (psDroid->body * newBaseBody) / prevBaseBody;
psDroid->originalBody = newBaseBody;
}
//if a transporter droid then need to upgrade the contents
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
for (DROID *psCurr = psDroid->psGroup->psList; psCurr != NULL; psCurr = psCurr->psGrpNext)
{
if (psCurr != psDroid)
{
droidBodyUpgrade(psCurr);
}
}
}
}
QScriptValue js_stats(QScriptContext *context, QScriptEngine *engine)
{
QScriptValue callee = context->callee();
int type = callee.property("type").toInt32();
int player = callee.property("player").toInt32();
int index = callee.property("index").toInt32();
QString name = callee.property("name").toString();
if (context->argumentCount() == 1) // setter
{
int value = context->argument(0).toInt32();
if (type == COMP_BODY)
{
BODY_STATS *psStats = asBodyStats + index;
if (name == "HitPoints")
{
// Update body points for all droids, to avoid making them damaged
// FIXME -- this is _really_ slow! we could be updating dozens of bodies!
psStats->upgrade[player].body = value;
for (DROID *psDroid = apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(psDroid);
}
for (DROID *psDroid = mission.apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(psDroid);
}
for (DROID *psDroid = apsLimboDroids[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(psDroid);
}
}
else if (name == "Armour")
{
psStats->upgrade[player].armour = value;
}
else if (name == "Thermal")
{
psStats->upgrade[player].thermal = value;
}
else if (name == "Power")
{
psStats->upgrade[player].power = value;
}
else if (name == "Resistance")
{
psStats->upgrade[player].resistance = value;
}
else
{
SCRIPT_ASSERT(context, false, "Upgrade component %s not found", name.toUtf8().constData());
}
}
else if (type == COMP_SENSOR)
{
SENSOR_STATS *psStats = asSensorStats + index;
SCRIPT_ASSERT(context, name == "Range", "Invalid sensor parameter");
psStats->upgrade[player].range = value;
}
else if (type == COMP_ECM)
{
ECM_STATS *psStats = asECMStats + index;
SCRIPT_ASSERT(context, name == "Range", "Invalid ECM parameter");
psStats->upgrade[player].range = value;
}
else if (type == COMP_CONSTRUCT)
{
CONSTRUCT_STATS *psStats = asConstructStats + index;
SCRIPT_ASSERT(context, name == "ConstructorPoints", "Invalid constructor parameter");
psStats->upgrade[player].constructPoints = value;
}
else if (type == COMP_WEAPON)
{
WEAPON_STATS *psStats = asWeaponStats + index;
if (name == "MaxRange") psStats->upgrade[player].maxRange = value;
else if (name == "MinRange") psStats->upgrade[player].minRange = value;
else if (name == "HitChance") psStats->upgrade[player].hitChance = value;
else if (name == "FirePause") psStats->upgrade[player].firePause = value;
else if (name == "Rounds") psStats->upgrade[player].numRounds = value;
else if (name == "ReloadTime") psStats->upgrade[player].reloadTime = value;
else if (name == "Damage") psStats->upgrade[player].damage = value;
else if (name == "Radius") psStats->upgrade[player].radius = value;
else if (name == "RadiusDamage") psStats->upgrade[player].radiusDamage = value;
else if (name == "RepeatDamage") psStats->upgrade[player].periodicalDamage = value;
else if (name == "RepeatTime") psStats->upgrade[player].periodicalDamageTime = value;
else if (name == "RepeatRadius") psStats->upgrade[player].periodicalDamageRadius = value;
else SCRIPT_ASSERT(context, false, "Invalid weapon method");
}
else if (type == SCRCB_RES || type == SCRCB_REP || type == SCRCB_POW || type == SCRCB_CON || type == SCRCB_REA
|| type == SCRCB_HIT || type == SCRCB_ELW || type == SCRCB_ARM || type == SCRCB_HEA)
{
STRUCTURE_STATS *psStats = asStructureStats + index;
switch (type)
{
case SCRCB_RES: psStats->upgrade[player].research = value; break;
case SCRCB_REP: psStats->upgrade[player].repair = value; break;
case SCRCB_POW: psStats->upgrade[player].power = value; break;
case SCRCB_CON: psStats->upgrade[player].production = value; break;
case SCRCB_REA: psStats->upgrade[player].rearm = value; break;
case SCRCB_ELW: psStats->upgrade[player].resistance = value; break;
case SCRCB_HEA: psStats->upgrade[player].thermal = value; break;
case SCRCB_ARM: psStats->upgrade[player].armour = value; break;
case SCRCB_HIT:
// Update body points for all structures, to avoid making them damaged
// FIXME - this is _really_ slow! we could be doing this for
// dozens of buildings one at a time!
for (STRUCTURE *psCurr = apsStructLists[player]; psCurr; psCurr = psCurr->psNext)
{
if (psStats == psCurr->pStructureType && psStats->upgrade[player].hitpoints < value)
{
psCurr->body = (psCurr->body * value) / psStats->upgrade[player].hitpoints;
}
}
for (STRUCTURE *psCurr = mission.apsStructLists[player]; psCurr; psCurr = psCurr->psNext)
{
if (psStats == psCurr->pStructureType && psStats->upgrade[player].hitpoints < value)
{
psCurr->body = (psCurr->body * value) / psStats->upgrade[player].hitpoints;
}
}
psStats->upgrade[player].hitpoints = value;
break;
}
}
else
{
SCRIPT_ASSERT(context, false, "Component type not found for upgrade");
}
}
// Now read value and return it
if (type == COMP_BODY)
{
BODY_STATS *psStats = asBodyStats + index;
if (name == "HitPoints") return psStats->upgrade[player].body;
else if (name == "Armour") return psStats->upgrade[player].armour;
else if (name == "Thermal") return psStats->upgrade[player].thermal;
else if (name == "Power") return psStats->upgrade[player].power;
else if (name == "Resistance") return psStats->upgrade[player].resistance;
else SCRIPT_ASSERT(context, false, "Upgrade component %s not found", name.toUtf8().constData());
}
else if (type == COMP_SENSOR)
{
SENSOR_STATS *psStats = asSensorStats + index;
SCRIPT_ASSERT(context, name == "Range", "Invalid sensor parameter");
return psStats->upgrade[player].range;
}
else if (type == COMP_ECM)
{
ECM_STATS *psStats = asECMStats + index;
SCRIPT_ASSERT(context, name == "Range", "Invalid ECM parameter");
return psStats->upgrade[player].range;
}
else if (type == COMP_CONSTRUCT)
{
CONSTRUCT_STATS *psStats = asConstructStats + index;
SCRIPT_ASSERT(context, name == "ConstructorPoints", "Invalid constructor parameter");
return psStats->upgrade[player].constructPoints;
}
else if (type == COMP_WEAPON)
{
WEAPON_STATS *psStats = asWeaponStats + index;
if (name == "MaxRange") return psStats->upgrade[player].maxRange;
else if (name == "MinRange") return psStats->upgrade[player].minRange;
else if (name == "HitChance") return psStats->upgrade[player].hitChance;
else if (name == "FirePause") return psStats->upgrade[player].firePause;
else if (name == "Rounds") return psStats->upgrade[player].numRounds;
else if (name == "ReloadTime") return psStats->upgrade[player].reloadTime;
else if (name == "Damage") return psStats->upgrade[player].damage;
else if (name == "Radius") return psStats->upgrade[player].radius;
else if (name == "RadiusDamage") return psStats->upgrade[player].radiusDamage;
else if (name == "RepeatDamage") return psStats->upgrade[player].periodicalDamage;
else if (name == "RepeatTime") return psStats->upgrade[player].periodicalDamageTime;
else if (name == "RepeatRadius") return psStats->upgrade[player].periodicalDamageRadius;
else SCRIPT_ASSERT(context, false, "Invalid weapon method");
}
else if (type == SCRCB_RES || type == SCRCB_REP || type == SCRCB_POW || type == SCRCB_CON || type == SCRCB_REA
|| type == SCRCB_HIT || type == SCRCB_ELW || type == SCRCB_ARM || type == SCRCB_HEA)
{
STRUCTURE_STATS *psStats = asStructureStats + index;
switch (type)
{
case SCRCB_RES: return psStats->upgrade[player].research; break;
case SCRCB_REP: return psStats->upgrade[player].repair; break;
case SCRCB_POW: return psStats->upgrade[player].power; break;
case SCRCB_CON: return psStats->upgrade[player].production; break;
case SCRCB_REA: return psStats->upgrade[player].rearm; break;
case SCRCB_ELW: return psStats->upgrade[player].resistance; break;
case SCRCB_HEA: return psStats->upgrade[player].thermal; break;
case SCRCB_ARM: return psStats->upgrade[player].armour; break;
case SCRCB_HIT: return psStats->upgrade[player].hitpoints;
default: SCRIPT_ASSERT(context, false, "Component type not found for upgrade"); break;
}
}
return QScriptValue::NullValue;
}
static void setStatsFunc(QScriptValue &base, QScriptEngine *engine, QString name, int player, int type, int index, int value)
{
QScriptValue v = engine->newFunction(js_stats);
base.setProperty(name, v, QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
v.setProperty("player", player, QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly | QScriptValue::Undeletable);
v.setProperty("type", type, QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly | QScriptValue::Undeletable);
v.setProperty("index", index, QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly | QScriptValue::Undeletable);
v.setProperty("name", name, QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
bool registerFunctions(QScriptEngine *engine, QString scriptName)
{
debug(LOG_WZ, "Loading functions for engine %p, script %s", engine, scriptName.toUtf8().constData());
@ -3846,6 +4104,280 @@ bool registerFunctions(QScriptEngine *engine, QString scriptName)
GROUPMAP *psMap = new GROUPMAP;
groups.insert(engine, psMap);
/// Register 'Stats' object. It is a read-only representation of basic game component states.
//== \item[Stats] A sparse, read-only array containing rules information for game entity types.
//== (For now only the highest level member attributes are documented here. Use the 'jsdebug' cheat
//== to see them all.)
//== These values are defined:
//== \begin{description}
QScriptValue stats = engine->newObject();
{
//== \item[Body] Droid bodies
QScriptValue bodybase = engine->newObject();
for (int j = 0; j < numBodyStats; j++)
{
BODY_STATS *psStats = asBodyStats + j;
QScriptValue body = engine->newObject();
body.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("HitPoints", psStats->body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Power", psStats->base.power, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Armour", psStats->base.armour, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Thermal", psStats->base.thermal, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Resistance", psStats->base.resistance, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("Size", psStats->size, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("WeaponSlots", psStats->weaponSlots, QScriptValue::ReadOnly | QScriptValue::Undeletable);
body.setProperty("BodyClass", psStats->bodyClass, QScriptValue::ReadOnly | QScriptValue::Undeletable);
bodybase.setProperty(getStatName(psStats), body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Body", bodybase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Sensor] Sensor turrets
QScriptValue sensorbase = engine->newObject();
for (int j = 0; j < numSensorStats; j++)
{
SENSOR_STATS *psStats = asSensorStats + j;
QScriptValue sensor = engine->newObject();
sensor.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensor.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensor.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensor.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensor.setProperty("HitPoints", psStats->body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensor.setProperty("Range", psStats->base.range, QScriptValue::ReadOnly | QScriptValue::Undeletable);
sensorbase.setProperty(getStatName(psStats), sensor, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Sensor", sensorbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[ECM] ECM (Electronic Counter-Measure) turrets
QScriptValue ecmbase = engine->newObject();
for (int j = 0; j < numECMStats; j++)
{
ECM_STATS *psStats = asECMStats + j;
QScriptValue ecm = engine->newObject();
ecm.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecm.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecm.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecm.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecm.setProperty("HitPoints", psStats->body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecm.setProperty("Range", psStats->base.range, QScriptValue::ReadOnly | QScriptValue::Undeletable);
ecmbase.setProperty(getStatName(psStats), ecm, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("ECM", ecmbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Repair] Repair turrets (not used, incidentially, for repair centers)
QScriptValue repairbase = engine->newObject();
for (int j = 0; j < numRepairStats; j++)
{
REPAIR_STATS *psStats = asRepairStats + j;
QScriptValue repair = engine->newObject();
repair.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repair.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repair.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repair.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repair.setProperty("HitPoints", psStats->body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repair.setProperty("RepairPoints", psStats->base.repairPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
repairbase.setProperty(getStatName(psStats), repair, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Repair", repairbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Construct] Constructor turrets (eg for trucks)
QScriptValue conbase = engine->newObject();
for (int j = 0; j < numConstructStats; j++)
{
CONSTRUCT_STATS *psStats = asConstructStats + j;
QScriptValue con = engine->newObject();
con.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
con.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
con.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
con.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
con.setProperty("HitPoints", psStats->body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
con.setProperty("ConstructorPoints", psStats->base.constructPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
conbase.setProperty(getStatName(psStats), con, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Construct", conbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Weapon] Weapon turrets
QScriptValue wbase = engine->newObject();
for (int j = 0; j < numWeaponStats; j++)
{
WEAPON_STATS *psStats = asWeaponStats + j;
QScriptValue weap = engine->newObject();
weap.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Weight", psStats->weight, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("BuildPower", psStats->buildPower, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("BuildTime", psStats->buildPoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("MaxRange", psStats->base.maxRange, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("MinRange", psStats->base.minRange, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("HitChance", psStats->base.hitChance, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("FirePause", psStats->base.firePause, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("ReloadTime", psStats->base.reloadTime, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Rounds", psStats->base.numRounds, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Damage", psStats->base.damage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RadiusDamage", psStats->base.radiusDamage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatDamage", psStats->base.periodicalDamage, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatRadius", psStats->base.periodicalDamageRadius, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatTime", psStats->base.periodicalDamageTime, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("Radius", psStats->base.radius, QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("ImpactType", psStats->weaponClass == WC_KINETIC ? "KINETIC" : "HEAT",
QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatType", psStats->periodicalDamageWeaponClass == WC_KINETIC ? "KINETIC" : "HEAT",
QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("ImpactClass", getWeaponSubClass(psStats->weaponSubClass),
QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("RepeatClass", getWeaponSubClass(psStats->periodicalDamageWeaponSubClass),
QScriptValue::ReadOnly | QScriptValue::Undeletable);
weap.setProperty("FireOnMove", psStats->fireOnMove, QScriptValue::ReadOnly | QScriptValue::Undeletable);
wbase.setProperty(getStatName(psStats), weap, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Weapon", wbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[WeaponClass] Defined weapon classes
QScriptValue weaptypes = engine->newArray(WSC_NUM_WEAPON_SUBCLASSES);
for (int j = 0; j < WSC_NUM_WEAPON_SUBCLASSES; j++)
{
weaptypes.setProperty(j, getWeaponSubClass((WEAPON_SUBCLASS)j), QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("WeaponClass", weaptypes, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Building] Buildings
QScriptValue structbase = engine->newObject();
for (int j = 0; j < numStructureStats; j++)
{
STRUCTURE_STATS *psStats = asStructureStats + j;
QScriptValue strct = engine->newObject();
strct.setProperty("Id", psStats->pName, QScriptValue::ReadOnly | QScriptValue::Undeletable);
if (psStats->type == REF_DEFENSE || psStats->type == REF_WALL || psStats->type == REF_WALLCORNER
|| psStats->type == REF_BLASTDOOR || psStats->type == REF_GATE)
{
strct.setProperty("Type", "Wall", QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
else if (psStats->type != REF_DEMOLISH)
{
strct.setProperty("Type", "Structure", QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
else
{
strct.setProperty("Type", "Demolish", QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
strct.setProperty("ResearchPoints", psStats->base.research, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("RepairPoints", psStats->base.repair, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("PowerPoints", psStats->base.power, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("ProductionPoints", psStats->base.production, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("RearmPoints", psStats->base.rearm, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("Armour", psStats->base.armour, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("Thermal", psStats->base.thermal, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("HitPoints", psStats->base.hitpoints, QScriptValue::ReadOnly | QScriptValue::Undeletable);
strct.setProperty("Resistance", psStats->base.resistance, QScriptValue::ReadOnly | QScriptValue::Undeletable);
structbase.setProperty(getStatName(psStats), strct, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
stats.setProperty("Building", structbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
engine->globalObject().setProperty("Stats", stats, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \end{description}
//== \item[Upgrades] A special array containing per-player rules information for game entity types,
//== which can be written to in order to implement upgrades and other dynamic rules changes. Each item in the
//== array contains a subset of the sparse array of rules information in the \emph{Stats} global.
//== These values are defined:
//== \begin{description}
QScriptValue upgrades = engine->newArray(MAX_PLAYERS);
for (int i = 0; i < MAX_PLAYERS; i++)
{
QScriptValue node = engine->newObject();
//== \item[Body] Droid bodies
QScriptValue bodybase = engine->newObject();
for (int j = 0; j < numBodyStats; j++)
{
BODY_STATS *psStats = asBodyStats + j;
QScriptValue body = engine->newObject();
setStatsFunc(body, engine, "HitPoints", i, COMP_BODY, j, psStats->upgrade[i].body);
setStatsFunc(body, engine, "Power", i, COMP_BODY, j, psStats->upgrade[i].power);
setStatsFunc(body, engine, "Armour", i, COMP_BODY, j, psStats->upgrade[i].armour);
setStatsFunc(body, engine, "Thermal", i, COMP_BODY, j, psStats->upgrade[i].thermal);
setStatsFunc(body, engine, "Resistance", i, COMP_BODY, j, psStats->upgrade[i].resistance);
bodybase.setProperty(getStatName(psStats), body, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Body", bodybase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Sensor] Sensor turrets
QScriptValue sensorbase = engine->newObject();
for (int j = 0; j < numSensorStats; j++)
{
SENSOR_STATS *psStats = asSensorStats + j;
QScriptValue sensor = engine->newObject();
setStatsFunc(sensor, engine, "Range", i, COMP_SENSOR, j, psStats->upgrade[i].range);
sensorbase.setProperty(getStatName(psStats), sensor, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Sensor", sensorbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[ECM] ECM (Electronic Counter-Measure) turrets
QScriptValue ecmbase = engine->newObject();
for (int j = 0; j < numECMStats; j++)
{
ECM_STATS *psStats = asECMStats + j;
QScriptValue ecm = engine->newObject();
setStatsFunc(ecm, engine, "Range", i, COMP_ECM, j, psStats->upgrade[i].range);
ecmbase.setProperty(getStatName(psStats), ecm, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("ECM", ecmbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Repair] Repair turrets (not used, incidentially, for repair centers)
QScriptValue repairbase = engine->newObject();
for (int j = 0; j < numRepairStats; j++)
{
REPAIR_STATS *psStats = asRepairStats + j;
QScriptValue repair = engine->newObject();
setStatsFunc(repair, engine, "RepairPoints", i, COMP_REPAIRUNIT, j, psStats->upgrade[i].repairPoints);
repairbase.setProperty(getStatName(psStats), repair, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Repair", repairbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Construct] Constructor turrets (eg for trucks)
QScriptValue conbase = engine->newObject();
for (int j = 0; j < numConstructStats; j++)
{
CONSTRUCT_STATS *psStats = asConstructStats + j;
QScriptValue con = engine->newObject();
setStatsFunc(con, engine, "ConstructorPoints", i, COMP_CONSTRUCT, j, psStats->upgrade[i].constructPoints);
conbase.setProperty(getStatName(psStats), con, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Construct", conbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Weapon] Weapon turrets
QScriptValue wbase = engine->newObject();
for (int j = 0; j < numWeaponStats; j++)
{
WEAPON_STATS *psStats = asWeaponStats + j;
QScriptValue weap = engine->newObject();
setStatsFunc(weap, engine, "MaxRange", i, COMP_WEAPON, j, psStats->upgrade[i].maxRange);
setStatsFunc(weap, engine, "MinRange", i, COMP_WEAPON, j, psStats->upgrade[i].minRange);
setStatsFunc(weap, engine, "HitChance", i, COMP_WEAPON, j, psStats->upgrade[i].hitChance);
setStatsFunc(weap, engine, "FirePause", i, COMP_WEAPON, j, psStats->upgrade[i].firePause);
setStatsFunc(weap, engine, "ReloadTime", i, COMP_WEAPON, j, psStats->upgrade[i].reloadTime);
setStatsFunc(weap, engine, "Rounds", i, COMP_WEAPON, j, psStats->upgrade[i].numRounds);
setStatsFunc(weap, engine, "Radius", i, COMP_WEAPON, j, psStats->upgrade[i].radius);
setStatsFunc(weap, engine, "Damage", i, COMP_WEAPON, j, psStats->upgrade[i].damage);
setStatsFunc(weap, engine, "RadiusDamage", i, COMP_WEAPON, j, psStats->upgrade[i].radiusDamage);
setStatsFunc(weap, engine, "RepeatDamage", i, COMP_WEAPON, j, psStats->upgrade[i].periodicalDamage);
setStatsFunc(weap, engine, "RepeatTime", i, COMP_WEAPON, j, psStats->upgrade[i].periodicalDamageTime);
setStatsFunc(weap, engine, "RepeatRadius", i, COMP_WEAPON, j, psStats->upgrade[i].periodicalDamageRadius);
wbase.setProperty(getStatName(psStats), weap, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Weapon", wbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \item[Building] Buildings
QScriptValue structbase = engine->newObject();
for (int j = 0; j < numStructureStats; j++)
{
STRUCTURE_STATS *psStats = asStructureStats + j;
QScriptValue strct = engine->newObject();
setStatsFunc(strct, engine, "ResearchPoints", i, SCRCB_RES, j, psStats->upgrade[i].research);
setStatsFunc(strct, engine, "RepairPoints", i, SCRCB_REP, j, psStats->upgrade[i].repair);
setStatsFunc(strct, engine, "PowerPoints", i, SCRCB_POW, j, psStats->upgrade[i].power);
setStatsFunc(strct, engine, "ProductionPoints", i, SCRCB_CON, j, psStats->upgrade[i].production);
setStatsFunc(strct, engine, "RearmPoints", i, SCRCB_REA, j, psStats->upgrade[i].rearm);
setStatsFunc(strct, engine, "Armour", i, SCRCB_ARM, j, psStats->upgrade[i].armour);
setStatsFunc(strct, engine, "Resistance", i, SCRCB_ELW, j, psStats->upgrade[i].resistance);
setStatsFunc(strct, engine, "Thermal", i, SCRCB_HEA, j, psStats->upgrade[i].thermal);
setStatsFunc(strct, engine, "HitPoints", i, SCRCB_HIT, j, psStats->upgrade[i].hitpoints);
structbase.setProperty(getStatName(psStats), strct, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
node.setProperty("Building", structbase, QScriptValue::ReadOnly | QScriptValue::Undeletable);
// Finally
upgrades.setProperty(i, node, QScriptValue::ReadOnly | QScriptValue::Undeletable);
}
engine->globalObject().setProperty("Upgrades", upgrades, QScriptValue::ReadOnly | QScriptValue::Undeletable);
//== \end{description}
// Register functions to the script engine here
engine->globalObject().setProperty("_", engine->newFunction(js_translate));
engine->globalObject().setProperty("dump", engine->newFunction(js_dump));
@ -3880,6 +4412,7 @@ bool registerFunctions(QScriptEngine *engine, QString scriptName)
engine->globalObject().setProperty("hackChangeMe", engine->newFunction(js_hackChangeMe));
engine->globalObject().setProperty("hackAssert", engine->newFunction(js_hackAssert));
engine->globalObject().setProperty("hackMarkTiles", engine->newFunction(js_hackMarkTiles));
engine->globalObject().setProperty("receiveAllEvents", engine->newFunction(js_receiveAllEvents));
// General functions -- geared for use in AI scripts
engine->globalObject().setProperty("debug", engine->newFunction(js_debug));

View File

@ -136,20 +136,6 @@ BASE_STATS* get_any_component_from_ID(QString name)
return NULL;
}
//searches for function with given name
//returns NULL if not found
FUNCTION* find_function_by_ID(QString FunctionName)
{
for (unsigned int incF = 0; incF < numFunctions; incF++)
{
if (FunctionName.compare(asFunctions[incF]->pName, Qt::CaseInsensitive) == 0)
{
return asFunctions[incF];
}
}
return NULL;
}
/** Load the research stats */
bool loadResearch(QString filename)
{
@ -177,6 +163,8 @@ bool loadResearch(QString filename)
ASSERT_OR_RETURN(false, checkResearchName(&research, inc), "Research name '%s' used already", research.pName);
research.ref = REF_RESEARCH_START + inc;
research.resultStrings = ini.value("results").toStringList();
//set subGroup icon
QString subGroup = ini.value("subgroupIconID", "").toString();
@ -388,19 +376,6 @@ bool loadResearch(QString filename)
}
}
//set result functions
QStringList resFunc = ini.value("resultFunctions").toStringList();
for (int j = 0; j < resFunc.size(); j++)
{
QString funcID = resFunc[j].trimmed();
FUNCTION *pFunc = find_function_by_ID(funcID);
ASSERT(pFunc != NULL, "Invalid item '%s' in list of result functions of research '%s' ", funcID.toUtf8().constData(), getResearchName(&research));
if (pFunc != NULL)
{
research.pFunctionList.push_back(pFunc);
}
}
asResearch.push_back(research);
ini.endGroup();
}
@ -557,9 +532,6 @@ void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE
{
RESEARCH * pResearch = &asResearch[researchIndex];
UDWORD type, inc;
STRUCTURE *psCurr;
DROID *psDroid;
FUNCTION *pFunction;
UDWORD compInc;
MESSAGE *pMessage;
//the message gets sent to console
@ -653,320 +625,6 @@ void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE
apCompLists[player][type][pResearch->pRedArtefacts[inc]->ref - statRefStart(type)] = REDUNDANT;
}
//check for technology effects
for (inc = 0; inc < pResearch->pFunctionList.size(); inc++)
{
pFunction = pResearch->pFunctionList[inc];
switch (pFunction->type)
{
case PRODUCTION_UPGRADE_TYPE:
productionUpgrade(pFunction, player);
// search the list of players structures for a Factory
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if ((psCurr->pStructureType->type == REF_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->factory) ||
(psCurr->pStructureType->type == REF_CYBORG_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->cyborgFactory) ||
(psCurr->pStructureType->type == REF_VTOL_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->vtolFactory))
{
// upgrade the Output for the structure
structureProductionUpgrade(psCurr);
}
}
// and the mission structures
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if ((psCurr->pStructureType->type == REF_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->factory) ||
(psCurr->pStructureType->type == REF_CYBORG_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->cyborgFactory) ||
(psCurr->pStructureType->type == REF_VTOL_FACTORY &&
((PRODUCTION_UPGRADE_FUNCTION *)pFunction)->vtolFactory))
{
// upgrade the Output for the structure
structureProductionUpgrade(psCurr);
}
}
// message/sound in here for production boost
break;
case RESEARCH_UPGRADE_TYPE:
researchUpgrade(pFunction, player);
//search the list of players structures for a Research Facility
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_RESEARCH)
{
// upgrade the research points
structureResearchUpgrade(psCurr);
}
}
// and the mission structures
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_RESEARCH)
{
// upgrade the research points
structureResearchUpgrade(psCurr);
}
}
// Stuff a message in here/sound whatever for research boost.
break;
case POWER_UPGRADE_TYPE:
powerUpgrade(pFunction, player);
// search the list of players structures for a Power Gens
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_POWER_GEN)
{
// upgrade the power points
structurePowerUpgrade(psCurr);
}
}
// and the mission structure
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_POWER_GEN)
{
// upgrade the power points
structurePowerUpgrade(psCurr);
}
}
break;
case REARM_UPGRADE_TYPE:
reArmUpgrade(pFunction, player);
// search the list of players structures for a ReArm pad
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_REARM_PAD)
{
// upgrade the rearm points
structureReArmUpgrade(psCurr);
}
}
// and the mission structure
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_REARM_PAD)
{
// upgrade the rearm points
structureReArmUpgrade(psCurr);
}
}
break;
case REPAIR_UPGRADE_TYPE:
repairFacUpgrade(pFunction, player);
// search the list of players structures for a Power Gens
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_REPAIR_FACILITY)
{
// upgrade the repair points
structureRepairUpgrade(psCurr);
}
}
// and the mission structure
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_REPAIR_FACILITY)
{
// upgrade the repair points
structureRepairUpgrade(psCurr);
}
}
break;
case WEAPON_UPGRADE_TYPE:
// for the current player, upgrade the weapon stats
weaponUpgrade(pFunction, player);
// message/sound for weapon upgrade
break;
case DROIDSENSOR_UPGRADE_TYPE:
// for the current player, upgrade the sensor stats
sensorUpgrade(pFunction, player);
// for each structure in the player's list, upgrade the sensor stat
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
structureSensorUpgrade(psCurr);
visTilesUpdate(psCurr);
}
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
structureSensorUpgrade(psCurr);
}
// for each droid in the player's list, upgrade the sensor stat
for (psDroid = apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidSensorUpgrade(psDroid);
visTilesUpdate(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidSensorUpgrade);
}
}
for (psDroid = mission.apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidSensorUpgrade(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidSensorUpgrade);
}
}
for (psDroid = apsLimboDroids[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidSensorUpgrade(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidSensorUpgrade);
}
}
// message/sound for sensor upgrade
break;
case DROIDECM_UPGRADE_TYPE:
// for the current player, upgrade the ecm stats
ecmUpgrade(pFunction, player);
// for each structure in the player's list, upgrade the ecm stat
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
structureECMUpgrade(psCurr);
}
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
structureECMUpgrade(psCurr);
}
// for each droid in the player's list, upgrade the ecm stat
for (psDroid = apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidECMUpgrade(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidECMUpgrade);
}
}
for (psDroid = mission.apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidECMUpgrade(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidECMUpgrade);
}
}
for (psDroid = apsLimboDroids[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidECMUpgrade(psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidECMUpgrade);
}
}
// message/sound for ecm upgrade
break;
case DROIDREPAIR_UPGRADE_TYPE:
// for the current player, upgrade the repair stats
repairUpgrade(pFunction, player);
// message/sound for repair upgrade
break;
case DROIDCONST_UPGRADE_TYPE:
// for the current player, upgrade the constructor stats
constructorUpgrade(pFunction, player);
// message/sound for constructor upgrade
break;
case DROIDBODY_UPGRADE_TYPE:
// for each droid in the player's list, upgrade the body points
for (psDroid = apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(pFunction, psDroid);
}
for (psDroid = mission.apsDroidLists[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(pFunction, psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidSensorUpgrade);
}
}
for (psDroid = apsLimboDroids[player]; psDroid != NULL; psDroid = psDroid->psNext)
{
droidBodyUpgrade(pFunction, psDroid);
if (psDroid->droidType == DROID_TRANSPORTER || psDroid->droidType == DROID_SUPERTRANSPORTER)
{
upgradeTransporterDroids(psDroid, droidSensorUpgrade);
}
}
// DO THIS AFTER so above calculations can use the previous upgrade values for
// the current player, upgrade the body stats
bodyUpgrade(pFunction, player);
// message/sound for body upgrade
break;
case STRUCTURE_UPGRADE_TYPE:
// for each structure in the player's list, upgrade the stats
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
//do this for none wallDefense structs
if (!wallDefenceStruct(psCurr->pStructureType))
{
structureBodyUpgrade(pFunction, psCurr);
structureArmourUpgrade(pFunction, psCurr);
structureResistanceUpgrade(pFunction, psCurr);
}
// Defense type can have resistance upgrade now - AB 19/02/99
if (psCurr->pStructureType->type == REF_DEFENSE)
{
structureResistanceUpgrade(pFunction, psCurr);
}
}
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
//do this for none wallDefense structs
if (!wallDefenceStruct(psCurr->pStructureType))
{
structureBodyUpgrade(pFunction, psCurr);
structureArmourUpgrade(pFunction, psCurr);
structureResistanceUpgrade(pFunction, psCurr);
}
// Defense type can have resistance upgrade now - AB 19/02/99
if (psCurr->pStructureType->type == REF_DEFENSE)
{
structureResistanceUpgrade(pFunction, psCurr);
}
}
// DO THIS AFTER so above calculations can use the previous upgrade values
// for the current player, upgrade the structure stats
structureUpgrade(pFunction, player);
// message/sound for structure upgrade
break;
case WALLDEFENCE_UPGRADE_TYPE:
//for each structure in the player's list, upgrade the stats
for (psCurr = apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
// do this for wallDefense structs
if (wallDefenceStruct(psCurr->pStructureType))
{
structureBodyUpgrade(pFunction, psCurr);
structureArmourUpgrade(pFunction, psCurr);
}
}
for (psCurr = mission.apsStructLists[player]; psCurr != NULL; psCurr = psCurr->psNext)
{
// do this for wallDefense structs
if (wallDefenceStruct(psCurr->pStructureType))
{
structureBodyUpgrade(pFunction, psCurr);
structureArmourUpgrade(pFunction, psCurr);
}
}
// DO THIS AFTER so above calculations can use the previous upgrade values
// for the current player, upgrade the wall/defence structure stats
wallDefenceUpgrade(pFunction, player);
// message/sound for wall/defence structure upgrade
break;
default:
ASSERT(false, "Invalid function type");
break;
}//end of switch
}//end of function loop
//Add message to player's list if Major Topic
if ((pResearch->techCode == TC_MAJOR) && bDisplay)
{
@ -1021,9 +679,8 @@ void researchResult(UDWORD researchIndex, UBYTE player, bool bDisplay, STRUCTURE
psCBLastResStructure = NULL;
CBResFacilityOwner = -1;
psCBLastResearch = NULL;
triggerEventResearched(pResearch, psResearchFacility, player);
}
triggerEventResearched(pResearch, psResearchFacility, player, bTrigger);
}
/*This function is called when the research files are reloaded*/
@ -1622,11 +1279,6 @@ bool checkResearchStats(void)
{
ASSERT(asResearch[resInc].pStructList[inc] <= numStructureStats, "Invalid Structure for topic %s", asResearch[resInc].pName);
}
for (inc = 0; inc < asResearch[resInc].pFunctionList.size(); inc++)
{
ASSERT(asResearch[resInc].pFunctionList[inc]->ref - REF_FUNCTION_START <= numFunctions,
"Invalid function for %s", asResearch[resInc].pName);
}
for (inc = 0; inc < asResearch[resInc].pRedStructs.size(); inc++)
{
ASSERT(asResearch[resInc].pRedStructs[inc] <= numStructureStats,
@ -1738,12 +1390,6 @@ void replaceStructureComponent(STRUCTURE *pList, UDWORD oldType, UDWORD oldCompI
{
switch (oldType)
{
case COMP_ECM:
objEcmCache((BASE_OBJECT *)psStructure, asECMStats + newCompInc);
break;
case COMP_SENSOR:
objSensorCache((BASE_OBJECT *)psStructure, asSensorStats + newCompInc);
break;
case COMP_WEAPON:
for (inc=0; inc < psStructure->numWeaps; inc++)
{
@ -1848,7 +1494,8 @@ std::vector<AllyResearch> const &listAllyResearch(unsigned ref)
r.timeToResearch = -1;
if (r.powerNeeded == -1)
{
r.timeToResearch = (subject.researchPoints - playerRes.currentPoints) / std::max(res->researchPoints, 1u);
r.timeToResearch = (subject.researchPoints - playerRes.currentPoints)
/ MAX(psStruct->pStructureType->base.research, 1u);
}
r.active = psStruct->status == SS_BUILT;
researches[cRef].push_back(r);

View File

@ -24,6 +24,7 @@
#ifndef __INCLUDED_RESEARCHDEF_H__
#define __INCLUDED_RESEARCHDEF_H__
#include <QStringList>
#include "lib/framework/frame.h"
#include "statsdef.h"
@ -52,12 +53,12 @@ struct RESEARCH : public BASE_STATS
this topic must be explicitly enabled*/
std::vector<UWORD> pPRList; ///< List of research pre-requisites
std::vector<UWORD> pStructList; ///< List of structures that when built would enable this research
std::vector<FUNCTION *> pFunctionList; ///< List of functions that can be performed on completion of research
std::vector<UWORD> pRedStructs; ///< List of Structures that become redundant
std::vector<COMPONENT_STATS *> pRedArtefacts; ///< List of Artefacts that become redundant
std::vector<UWORD> pStructureResults; ///< List of Structures that are possible after this research
QList<COMPONENT_STATS *> componentResults; ///< List of Components that are possible after this research
QList<RES_COMP_REPLACEMENT> componentReplacement; ///< List of Components that are automatically replaced with new onew after research
QStringList resultStrings; ///< List of hints to javascript interface how to deal with the research
const struct VIEWDATA *pViewData; // data used to display a message in the Intelligence Screen
UWORD iconID; /* the ID from 'Framer' for which graphic to draw in interface*/
BASE_STATS *psStat; /* A stat used to define which graphic is drawn instead of the two fields below */

View File

@ -8500,7 +8500,7 @@ bool scrObjWeaponMaxRange(void)
{
ASSERT_OR_RETURN(false, psDroid->asWeaps[0].nStat < numWeaponStats, "Invalid range referenced.");
psStats = asWeaponStats + psDroid->asWeaps[0].nStat;
scrFunctionResult.v.ival = psStats->longRange;
scrFunctionResult.v.ival = psStats->base.maxRange;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
{
return false;
@ -8516,7 +8516,7 @@ bool scrObjWeaponMaxRange(void)
{
ASSERT_OR_RETURN(false, psStruct->asWeaps[0].nStat < numWeaponStats, "Invalid range referenced.");
psStats = asWeaponStats + psStruct->asWeaps[0].nStat;
scrFunctionResult.v.ival = psStats->longRange;
scrFunctionResult.v.ival = psStats->base.maxRange;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
{
return false;
@ -10363,19 +10363,17 @@ static DROID_TEMPLATE *scrCheckTemplateExists(SDWORD player, DROID_TEMPLATE *psT
return NULL;
}
// deprecated
bool scrWeaponLongHitUpgrade(void)
{
SDWORD player, weapIndex;
const WEAPON_STATS *psWeapStats;
if (!stackPopParams(2, VAL_INT, &player, ST_WEAPON, &weapIndex))
{
return false;
}
psWeapStats = &asWeaponStats[weapIndex];
scrFunctionResult.v.ival = asWeaponUpgrade[player][psWeapStats->weaponSubClass].longHit;
scrFunctionResult.v.ival = 0;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
{
return false;
@ -10384,19 +10382,17 @@ bool scrWeaponLongHitUpgrade(void)
return true;
}
// deprecated
bool scrWeaponDamageUpgrade(void)
{
SDWORD player, weapIndex;
const WEAPON_STATS *psWeapStats;
if (!stackPopParams(2, VAL_INT, &player, ST_WEAPON, &weapIndex))
{
return false;
}
psWeapStats = &asWeaponStats[weapIndex];
scrFunctionResult.v.ival = asWeaponUpgrade[player][psWeapStats->weaponSubClass].damage;
scrFunctionResult.v.ival = 0;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
{
return false;
@ -10405,19 +10401,17 @@ bool scrWeaponDamageUpgrade(void)
return true;
}
// deprecated
bool scrWeaponFirePauseUpgrade(void)
{
SDWORD player, weapIndex;
const WEAPON_STATS *psWeapStats;
if (!stackPopParams(2, VAL_INT, &player, ST_WEAPON, &weapIndex))
{
return false;
}
psWeapStats = &asWeaponStats[weapIndex];
scrFunctionResult.v.ival = asWeaponUpgrade[player][psWeapStats->weaponSubClass].firePause;
scrFunctionResult.v.ival = 0;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
{
return false;

View File

@ -458,27 +458,27 @@ bool scrWeaponObjGet(UDWORD index)
{
case WEAPID_LONG_RANGE:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].longRange;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.maxRange;
break;
case WEAPID_LONG_HIT:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].longHit;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.hitChance;
break;
case WEAPID_DAMAGE:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].damage;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.damage;
break;
case WEAPID_FIRE_PAUSE:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].firePause;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.firePause;
break;
case WEAPID_RELOAD_TIME:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].reloadTime;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.reloadTime;
break;
case WEAPID_NUM_ROUNDS:
type = VAL_INT;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].numRounds;
scrFunctionResult.v.ival = asWeaponStats[weapIndex].base.numRounds;
break;
default:
ASSERT( false, "unknown variable index" );

View File

@ -57,14 +57,6 @@ static TERRAIN_TABLE *asTerrainTable;
WEAPON_MODIFIER asWeaponModifier[WE_NUMEFFECTS][PROPULSION_TYPE_NUM];
WEAPON_MODIFIER asWeaponModifierBody[WE_NUMEFFECTS][SIZE_NUM];
//used to hold the current upgrade level per player per weapon subclass
WEAPON_UPGRADE asWeaponUpgrade[MAX_PLAYERS][WSC_NUM_WEAPON_SUBCLASSES];
SENSOR_UPGRADE asSensorUpgrade[MAX_PLAYERS];
ECM_UPGRADE asECMUpgrade[MAX_PLAYERS];
REPAIR_UPGRADE asRepairUpgrade[MAX_PLAYERS];
CONSTRUCTOR_UPGRADE asConstUpgrade[MAX_PLAYERS];
BODY_UPGRADE asBodyUpgrade[MAX_PLAYERS][BODY_TYPE];
/* The number of different stats stored */
UDWORD numBodyStats;
UDWORD numBrainStats;
@ -418,14 +410,6 @@ void statsInitVars(void)
numWeaponStats = 0;
numConstructStats = 0;
//initialise the upgrade structures
memset(asWeaponUpgrade, 0, sizeof(asWeaponUpgrade));
memset(asSensorUpgrade, 0, sizeof(asSensorUpgrade));
memset(asECMUpgrade, 0, sizeof(asECMUpgrade));
memset(asRepairUpgrade, 0, sizeof(asRepairUpgrade));
memset(asConstUpgrade, 0, sizeof(asConstUpgrade));
memset(asBodyUpgrade, 0, sizeof(asBodyUpgrade));
// init the max values
maxComponentWeight = maxBodyArmour = maxBodyPower =
maxBodyPoints = maxSensorRange = maxECMRange =
@ -461,8 +445,6 @@ bool statsShutDown(void)
deallocBodyStats();
STATS_DEALLOC(asBrainStats, numBrainStats);
STATS_DEALLOC(asPropulsionStats, numPropulsionStats);
STATS_DEALLOC(asSensorStats, numSensorStats);
STATS_DEALLOC(asECMStats, numECMStats);
STATS_DEALLOC(asRepairStats, numRepairStats);
STATS_DEALLOC(asConstructStats, numConstructStats);
deallocPropulsionTypes();
@ -644,26 +626,37 @@ bool loadWeaponStats(const char *pFileName)
psStats->buildPoints = ini.value("buildPoints", 0).toUInt();
psStats->weight = ini.value("weight", 0).toUInt();
psStats->body = ini.value("body", 0).toUInt();
psStats->longRange = ini.value("longRange").toUInt();
psStats->longHit = ini.value("longHit").toUInt();
psStats->firePause = ini.value("firePause").toUInt();
psStats->numExplosions = ini.value("numExplosions").toUInt();
psStats->numRounds = ini.value("numRounds").toUInt();
psStats->reloadTime = ini.value("reloadTime").toUInt();
psStats->damage = ini.value("damage").toUInt();
psStats->radius = ini.value("radius").toUInt();
psStats->radiusHit = ini.value("radiusHit").toUInt();
psStats->radiusDamage = ini.value("radiusDamage").toUInt();
psStats->periodicalDamageTime = ini.value("periodicalDamageTime", 0).toUInt();
psStats->periodicalDamage = ini.value("periodicalDamage", 0).toUInt();
psStats->periodicalDamageRadius = ini.value("periodicalDamageRadius", 0).toUInt();
psStats->radiusLife = ini.value("radiusLife").toUInt();
psStats->base.maxRange = ini.value("longRange").toUInt();
psStats->base.minRange = ini.value("minRange", 0).toUInt();
psStats->base.hitChance = ini.value("longHit").toUInt();
psStats->base.firePause = ini.value("firePause").toUInt();
psStats->base.numRounds = ini.value("numRounds").toUInt();
psStats->base.reloadTime = ini.value("reloadTime").toUInt();
psStats->base.damage = ini.value("damage").toUInt();
psStats->base.radius = ini.value("radius").toUInt();
psStats->base.radiusDamage = ini.value("radiusDamage").toUInt();
psStats->base.periodicalDamageTime = ini.value("periodicalDamageTime", 0).toUInt();
psStats->base.periodicalDamage = ini.value("periodicalDamage", 0).toUInt();
psStats->base.periodicalDamageRadius = ini.value("periodicalDamageRadius", 0).toUInt();
// multiply time stats
psStats->base.firePause *= WEAPON_TIME;
psStats->base.periodicalDamageTime *= WEAPON_TIME;
psStats->radiusLife *= WEAPON_TIME;
psStats->base.reloadTime *= WEAPON_TIME;
// copy for upgrades
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j] = psStats->base;
}
psStats->numExplosions = ini.value("numExplosions").toUInt();
psStats->flightSpeed = ini.value("flightSpeed", 1).toUInt();
psStats->rotate = ini.value("rotate").toUInt();
psStats->minElevation = ini.value("minElevation").toInt();
psStats->maxElevation = ini.value("maxElevation").toInt();
psStats->recoilValue = ini.value("recoilValue").toUInt();
psStats->minRange = ini.value("minRange", 0).toUInt();
psStats->effectSize = ini.value("effectSize").toUInt();
surfaceToAir = ini.value("surfaceToAir", 0).toUInt();
psStats->vtolAttackRuns = ini.value("numAttackRuns", 0).toUInt();
@ -679,12 +672,6 @@ bool loadWeaponStats(const char *pFileName)
allocateStatName((BASE_STATS *)psStats, list[i].toUtf8().constData());
psStats->ref = REF_WEAPON_START + i;
//multiply time stats
psStats->firePause *= WEAPON_TIME;
psStats->periodicalDamageTime *= WEAPON_TIME;
psStats->radiusLife *= WEAPON_TIME;
psStats->reloadTime *= WEAPON_TIME;
//get the IMD for the component
psStats->pIMD = statsGetIMD(ini, psStats, "model");
psStats->pMountGraphic = statsGetIMD(ini, psStats, "mountModel");
@ -817,9 +804,9 @@ bool loadWeaponStats(const char *pFileName)
// Set the max stat values for the design screen
if (psStats->designable)
{
setMaxWeaponRange(psStats->longRange);
setMaxWeaponDamage(psStats->damage);
setMaxWeaponROF(weaponROF(psStats, -1));
setMaxWeaponRange(psStats->base.maxRange);
setMaxWeaponDamage(psStats->base.damage);
setMaxWeaponROF(weaponROF(psStats, 0));
setMaxComponentWeight(psStats->weight);
}
@ -852,10 +839,17 @@ bool loadBodyStats(const char *pFileName)
psStats->buildPoints = ini.value("buildPoints", 0).toInt();
psStats->body = ini.value("hitpoints").toInt();
psStats->weaponSlots = ini.value("weaponSlots").toInt();
psStats->powerOutput = ini.value("powerOutput").toInt();
psStats->armourValue[WC_KINETIC] = ini.value("armourKinetic").toInt();
psStats->armourValue[WC_HEAT] = ini.value("armourHeat").toInt();
psStats->designable = ini.value("designable", false).toBool();
sstrcpy(psStats->bodyClass, ini.value("class").toString().toUtf8().constData());
psStats->base.thermal = ini.value("armourHeat").toInt();
psStats->base.armour = ini.value("armourKinetic").toInt();
psStats->base.power = ini.value("powerOutput").toInt();
psStats->base.body = psStats->body; // special exception hack
psStats->base.resistance = ini.value("resistance", 30).toInt();
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j] = psStats->base;
}
QString dtype = ini.value("droidType", "DROID").toString();
psStats->droidTypeOverride = DROID_DEFAULT;
if (dtype.compare("PERSON") == 0)
@ -899,9 +893,9 @@ bool loadBodyStats(const char *pFileName)
//set the max stat values for the design screen
if (psStats->designable)
{
setMaxBodyArmour(psStats->armourValue[WC_KINETIC]);
setMaxBodyArmour(psStats->armourValue[WC_HEAT]);
setMaxBodyPower(psStats->powerOutput);
setMaxBodyArmour(psStats->base.armour);
setMaxBodyArmour(psStats->base.thermal);
setMaxBodyPower(psStats->base.power);
setMaxBodyPoints(psStats->body);
setMaxComponentWeight(psStats->weight);
}
@ -1103,9 +1097,12 @@ bool loadSensorStats(const char *pFileName)
psStats->buildPoints = ini.value("buildPoints", 0).toInt();
psStats->weight = ini.value("weight", 0).toInt();
psStats->body = ini.value("bodyPoints", 0).toInt();
psStats->range = ini.value("range").toInt();
psStats->base.range = ini.value("range").toInt();
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j].range = psStats->base.range;
}
psStats->time = ini.value("time").toInt();
psStats->power = ini.value("power").toInt();
psStats->designable = ini.value("designable", false).toBool();
allocateStatName((BASE_STATS *)psStats, list[i].toUtf8().constData());
@ -1167,7 +1164,7 @@ bool loadSensorStats(const char *pFileName)
// set the max stat values for the design screen
if (psStats->designable)
{
setMaxSensorRange(psStats->range);
setMaxSensorRange(psStats->base.range);
setMaxComponentWeight(psStats->weight);
}
@ -1201,7 +1198,11 @@ bool loadECMStats(const char *pFileName)
psStats->buildPoints = ini.value("buildPoints", 0).toInt();
psStats->weight = ini.value("weight", 0).toInt();
psStats->body = ini.value("body", 0).toInt();
psStats->range = ini.value("range").toInt();
psStats->base.range = ini.value("range").toInt();
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j].range = psStats->base.range;
}
psStats->designable = ini.value("designable", false).toBool();
allocateStatName((BASE_STATS *)psStats, list[i].toUtf8().constData());
@ -1232,7 +1233,7 @@ bool loadECMStats(const char *pFileName)
// Set the max stat values for the design screen
if (psStats->designable)
{
setMaxECMRange(psStats->range);
setMaxECMRange(psStats->base.range);
setMaxComponentWeight(psStats->weight);
}
}
@ -1265,8 +1266,11 @@ bool loadRepairStats(const char *pFileName)
psStats->buildPower = ini.value("buildPower", 0).toInt();
psStats->buildPoints = ini.value("buildPoints", 0).toInt();
psStats->weight = ini.value("weight", 0).toInt();
psStats->repairArmour = ini.value("repairArmour").toBool();
psStats->repairPoints = ini.value("repairPoints").toInt();
psStats->base.repairPoints = ini.value("repairPoints").toInt();
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j].repairPoints = psStats->base.repairPoints;
}
psStats->time = ini.value("time", 0).toInt() * WEAPON_TIME;
psStats->designable = ini.value("designable", false).toBool();
@ -1301,7 +1305,7 @@ bool loadRepairStats(const char *pFileName)
//set the max stat values for the design screen
if (psStats->designable)
{
setMaxRepairPoints(psStats->repairPoints);
setMaxRepairPoints(psStats->base.repairPoints);
setMaxComponentWeight(psStats->weight);
}
@ -1335,7 +1339,11 @@ bool loadConstructStats(const char *pFileName)
psStats->buildPoints = ini.value("buildPoints", 0).toInt();
psStats->weight = ini.value("weight", 0).toInt();
psStats->body = ini.value("bodyPoints", 0).toInt();
psStats->constructPoints = ini.value("constructPoints").toInt();
psStats->base.constructPoints = ini.value("constructPoints").toInt();
for (int j = 0; j < MAX_PLAYERS; j++)
{
psStats->upgrade[j].constructPoints = psStats->base.constructPoints;
}
psStats->designable = ini.value("designable", false).toBool();
allocateStatName((BASE_STATS *)psStats, list[i].toUtf8().constData());
@ -1352,7 +1360,7 @@ bool loadConstructStats(const char *pFileName)
// Set the max stat values for the design screen
if (psStats->designable)
{
setMaxConstPoints(psStats->constructPoints);
setMaxConstPoints(psStats->base.constructPoints);
setMaxComponentWeight(psStats->weight);
}
}
@ -2128,6 +2136,34 @@ bool getWeaponSubClass(const char *subClass, WEAPON_SUBCLASS *wclass)
return true;
}
/*returns the weapon sub class based on the string name passed in */
const char *getWeaponSubClass(WEAPON_SUBCLASS wclass)
{
switch (wclass)
{
case WSC_CANNON: return "CANNON";
case WSC_MORTARS: return "MORTARS";
case WSC_MISSILE: return "MISSILE";
case WSC_ROCKET: return "ROCKET";
case WSC_ENERGY: return "ENERGY";
case WSC_GAUSS: return "GAUSS";
case WSC_FLAME: return "FLAME";
case WSC_HOWITZERS: return "HOWITZERS";
case WSC_MGUN: return "MACHINE GUN";
case WSC_ELECTRONIC: return "ELECTRONIC";
case WSC_AAGUN: return "A-A GUN";
case WSC_SLOWMISSILE: return "SLOW MISSILE";
case WSC_SLOWROCKET: return "SLOW ROCKET";
case WSC_LAS_SAT: return "LAS_SAT";
case WSC_BOMB: return "BOMB";
case WSC_COMMAND: return "COMMAND";
case WSC_EMP: return "EMP";
case WSC_NUM_WEAPON_SUBCLASSES: break;
}
ASSERT(false, "No such weapon subclass");
return "Bad weapon subclass";
}
/*returns the movement model based on the string name passed in */
bool getMovementModel(const char *movementModel, MOVEMENT_MODEL *model)
{
@ -2210,22 +2246,13 @@ bool getWeaponClass(QString weaponClassStr, WEAPON_CLASS *weaponClass)
{
*weaponClass = WC_KINETIC;
}
else if (weaponClassStr.compare("EXPLOSIVE") == 0)
{
//psStats->weaponClass = WC_EXPLOSIVE;
*weaponClass = WC_KINETIC; // explosives were removed from release version of Warzone
}
else if (weaponClassStr.compare("HEAT") == 0)
{
*weaponClass = WC_HEAT;
}
else if (weaponClassStr.compare("MISC") == 0)
{
//psStats->weaponClass = WC_MISC;
*weaponClass = WC_HEAT; // removed from release version of Warzone
}
else
{
ASSERT(false, "Bad weapon class %s", weaponClassStr.toUtf8().constData());
return false;
};
return true;
@ -2251,87 +2278,71 @@ char *allocateName(const char *name)
/*Access functions for the upgradeable stats of a weapon*/
UDWORD weaponFirePause(const WEAPON_STATS *psStats, UBYTE player)
int weaponFirePause(const WEAPON_STATS *psStats, int player)
{
if (psStats->reloadTime == 0)
{
return (psStats->firePause - (psStats->firePause * asWeaponUpgrade[player][
psStats->weaponSubClass].firePause) / 100);
}
else
{
return psStats->firePause; //fire pause is neglectable for weapons with reload time
}
return psStats->upgrade[player].firePause;
}
/* Reload time is reduced for weapons with salvo fire */
UDWORD weaponReloadTime(WEAPON_STATS *psStats, UBYTE player)
int weaponReloadTime(const WEAPON_STATS *psStats, int player)
{
return (psStats->reloadTime - (psStats->reloadTime * asWeaponUpgrade[player][psStats->weaponSubClass].firePause) / 100);
return psStats->upgrade[player].reloadTime;
}
UDWORD weaponLongHit(const WEAPON_STATS *psStats, UBYTE player)
int weaponLongHit(const WEAPON_STATS *psStats, int player)
{
return (psStats->longHit + (psStats->longHit * asWeaponUpgrade[player][psStats->weaponSubClass].longHit) / 100);
return psStats->upgrade[player].hitChance;
}
UDWORD weaponDamage(const WEAPON_STATS *psStats, UBYTE player)
int weaponDamage(const WEAPON_STATS *psStats, int player)
{
return (psStats->damage + (psStats->damage * asWeaponUpgrade[player][psStats->weaponSubClass].damage) / 100);
return psStats->upgrade[player].damage;
}
UDWORD weaponRadDamage(WEAPON_STATS *psStats, UBYTE player)
int weaponRadDamage(const WEAPON_STATS *psStats, int player)
{
return (psStats->radiusDamage + (psStats->radiusDamage * asWeaponUpgrade[player][psStats->weaponSubClass].radiusDamage) / 100);
return psStats->upgrade[player].radiusDamage;
}
UDWORD weaponPeriodicalDamage(WEAPON_STATS *psStats, UBYTE player)
int weaponPeriodicalDamage(const WEAPON_STATS *psStats, int player)
{
return (psStats->periodicalDamage + (psStats->periodicalDamage
* asWeaponUpgrade[player][psStats->periodicalDamageWeaponSubClass].periodicalDamage) / 100);
return psStats->upgrade[player].periodicalDamage;
}
UDWORD weaponRadiusHit(WEAPON_STATS *psStats, UBYTE player)
int sensorRange(const SENSOR_STATS *psStats, int player)
{
return (psStats->radiusHit + (psStats->radiusHit * asWeaponUpgrade[player][psStats->weaponSubClass].radiusHit) / 100);
return psStats->upgrade[player].range;
}
UDWORD sensorRange(SENSOR_STATS *psStats, UBYTE player)
int ecmRange(const ECM_STATS *psStats, int player)
{
return psStats->range + (psStats->range * asSensorUpgrade[player].range) / 100;
return psStats->upgrade[player].range;
}
UDWORD ecmRange(ECM_STATS *psStats, UBYTE player)
int repairPoints(const REPAIR_STATS *psStats, int player)
{
return psStats->range + (psStats->range * asECMUpgrade[player].range) / 100;
return psStats->upgrade[player].repairPoints;
}
UDWORD repairPoints(REPAIR_STATS *psStats, UBYTE player)
int constructorPoints(const CONSTRUCT_STATS *psStats, int player)
{
return (psStats->repairPoints + (psStats->repairPoints * asRepairUpgrade[player].repairPoints) / 100);
return psStats->upgrade[player].constructPoints;
}
UDWORD constructorPoints(CONSTRUCT_STATS *psStats, UBYTE player)
int bodyPower(const BODY_STATS *psStats, int player)
{
return (psStats->constructPoints + (psStats->constructPoints * asConstUpgrade[player].constructPoints) / 100);
return psStats->upgrade[player].power;
}
UDWORD bodyPower(BODY_STATS *psStats, UBYTE player, UBYTE bodyType)
{
return (psStats->powerOutput + (psStats->powerOutput * asBodyUpgrade[player][bodyType].powerOutput) / 100);
}
UDWORD bodyArmour(BODY_STATS *psStats, UBYTE player, UBYTE bodyType, WEAPON_CLASS weaponClass)
int bodyArmour(const BODY_STATS *psStats, int player, WEAPON_CLASS weaponClass)
{
switch (weaponClass)
{
case WC_KINETIC:
//case WC_EXPLOSIVE:
return (psStats->armourValue[WC_KINETIC] + (psStats->armourValue[WC_KINETIC] * asBodyUpgrade[player][bodyType].armourValue[WC_KINETIC]) / 100);
return psStats->upgrade[player].armour;
case WC_HEAT:
//case WC_MISC:
return (psStats->armourValue[WC_HEAT] + (psStats->armourValue[WC_HEAT] * asBodyUpgrade[player][bodyType].armourValue[WC_HEAT]) / 100);
default:
return psStats->upgrade[player].thermal;
case WC_NUM_WEAPON_CLASSES:
break;
}
ASSERT(false, "Unknown weapon class");
@ -2339,23 +2350,22 @@ UDWORD bodyArmour(BODY_STATS *psStats, UBYTE player, UBYTE bodyType, WEAPON_CLAS
}
//calculates the weapons ROF based on the fire pause and the salvos
UWORD weaponROF(WEAPON_STATS *psStat, SBYTE player)
int weaponROF(const WEAPON_STATS *psStat, int player)
{
UWORD rof = 0;
int rof = 0;
//if there are salvos
if (psStat->numRounds)
if (psStat->upgrade[player].numRounds) // if there are salvos
{
if (psStat->reloadTime != 0)
if (psStat->upgrade[player].reloadTime != 0)
{
// Rounds per salvo multiplied with the number of salvos per minute
rof = (UWORD)(psStat->numRounds * 60 * GAME_TICKS_PER_SEC /
(player >= 0 ? weaponReloadTime(psStat, player) : psStat->reloadTime));
rof = psStat->upgrade[player].numRounds * 60 * GAME_TICKS_PER_SEC /
(player >= 0 ? weaponReloadTime(psStat, player) : psStat->upgrade[player].reloadTime);
}
}
if (rof == 0)
{
rof = (UWORD)weaponFirePause(psStat, (UBYTE)selectedPlayer);
rof = weaponFirePause(psStat, selectedPlayer);
if (rof != 0)
{
rof = (UWORD)(60 * GAME_TICKS_PER_SEC / rof);
@ -2595,73 +2605,47 @@ void updateMaxConstStats(UWORD maxValue)
}
}
//propulsion stats are not upgradeable
void adjustMaxDesignStats(void)
{
UWORD weaponDamage, sensorRange, repairPoints,
ecmRange, constPoints, bodyPoints, bodyPower, bodyArmour, inc;
ecmRange, constPoints, bodyPoints, bodyPower, bodyArmour;
// init all the values
weaponDamage = sensorRange = repairPoints = ecmRange = constPoints = bodyPoints = bodyPower = bodyArmour = 0;
//go thru' all the functions getting the max upgrade values for the stats
for (inc = 0; inc < numFunctions; inc++)
for (int j = 0; j < numBodyStats; j++)
{
switch (asFunctions[inc]->type)
{
case DROIDREPAIR_UPGRADE_TYPE:
if (repairPoints < ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints)
{
repairPoints = ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints;
}
break;
case DROIDECM_UPGRADE_TYPE:
if (ecmRange < ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints)
{
ecmRange = ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints;
}
break;
case DROIDBODY_UPGRADE_TYPE:
if (bodyPoints < ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->body)
{
bodyPoints = ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->body;
}
if (bodyPower < ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints)
{
bodyPower = ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints;
}
if (bodyArmour < ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->armourValue[WC_KINETIC])
{
bodyArmour = ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->armourValue[WC_KINETIC];
}
if (bodyArmour < ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->armourValue[WC_HEAT])
{
bodyArmour = ((DROIDBODY_UPGRADE_FUNCTION *)asFunctions[inc])->armourValue[WC_HEAT];
}
break;
case DROIDSENSOR_UPGRADE_TYPE:
if (sensorRange < ((DROIDSENSOR_UPGRADE_FUNCTION *)asFunctions[inc])->range)
{
sensorRange = ((DROIDSENSOR_UPGRADE_FUNCTION *)asFunctions[inc])->range;
}
break;
case DROIDCONST_UPGRADE_TYPE:
if (constPoints < ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints)
{
constPoints = ((UPGRADE_FUNCTION *)asFunctions[inc])->upgradePoints;
}
break;
case WEAPON_UPGRADE_TYPE:
if (weaponDamage < ((WEAPON_UPGRADE_FUNCTION *)asFunctions[inc])->damage)
{
weaponDamage = ((WEAPON_UPGRADE_FUNCTION *)asFunctions[inc])->damage;
}
break;
default:
//not interested in other function types
break;
}
BODY_STATS *psStats = asBodyStats + j;
bodyPoints = MAX(bodyPoints, psStats->upgrade[selectedPlayer].body);
bodyArmour = MAX(bodyArmour, psStats->upgrade[selectedPlayer].armour);
bodyPower = MAX(bodyPower, psStats->upgrade[selectedPlayer].power);
}
for (int j = 0; j < numSensorStats; j++)
{
SENSOR_STATS *psStats = asSensorStats + j;
sensorRange = MAX(sensorRange, psStats->upgrade[selectedPlayer].range);
}
for (int j = 0; j < numECMStats; j++)
{
ECM_STATS *psStats = asECMStats + j;
ecmRange = MAX(ecmRange, psStats->upgrade[selectedPlayer].range);
}
for (int j = 0; j < numRepairStats; j++)
{
REPAIR_STATS *psStats = asRepairStats + j;
repairPoints = MAX(repairPoints, psStats->upgrade[selectedPlayer].repairPoints);
}
for (int j = 0; j < numConstructStats; j++)
{
CONSTRUCT_STATS *psStats = asConstructStats + j;
constPoints = MAX(constPoints, psStats->upgrade[selectedPlayer].constructPoints);
}
for (int j = 0; j < numWeaponStats; j++)
{
WEAPON_STATS *psStats = asWeaponStats + j;
weaponDamage = MAX(weaponDamage, psStats->upgrade[selectedPlayer].damage);
}
//determine the effect on the max values for the stats
@ -2676,7 +2660,6 @@ void adjustMaxDesignStats(void)
/* Check if an object has a weapon */
bool objHasWeapon(const BASE_OBJECT *psObj)
{
//check if valid type
if (psObj->type == OBJ_DROID)
{

View File

@ -47,18 +47,6 @@ extern PROPULSION_TYPES *asPropulsionTypes;
extern WEAPON_MODIFIER asWeaponModifier[WE_NUMEFFECTS][PROPULSION_TYPE_NUM];
extern WEAPON_MODIFIER asWeaponModifierBody[WE_NUMEFFECTS][SIZE_NUM];
//used to hold the current upgrade level per player per weapon subclass
extern WEAPON_UPGRADE asWeaponUpgrade[MAX_PLAYERS][WSC_NUM_WEAPON_SUBCLASSES];
extern SENSOR_UPGRADE asSensorUpgrade[MAX_PLAYERS];
extern ECM_UPGRADE asECMUpgrade[MAX_PLAYERS];
extern REPAIR_UPGRADE asRepairUpgrade[MAX_PLAYERS];
extern CONSTRUCTOR_UPGRADE asConstUpgrade[MAX_PLAYERS];
//body upgrades are possible for droids and/or cyborgs
#define DROID_BODY_UPGRADE 0
#define CYBORG_BODY_UPGRADE 1
#define BODY_TYPE 2
extern BODY_UPGRADE asBodyUpgrade[MAX_PLAYERS][BODY_TYPE];
/* The number of different stats stored */
extern UDWORD numBodyStats;
extern UDWORD numBrainStats;
@ -131,8 +119,6 @@ extern bool statsAllocRepair(UDWORD numEntries);
/*Allocate Construct Stats*/
extern bool statsAllocConstruct(UDWORD numEntries);
extern UWORD weaponROF(WEAPON_STATS *psStat, SBYTE player);
/*******************************************************************************
* Load stats functions
*******************************************************************************/
@ -203,6 +189,7 @@ extern void getStatsDetails(UDWORD compType, BASE_STATS **ppsStats, UDWORD *pnum
extern SDWORD getCompFromResName(UDWORD compType, const char *pName);
/*returns the weapon sub class based on the string name passed in */
extern bool getWeaponSubClass(const char* subClass, WEAPON_SUBCLASS* wclass);
const char *getWeaponSubClass(WEAPON_SUBCLASS wclass);
/*either gets the name associated with the resource (if one) or allocates space and copies pName*/
extern char* allocateName(const char* name);
/*return the name to display for the interface - valid for OBJECTS and STATS*/
@ -246,28 +233,20 @@ extern bool getPropulsionType(const char* typeName, PROPULSION_TYPE* type);
*/
extern const StringToEnumMap<WEAPON_EFFECT> map_WEAPON_EFFECT;
extern UWORD weaponROF(WEAPON_STATS *psStat, SBYTE player);
/*Access functions for the upgradeable stats of a weapon*/
extern UDWORD weaponFirePause(const WEAPON_STATS* psStats, UBYTE player);
extern UDWORD weaponReloadTime(WEAPON_STATS *psStats, UBYTE player);
extern UDWORD weaponShortHit(const WEAPON_STATS* psStats, UBYTE player);
extern UDWORD weaponLongHit(const WEAPON_STATS* psStats, UBYTE player);
extern UDWORD weaponDamage(const WEAPON_STATS* psStats, UBYTE player);
extern UDWORD weaponRadDamage(WEAPON_STATS *psStats, UBYTE player);
extern UDWORD weaponPeriodicalDamage(WEAPON_STATS *psStats, UBYTE player);
extern UDWORD weaponRadiusHit(WEAPON_STATS *psStats, UBYTE player);
/*Access functions for the upgradeable stats of a sensor*/
extern UDWORD sensorRange(SENSOR_STATS *psStats, UBYTE player);
/*Access functions for the upgradeable stats of a ECM*/
extern UDWORD ecmRange(ECM_STATS *psStats, UBYTE player);
/*Access functions for the upgradeable stats of a repair*/
extern UDWORD repairPoints(REPAIR_STATS *psStats, UBYTE player);
/*Access functions for the upgradeable stats of a constructor*/
extern UDWORD constructorPoints(CONSTRUCT_STATS *psStats, UBYTE player);
/*Access functions for the upgradeable stats of a body*/
extern UDWORD bodyPower(BODY_STATS *psStats, UBYTE player, UBYTE bodyType);
extern UDWORD bodyArmour(BODY_STATS *psStats, UBYTE player, UBYTE bodyType,
WEAPON_CLASS weaponClass);
WZ_DECL_PURE int weaponROF(const WEAPON_STATS *psStat, int player);
WZ_DECL_PURE int weaponFirePause(const WEAPON_STATS* psStats, int player);
WZ_DECL_PURE int weaponReloadTime(const WEAPON_STATS *psStats, int player);
WZ_DECL_PURE int weaponShortHit(const WEAPON_STATS* psStats, int player);
WZ_DECL_PURE int weaponLongHit(const WEAPON_STATS* psStats, int player);
WZ_DECL_PURE int weaponDamage(const WEAPON_STATS* psStats, int player);
WZ_DECL_PURE int weaponRadDamage(const WEAPON_STATS *psStats, int player);
WZ_DECL_PURE int weaponPeriodicalDamage(const WEAPON_STATS *psStats, int player);
WZ_DECL_PURE int sensorRange(const SENSOR_STATS *psStats, int player);
WZ_DECL_PURE int ecmRange(const ECM_STATS *psStats, int player);
WZ_DECL_PURE int repairPoints(const REPAIR_STATS *psStats, int player);
WZ_DECL_PURE int constructorPoints(const CONSTRUCT_STATS *psStats, int player);
WZ_DECL_PURE int bodyPower(const BODY_STATS *psStats, int player);
WZ_DECL_PURE int bodyArmour(const BODY_STATS *psStats, int player, WEAPON_CLASS weaponClass);
extern void adjustMaxDesignStats(void);
@ -285,7 +264,7 @@ extern UDWORD getMaxWeaponDamage(void);
extern UDWORD getMaxWeaponROF(void);
extern UDWORD getMaxPropulsionSpeed(void);
extern bool objHasWeapon(const BASE_OBJECT *psObj);
WZ_DECL_PURE bool objHasWeapon(const BASE_OBJECT *psObj);
extern void statsInitVars(void);
@ -295,9 +274,9 @@ bool getWeaponClass(QString weaponClassStr, WEAPON_CLASS *weaponClass);
/* Wrappers */
/** If object is an active radar (has sensor turret), then return a pointer to its sensor stats. If not, return NULL. */
SENSOR_STATS *objActiveRadar(const BASE_OBJECT *psObj);
WZ_DECL_PURE SENSOR_STATS *objActiveRadar(const BASE_OBJECT *psObj);
/** Returns whether object has a radar detector sensor. */
bool objRadarDetector(const BASE_OBJECT *psObj);
WZ_DECL_PURE bool objRadarDetector(const BASE_OBJECT *psObj);
#endif // __INCLUDED_SRC_STATS_H__

View File

@ -408,48 +408,58 @@ struct PROPULSION_STATS : public COMPONENT_STATS
struct SENSOR_STATS : public COMPONENT_STATS
{
UDWORD range; ///< Sensor range
UDWORD power; ///< Sensor power (put against ecm power)
UDWORD location; ///< specifies whether the Sensor is default or for the Turret
SENSOR_TYPE type; ///< used for combat
UDWORD time; ///< time delay before associated weapon droids 'know' where the attack is from
iIMDShape *pMountGraphic; ///< The turret mount to use
struct
{
int range;
} upgrade[MAX_PLAYERS], base;
};
struct ECM_STATS : public COMPONENT_STATS
{
UDWORD range; ///< ECM range
UDWORD location; ///< specifies whether the ECM is default or for the Turret
iIMDShape *pMountGraphic; ///< The turret mount to use
struct
{
int range;
} upgrade[MAX_PLAYERS], base;
};
struct REPAIR_STATS : public COMPONENT_STATS
{
UDWORD repairPoints; ///< How much damage is restored to Body Points and armour each Repair Cycle
bool repairArmour; ///< whether armour can be repaired or not
UDWORD location; ///< specifies whether the Repair is default or for the Turret
UDWORD time; ///< time delay for repair cycle
iIMDShape *pMountGraphic; ///< The turret mount to use
struct
{
short repairPoints; ///< The number of points contributed each cycle
} upgrade[MAX_PLAYERS], base;
};
struct WEAPON_STATS : public COMPONENT_STATS
{
UDWORD longRange; ///< Max distance to target for long range shot
UDWORD minRange; ///< Min distance to target for shot
UDWORD shortHit; ///< Chance to hit at short range
UDWORD longHit; ///< Chance to hit at long range
UDWORD firePause; ///< Time between each weapon fire
UDWORD numExplosions; ///< The number of explosions per shot
UBYTE numRounds; ///< The number of rounds per salvo(magazine)
UDWORD reloadTime; ///< Time to reload the round of ammo (salvo fire)
UDWORD damage; ///< How much damage the weapon causes
UDWORD radius; ///< Basic blast radius of weapon
UDWORD radiusHit; ///< Chance to hit in the blast radius
UDWORD radiusDamage; ///< Damage done in the blast radius
struct
{
short maxRange;
short minRange;
short hitChance;
short firePause; ///< Pause between each shot
short numRounds; ///< The number of rounds per salvo
short reloadTime; ///< Time to reload the round of ammo
short damage;
short radius; ///< Basic blast radius of weapon
short radiusDamage; ///< "Splash damage"
short periodicalDamage; ///< Repeat damage each second after hit
short periodicalDamageRadius; ///< Repeat damage radius
short periodicalDamageTime; ///< How long the round keeps damaging
} base, upgrade[MAX_PLAYERS];
UDWORD periodicalDamageTime; ///< How long the round damages
UDWORD periodicalDamage; ///< Damage done each time cycle (each second)
UDWORD periodicalDamageRadius; ///< Radius of the round
WEAPON_CLASS periodicalDamageWeaponClass; ///< Periodical damage weapon class by damage type (KINETIC, HEAT)
WEAPON_SUBCLASS periodicalDamageWeaponSubClass; ///< Periodical damage weapon subclass (research class)
WEAPON_EFFECT periodicalDamageWeaponEffect; ///< Periodical damage weapon effect (propulsion/body damage modifier)
@ -476,6 +486,7 @@ struct WEAPON_STATS : public COMPONENT_STATS
/* Graphics control stats */
UDWORD radiusLife; ///< How long a blast radius is visible
UDWORD numExplosions; ///< The number of explosions per shot
/* Graphics used for the weapon */
iIMDShape *pMountGraphic; ///< The turret mount to use
@ -493,8 +504,12 @@ struct WEAPON_STATS : public COMPONENT_STATS
struct CONSTRUCT_STATS : public COMPONENT_STATS
{
UDWORD constructPoints; ///< The number of points contributed each cycle
iIMDShape *pMountGraphic; ///< The turret mount to use
struct
{
short constructPoints; ///< The number of points contributed each cycle
} upgrade[MAX_PLAYERS], base;
};
struct BRAIN_STATS : public COMPONENT_STATS
@ -516,13 +531,21 @@ struct BODY_STATS : public COMPONENT_STATS
{
BODY_SIZE size; ///< How big the body is - affects how hit
UDWORD weaponSlots; ///< The number of weapon slots on the body
UDWORD armourValue[WC_NUM_WEAPON_CLASSES]; ///< A measure of how much protection the armour provides. Cross referenced with the weapon types.
DROID_TYPE droidTypeOverride; // if not DROID_ANY, sets droid type
// A measure of how much energy the power plant outputs
UDWORD powerOutput; ///< this is the engine output of the body
iIMDShape **ppIMDList; ///< list of IMDs to use for propulsion unit - up to numPropulsionStats
iIMDShape *pFlameIMD; ///< pointer to which flame graphic to use - for VTOLs only at the moment
char bodyClass[40]; // TBD make into QString once this struct is class-safe
struct
{
int power;
int body;
int armour;
int thermal;
int resistance;
} upgrade[MAX_PLAYERS], base;
};
/************************************************************************************
@ -559,37 +582,4 @@ struct WEAPON_UPGRADE
UWORD radiusHit;
};
/*sensor stats which can be upgraded by research*/
struct SENSOR_UPGRADE
{
UWORD power;
UWORD range;
};
/*ECM stats which can be upgraded by research*/
struct ECM_UPGRADE
{
UDWORD range;
};
/*repair stats which can be upgraded by research*/
struct REPAIR_UPGRADE
{
UWORD repairPoints;
};
/*constructor stats which can be upgraded by research*/
struct CONSTRUCTOR_UPGRADE
{
UWORD constructPoints;
};
/*body stats which can be upgraded by research*/
struct BODY_UPGRADE
{
UWORD powerOutput;
UWORD body;
UWORD armourValue[WC_NUM_WEAPON_CLASSES];
};
#endif // __INCLUDED_STATSDEF_H__

View File

@ -103,11 +103,6 @@
//used to calculate how often to increase the resistance level of a structure
#define RESISTANCE_INTERVAL 2000
//used to calculate the time required for rearming
#define REARM_FACTOR 10
//used to calculate the time required for repairing
#define VTOL_REPAIR_FACTOR 10
//Value is stored for easy access to this structure stat
UDWORD factoryModuleStat;
UDWORD powerModuleStat;
@ -119,17 +114,6 @@ UDWORD numStructureStats;
//holder for the limits of each structure per map
STRUCTURE_LIMITS *asStructLimits[MAX_PLAYERS];
//holds the upgrades attained through research for structure stats
STRUCTURE_UPGRADE asStructureUpgrade[MAX_PLAYERS];
WALLDEFENCE_UPGRADE asWallDefenceUpgrade[MAX_PLAYERS];
//holds the upgrades for the functionality of structures through research
RESEARCH_UPGRADE asResearchUpgrade[MAX_PLAYERS];
POWER_UPGRADE asPowerUpgrade[MAX_PLAYERS];
REPAIR_FACILITY_UPGRADE asRepairFacUpgrade[MAX_PLAYERS];
PRODUCTION_UPGRADE asProductionUpgrade[MAX_PLAYERS][NUM_FACTORY_TYPES];
REARM_UPGRADE asReArmUpgrade[MAX_PLAYERS];
//used to hold the modifiers cross refd by weapon effect and structureStrength
STRUCTSTRENGTH_MODIFIER asStructStrengthModifier[WE_NUMEFFECTS][NUM_STRUCT_STRENGTH];
@ -487,7 +471,29 @@ bool loadStructureStats(QString filename)
// save indexes of special structures for futher use
initModuleStats(inc, psStats->type); // This function looks like a hack. But slightly less hacky than before.
psStats->base.research = ini.value("researchPoints", 0).toInt();
psStats->base.production = ini.value("productionPoints", 0).toInt();
psStats->base.repair = ini.value("repairPoints", 0).toInt();
psStats->base.power = ini.value("powerPoints", 0).toInt();
psStats->base.rearm = ini.value("rearmPoints", 0).toInt();
psStats->base.resistance = ini.value("resistance", 0).toUInt();
psStats->base.hitpoints = ini.value("bodyPoints", 1).toUInt();
psStats->base.armour = ini.value("armour", 0).toUInt();
psStats->base.thermal = ini.value("thermal", 0).toUInt();
for (int i = 0; i < MAX_PLAYERS; i++)
{
psStats->upgrade[i].research = psStats->base.research;
psStats->upgrade[i].power = psStats->base.power;
psStats->upgrade[i].repair = psStats->base.repair;
psStats->upgrade[i].production = psStats->base.production;
psStats->upgrade[i].rearm = psStats->base.rearm;
psStats->upgrade[i].resistance = ini.value("resistance", 0).toUInt();
psStats->upgrade[i].hitpoints = ini.value("bodyPoints", 1).toUInt();
psStats->upgrade[i].armour = ini.value("armour", 0).toUInt();
psStats->upgrade[i].thermal = ini.value("thermal", 0).toUInt();
}
// set structure strength
QString strength = ini.value("strength", "").toString();
ASSERT_OR_RETURN(false, structStrength.contains(strength), "Invalid strength '%s' of structure '%s'", strength.toUtf8().constData(), psStats->pName);
@ -501,12 +507,9 @@ bool loadStructureStats(QString filename)
psStats->baseBreadth = ini.value("baseBreadth", 0).toUInt();
ASSERT_OR_RETURN(false, psStats->baseBreadth < 100, "Invalid baseBreadth '%d' for structure '%s'", psStats->baseBreadth, psStats->pName);
psStats->bodyPoints = ini.value("bodyPoints", 1).toUInt();
psStats->armourValue = ini.value("armour").toUInt();
psStats->height = ini.value("height").toUInt();
psStats->powerToBuild = ini.value("buildPower").toUInt();
psStats->buildPoints = ini.value("buildPoints").toUInt();
psStats->resistance = ini.value("resistance").toUInt();
// set structure models
QStringList models = ini.value("structureModel").toStringList();
@ -557,18 +560,6 @@ bool loadStructureStats(QString filename)
psStats->psWeapStat[j] = pWeap;
}
// set list of functions
QStringList functions = ini.value("functions").toStringList();
psStats->defaultFunc = functions.size() - 1;
for (int j = 0; j < functions.size(); j++)
{
QString functionID = functions[j].trimmed();
FUNCTION *pFunc = findStatsByName(functionID.toUtf8().constData(), asFunctions, numFunctions);
ASSERT_OR_RETURN(false, pFunc, "Invalid item '%s' in list of functions of structure '%s' ", functionID.toUtf8().constData(), psStats->pName);
psStats->asFuncList.push_back(pFunc);
}
// check used structure turrets
int types = 0;
types += psStats->numWeaps != 0;
@ -598,26 +589,6 @@ bool loadStructureStats(QString filename)
}
initStructLimits();
// initialise the structure upgrade arrays
memset(asStructureUpgrade, 0, MAX_PLAYERS * sizeof(STRUCTURE_UPGRADE));
memset(asWallDefenceUpgrade, 0, MAX_PLAYERS * sizeof(WALLDEFENCE_UPGRADE));
memset(asResearchUpgrade, 0, MAX_PLAYERS * sizeof(RESEARCH_UPGRADE));
memset(asPowerUpgrade, 0, MAX_PLAYERS * sizeof(POWER_UPGRADE));
memset(asRepairFacUpgrade, 0, MAX_PLAYERS * sizeof(REPAIR_FACILITY_UPGRADE));
memset(asProductionUpgrade, 0, MAX_PLAYERS * NUM_FACTORY_TYPES * sizeof(PRODUCTION_UPGRADE));
memset(asReArmUpgrade, 0, MAX_PLAYERS * sizeof(REARM_UPGRADE));
// Wall Function requires a structure stat so can allocate it now
for (int i = 0; i < numFunctions; ++i)
{
if (asFunctions[i]->type == WALL_TYPE)
{
WALL_FUNCTION *wallFunction = (WALL_FUNCTION *)asFunctions[i];
wallFunction->pCornerStat = findStatsByName(wallFunction->pStructName, asStructureStats, numStructureStats);
ASSERT_OR_RETURN(false, wallFunction->pCornerStat, "Unknown Corner Wall stat for function %s", wallFunction->pName);
}
}
return true;
}
@ -774,7 +745,7 @@ int32_t structureDamage(STRUCTURE *psStructure, unsigned damage, WEAPON_CLASS we
CHECK_STRUCTURE(psStructure);
debug(LOG_ATTACK, "structure id %d, body %d, armour %d, damage: %d",
psStructure->id, psStructure->body, psStructure->armour[weaponClass], damage);
psStructure->id, psStructure->body, objArmour(psStructure, weaponClass), damage);
relativeDamage = objDamage(psStructure, damage, structureBody(psStructure), weaponClass, weaponSubClass, isDamagePerSecond);
@ -799,7 +770,7 @@ int32_t getStructureDamage(const STRUCTURE *psStructure)
unsigned maxBody = structureBodyBuilt(psStructure);
int64_t health = (int64_t)65536 * psStructure->body / maxBody;
int64_t health = (int64_t)65536 * psStructure->body / MAX(1, maxBody);
CLIP(health, 0, 65536);
return 65536 - health;
@ -1503,10 +1474,6 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
alignStructure(psBuilding);
//set up the sensor stats
objSensorCache(psBuilding, psBuilding->pStructureType->pSensor);
objEcmCache(psBuilding, psBuilding->pStructureType->pECM);
/* Store the weapons */
memset(psBuilding->asWeaps, 0, sizeof(WEAPON));
psBuilding->numWeaps = 0;
@ -1526,7 +1493,7 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
psBuilding->asWeaps[0].lastFired = gameTime;
}
psBuilding->asWeaps[weapon].nStat = pStructureType->psWeapStat[weapon] - asWeaponStats;
psBuilding->asWeaps[weapon].ammo = (asWeaponStats + psBuilding->asWeaps[weapon].nStat)->numRounds;
psBuilding->asWeaps[weapon].ammo = (asWeaponStats + psBuilding->asWeaps[weapon].nStat)->upgrade[psBuilding->player].numRounds;
psBuilding->numWeaps++;
}
}
@ -1543,14 +1510,10 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
psBuilding->asWeaps[0].lastFired = gameTime;
}
psBuilding->asWeaps[0].nStat = pStructureType->psWeapStat[0] - asWeaponStats;
psBuilding->asWeaps[0].ammo = (asWeaponStats + psBuilding->asWeaps[0].nStat)->numRounds;
psBuilding->asWeaps[0].ammo = (asWeaponStats + psBuilding->asWeaps[0].nStat)->upgrade[psBuilding->player].numRounds;
}
}
for (int j = 0; j < WC_NUM_WEAPON_CLASSES; j++)
{
psBuilding->armour[j] = (UWORD)structureArmour(pStructureType, (UBYTE)player);
}
psBuilding->resistance = (UWORD)structureResistance(pStructureType, (UBYTE)player);
psBuilding->lastResistance = ACTION_START_TIME;
@ -1698,9 +1661,6 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
bUpgraded = true;
//put any production on hold
holdProduction(psBuilding, ModeImmediate);
psBuilding->pFunctionality->factory.productionOutput += ((
PRODUCTION_FUNCTION*)pStructureType->asFuncList[0])->productionOutput;
}
}
@ -1717,9 +1677,6 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
bodyDiff = 65536 - getStructureDamage(psBuilding);
psBuilding->capacity++;
psBuilding->pFunctionality->researchFacility.researchPoints += ((
RESEARCH_FUNCTION*)pStructureType->asFuncList[0])->
researchPoints;
bUpgraded = true;
//cancel any research - put on hold now
if (psBuilding->pFunctionality->researchFacility.psSubject)
@ -1748,7 +1705,6 @@ STRUCTURE* buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
//need to inform any res Extr associated that not digging until complete
releasePowerGen(psBuilding);
structurePowerUpgrade(psBuilding);
}
}
if (bUpgraded)
@ -1948,19 +1904,12 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType)
default:
ASSERT_OR_RETURN(false, false, "Invalid factory type");
}
structureProductionUpgrade(psBuilding); // set production output
break;
}
case REF_RESEARCH:
{
structureResearchUpgrade(psBuilding); // set research points
break;
}
case REF_POWER_GEN:
case REF_HQ:
case REF_REARM_PAD:
{
// Take advantage of upgrades
structurePowerUpgrade(psBuilding);
break;
}
case REF_RESOURCE_EXTRACTOR:
@ -1972,11 +1921,6 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType)
psResExtracter->psPowerGen = NULL;
break;
}
case REF_HQ:
{
// If an HQ has just been built make sure the radar is displayed!
break;
}
case REF_REPAIR_FACILITY:
{
REPAIR_FACILITY* psRepairFac = &psBuilding->pFunctionality->repairFacility;
@ -1989,8 +1933,6 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType)
// Add NULL droid to the group
psRepairFac->psGroup->add(NULL);
structureRepairUpgrade(psBuilding); // set repair power
// Create an assembly point for repaired droids
if (!createFlagPosition(&psRepairFac->psDeliveryPoint, psBuilding->player))
{
@ -2010,12 +1952,6 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType)
setFlagPositionInc(psBuilding->pFunctionality, psBuilding->player, REPAIR_FLAG);
break;
}
case REF_REARM_PAD:
{
structureReArmUpgrade(psBuilding); // set rearm points
break;
}
// Structure types without a FUNCTIONALITY
default:
break;
@ -3112,8 +3048,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
//electronic warfare affects the functionality of some structures in multiPlayer
if (bMultiPlayer)
{
if (psStructure->resistance < (SWORD)structureResistance(psStructure->
pStructureType, psStructure->player))
if (psStructure->resistance < structureResistance(psStructure->pStructureType, psStructure->player))
{
return;
}
@ -3127,7 +3062,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
{
pResearch = (RESEARCH *)pSubject;
pointsToAdd = gameTimeAdjustedAverage(psResFacility->researchPoints);
pointsToAdd = gameTimeAdjustedAverage(getBuildingResearchPoints(psStructure));
pointsToAdd = MIN(pointsToAdd, pResearch->researchPoints - pPlayerRes->currentPoints);
if (pointsToAdd > 0 && pPlayerRes->currentPoints == 0)
@ -3207,8 +3142,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
//electronic warfare affects the functionality of some structures in multiPlayer
if (bMultiPlayer)
{
if (psStructure->resistance < (SWORD)structureResistance(psStructure->
pStructureType, psStructure->player))
if (psStructure->resistance < structureResistance(psStructure->pStructureType, psStructure->player))
{
return;
}
@ -3238,7 +3172,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
if (psFactory->buildPointsRemaining > 0)
{
int progress = gameTimeAdjustedAverage(psFactory->productionOutput);
int progress = gameTimeAdjustedAverage(getBuildingProductionPoints(psStructure));
if (psFactory->buildPointsRemaining == psFactory->psSubject->buildPoints && progress > 0)
{
// We're just starting to build, check for power.
@ -3317,17 +3251,14 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
//don't do anything if the resistance is low in multiplayer
if (bMultiPlayer)
{
if (psStructure->resistance < (SWORD)structureResistance(psStructure->
pStructureType, psStructure->player))
if (psStructure->resistance < structureResistance(psStructure->pStructureType, psStructure->player))
{
objTrace(psStructure->id, "Resistance too low for repair");
return;
}
}
// FIXME: duplicate code, make repairing cost power again
/* do repairing */
psDroid->body += gameTimeAdjustedAverage(psRepairFac->power);
psDroid->body += gameTimeAdjustedAverage(getBuildingRepairPoints(psStructure));
}
if (psDroid->body >= psDroid->originalBody)
@ -3387,17 +3318,12 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
//check hasn't died whilst waiting to be rearmed
// also clear out any previously repaired droid
if ( psDroid->died ||
( psDroid->action != DACTION_MOVETOREARMPOINT &&
psDroid->action != DACTION_WAITDURINGREARM ) )
if (psDroid->died || (psDroid->action != DACTION_MOVETOREARMPOINT && psDroid->action != DACTION_WAITDURINGREARM))
{
psReArmPad->psObj = NULL;
return;
}
//if waiting to be rearmed
if ( psDroid->action == DACTION_WAITDURINGREARM &&
psDroid->sMove.Status == MOVEINACTIVE )
if (psDroid->action == DACTION_WAITDURINGREARM && psDroid->sMove.Status == MOVEINACTIVE)
{
if (psReArmPad->timeStarted == ACTION_START_TIME)
{
@ -3405,67 +3331,47 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
psReArmPad->timeStarted = gameTime;
psReArmPad->timeLastUpdated = gameTime;
}
/* do rearming */
UDWORD pointsRequired;
//amount required is a factor of the droids' weight
pointsRequired = psDroid->weight / REARM_FACTOR;
//take numWeaps into consideration
pointsToAdd = psReArmPad->reArmPoints * (gameTime - psReArmPad->timeStarted) / GAME_TICKS_PER_SEC;
pointsAlreadyAdded = psReArmPad->reArmPoints * (psReArmPad->timeLastUpdated - psReArmPad->timeStarted) / GAME_TICKS_PER_SEC;
if (pointsToAdd >= pointsRequired)
pointsToAdd = getBuildingRearmPoints(psStructure) * (gameTime - psReArmPad->timeStarted) / GAME_TICKS_PER_SEC;
pointsAlreadyAdded = getBuildingRearmPoints(psStructure) * (psReArmPad->timeLastUpdated - psReArmPad->timeStarted) / GAME_TICKS_PER_SEC;
if (pointsToAdd >= psDroid->weight) // amount required is a factor of the droid weight
{
// We should be fully loaded by now.
for (i = 0; i < psDroid->numWeaps; i++)
{
// set rearm value to no runs made
psDroid->asWeaps[i].usedAmmo = 0;
// reset ammo and lastFired
psDroid->asWeaps[i].ammo = asWeaponStats[psDroid->asWeaps[i].nStat].numRounds;
psDroid->asWeaps[i].ammo = asWeaponStats[psDroid->asWeaps[i].nStat].upgrade[psDroid->player].numRounds;
psDroid->asWeaps[i].lastFired = 0;
}
}
else
{
for (i = 0; i < psDroid->numWeaps; i++)
for (i = 0; i < psDroid->numWeaps; i++) // rearm one weapon at a time
{
// Make sure it's a rearmable weapon (and so we don't divide by zero)
if (psDroid->asWeaps[i].usedAmmo > 0 && asWeaponStats[psDroid->asWeaps[i].nStat].numRounds > 0)
if (psDroid->asWeaps[i].usedAmmo > 0 && asWeaponStats[psDroid->asWeaps[i].nStat].upgrade[psDroid->player].numRounds > 0)
{
// Do not "simplify" this formula.
// It is written this way to prevent rounding errors.
int ammoToAddThisTime =
pointsToAdd*getNumAttackRuns(psDroid,i)/pointsRequired -
pointsAlreadyAdded*getNumAttackRuns(psDroid,i)/pointsRequired;
pointsToAdd * getNumAttackRuns(psDroid, i) / psDroid->weight -
pointsAlreadyAdded * getNumAttackRuns(psDroid, i) / psDroid->weight;
psDroid->asWeaps[i].usedAmmo -= std::min<unsigned>(ammoToAddThisTime, psDroid->asWeaps[i].usedAmmo);
if (ammoToAddThisTime)
{
// reset ammo and lastFired
psDroid->asWeaps[i].ammo = asWeaponStats[psDroid->asWeaps[i].nStat].numRounds;
psDroid->asWeaps[i].ammo = asWeaponStats[psDroid->asWeaps[i].nStat].upgrade[psDroid->player].numRounds;
psDroid->asWeaps[i].lastFired = 0;
break;
}
}
}
}
/* do repairing */
if (psDroid->body < psDroid->originalBody)
if (psDroid->body < psDroid->originalBody) // do repairs
{
// Do not "simplify" this formula.
// It is written this way to prevent rounding errors.
pointsToAdd = VTOL_REPAIR_FACTOR * (100+asReArmUpgrade[psStructure->player].modifier) * (gameTime -
psReArmPad->timeStarted) / (GAME_TICKS_PER_SEC * 100);
pointsAlreadyAdded = VTOL_REPAIR_FACTOR * (100+asReArmUpgrade[psStructure->player].modifier) * (psReArmPad->timeLastUpdated -
psReArmPad->timeStarted) / (GAME_TICKS_PER_SEC * 100);
if ((pointsToAdd - pointsAlreadyAdded) > 0)
{
psDroid->body += (pointsToAdd - pointsAlreadyAdded);
}
psDroid->body += gameTimeAdjustedAverage(getBuildingRepairPoints(psStructure));
if (psDroid->body >= psDroid->originalBody)
{
/* set droid points to max */
psDroid->body = psDroid->originalBody;
}
}
@ -3722,8 +3628,7 @@ void structureUpdate(STRUCTURE *psBuilding, bool mission)
}
//check the resistance level of the structure
iPointsRequired = structureResistance(psBuilding->pStructureType,
psBuilding->player);
iPointsRequired = structureResistance(psBuilding->pStructureType, psBuilding->player);
if (psBuilding->resistance < (SWORD)iPointsRequired)
{
//start the resistance increase
@ -5566,7 +5471,7 @@ void printStructureInfo(STRUCTURE *psStructure)
{
CONPRINTF(ConsoleString, (ConsoleString, "%s - %d Units assigned - ID %d - sensor range %d - ECM %d",
getStatName(psStructure->pStructureType), countAssignedDroids(psStructure),
psStructure->id, structSensorRange(psStructure), structConcealment(psStructure)));
psStructure->id, structSensorRange(psStructure), structJammerPower(psStructure)));
}
else
#endif
@ -5583,8 +5488,8 @@ void printStructureInfo(STRUCTURE *psStructure)
{
CONPRINTF(ConsoleString, (ConsoleString, "%s - %d Units assigned - ID %d - armour %d|%d - sensor range %d - ECM %d - born %u - depth %.02f",
getStatName(psStructure->pStructureType), countAssignedDroids(psStructure),
psStructure->id, psStructure->armour[WC_KINETIC], psStructure->armour[WC_HEAT],
structSensorRange(psStructure), structConcealment(psStructure), psStructure->born, psStructure->foundationDepth));
psStructure->id, objArmour(psStructure, WC_KINETIC), objArmour(psStructure, WC_HEAT),
structSensorRange(psStructure), structJammerPower(psStructure), psStructure->born, psStructure->foundationDepth));
} else
#endif
if (psStructure->pStructureType->pSensor != NULL
@ -5648,7 +5553,7 @@ void printStructureInfo(STRUCTURE *psStructure)
{
CONPRINTF(ConsoleString, (ConsoleString, "%s - Connected %u of %u - Unique ID %u - Multiplier: %u",
getStatName(psStructure->pStructureType), numConnected, NUM_POWER_MODULES,
psStructure->id, psPowerGen->multiplier));
psStructure->id, getBuildingPowerPoints(psStructure)));
}
else
#endif
@ -5665,7 +5570,7 @@ void printStructureInfo(STRUCTURE *psStructure)
{
CONPRINTF(ConsoleString, (ConsoleString, "%s - Damage % 3.2f%% - Unique ID %u - Production Output: %u - BuildPointsRemaining: %u",
getStatName(psStructure->pStructureType), getStructureDamage(psStructure) * (100.f/65536.f), psStructure->id,
psStructure->pFunctionality->factory.productionOutput,
getBuildingProductionPoints(psStructure),
psStructure->pFunctionality->factory.buildPointsRemaining));
}
else
@ -5681,7 +5586,7 @@ void printStructureInfo(STRUCTURE *psStructure)
{
CONPRINTF(ConsoleString, (ConsoleString, "%s - Damage % 3.2f%% - Unique ID %u - Research Points: %u",
getStatName(psStructure->pStructureType), getStructureDamage(psStructure) * (100.f/65536.f), psStructure->id,
psStructure->pFunctionality->researchFacility.researchPoints));
getBuildingResearchPoints(psStructure)));
}
else
#endif
@ -5796,7 +5701,7 @@ bool electronicDamage(BASE_OBJECT *psTarget, UDWORD damage, UBYTE attackPlayer)
psStructure = (STRUCTURE *)psTarget;
bCompleted = false;
if (psStructure->pStructureType->resistance == 0)
if (psStructure->pStructureType->upgrade[psStructure->player].resistance == 0)
{
return false; // this structure type cannot be taken over
}
@ -5913,7 +5818,7 @@ bool validStructResistance(STRUCTURE *psStruct)
ASSERT_OR_RETURN(false, psStruct != NULL, "Invalid structure pointer");
if (psStruct->pStructureType->resistance != 0)
if (psStruct->pStructureType->upgrade[psStruct->player].resistance != 0)
{
/*certain structures will only provide rewards in multiplayer so
before they can become valid targets their resistance must be at least
@ -5928,8 +5833,7 @@ bool validStructResistance(STRUCTURE *psStruct)
case REF_CYBORG_FACTORY:
case REF_HQ:
case REF_REPAIR_FACILITY:
if (psStruct->resistance >= (SDWORD) (structureResistance(psStruct->
pStructureType, psStruct->player) / 2))
if (psStruct->resistance >= structureResistance(psStruct->pStructureType, psStruct->player) / 2)
{
bTarget = true;
}
@ -5965,115 +5869,17 @@ unsigned structureBodyBuilt(STRUCTURE const *psStructure)
/*Access functions for the upgradeable stats of a structure*/
UDWORD structureBody(const STRUCTURE *psStructure)
{
const STRUCTURE_STATS *psStats = psStructure->pStructureType;
const UBYTE player = psStructure->player;
switch(psStats->type)
{
// wall/defence structures:
case REF_DEFENSE:
case REF_WALL:
case REF_WALLCORNER:
case REF_GATE:
case REF_BLASTDOOR:
return psStats->bodyPoints + (psStats->bodyPoints * asWallDefenceUpgrade[player].body)/100;
// all other structures:
default:
return structureBaseBody(psStructure) + (structureBaseBody(psStructure) * asStructureUpgrade[player].body)/100;
}
return psStructure->pStructureType->upgrade[psStructure->player].hitpoints;
}
/*this returns the Base Body points of a structure - regardless of upgrade*/
UDWORD structureBaseBody(const STRUCTURE *psStructure)
{
const STRUCTURE_STATS *psStats = psStructure->pStructureType;
ASSERT_OR_RETURN(0, psStructure != NULL, "Invalid structure pointer");
switch(psStats->type)
{
// modules may be attached:
case REF_FACTORY:
case REF_VTOL_FACTORY:
ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for factory base body");
if (psStructure->capacity > 0)
{
//add on the default for the factory
return psStats->bodyPoints + asStructureStats[factoryModuleStat].bodyPoints * psStructure->capacity;
}
else
{
//no modules
return psStats->bodyPoints;
}
case REF_RESEARCH:
ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for research base body");
if (psStructure->capacity > 0)
{
//add on the default for the factory
return psStats->bodyPoints + asStructureStats[researchModuleStat].bodyPoints;
}
else
{
//no modules
return psStats->bodyPoints;
}
case REF_POWER_GEN:
ASSERT_OR_RETURN(0, psStructure->pFunctionality != NULL, "Invalid structure functionality pointer for power gen base body");
if (psStructure->capacity > 0)
{
//add on the default for the factory
return psStats->bodyPoints + asStructureStats[powerModuleStat].bodyPoints;
}
else
{
//no modules
return psStats->bodyPoints;
}
// all other structures:
default:
return psStats->bodyPoints;
}
}
UDWORD structureArmour(STRUCTURE_STATS *psStats, UBYTE player)
{
switch(psStats->type)
{
case REF_DEFENSE:
case REF_WALL:
case REF_WALLCORNER:
case REF_GATE:
case REF_BLASTDOOR:
return (psStats->armourValue + (psStats->armourValue *
asWallDefenceUpgrade[player].armour)/100);
break;
default:
return (psStats->armourValue + (psStats->armourValue *
asStructureUpgrade[player].armour)/100);
break;
}
return psStats->upgrade[player].armour;
}
UDWORD structureResistance(STRUCTURE_STATS *psStats, UBYTE player)
{
switch(psStats->type)
{
case REF_WALL:
case REF_GATE:
case REF_WALLCORNER:
case REF_BLASTDOOR:
//not upgradeable
return psStats->resistance;
break;
default:
return (psStats->resistance + (psStats->resistance *
asStructureUpgrade[player].resistance)/100);
break;
}
return psStats->upgrade[player].resistance;
}
@ -7136,8 +6942,7 @@ STRUCTURE * giftSingleStructure(STRUCTURE *psStructure, UBYTE attackPlayer, bool
psStructure->player = (UBYTE)attackPlayer;
//restore the resistance value
psStructure->resistance = (UWORD)structureResistance(psStructure->
pStructureType, psStructure->player);
psStructure->resistance = (UWORD)structureResistance(psStructure->pStructureType, psStructure->player);
// add to other list.
addStructure(psStructure);
@ -7280,25 +7085,6 @@ STRUCTURE * giftSingleStructure(STRUCTURE *psStructure, UBYTE attackPlayer, bool
return psNewStruct;
}
/*checks that the structure stats have loaded up as expected - must be done after
all StructureStats parts have been loaded*/
bool checkStructureStats(void)
{
UDWORD structInc, inc;
for (structInc=0; structInc < numStructureStats; structInc++)
{
for (inc = 0; inc < asStructureStats[structInc].asFuncList.size(); inc++)
{
ASSERT_OR_RETURN(false, asStructureStats[structInc].asFuncList[inc] != NULL, "Invalid function for structure %s", asStructureStats[structInc].pName);
}
}
return true;
}
/*returns the power cost to build this structure*/
UDWORD structPowerToBuild(const STRUCTURE* psStruct)
{

View File

@ -45,8 +45,6 @@
/*This should correspond to the structLimits! */
#define MAX_FACTORY 5
//used to flag when the Factory is ready to start building
#define ACTION_START_TIME 0
@ -67,20 +65,10 @@ extern SBYTE productionPlayer;
extern STRUCTURE_STATS *asStructureStats;
extern UDWORD numStructureStats;
extern STRUCTURE_LIMITS *asStructLimits[MAX_PLAYERS];
//holds the upgrades attained through research for structure stats
extern STRUCTURE_UPGRADE asStructureUpgrade[MAX_PLAYERS];
extern WALLDEFENCE_UPGRADE asWallDefenceUpgrade[MAX_PLAYERS];
//holds the upgrades for the functionality of structures through research
extern RESEARCH_UPGRADE asResearchUpgrade[MAX_PLAYERS];
extern POWER_UPGRADE asPowerUpgrade[MAX_PLAYERS];
extern REPAIR_FACILITY_UPGRADE asRepairFacUpgrade[MAX_PLAYERS];
extern PRODUCTION_UPGRADE asProductionUpgrade[MAX_PLAYERS][NUM_FACTORY_TYPES];
extern REARM_UPGRADE asReArmUpgrade[MAX_PLAYERS];
//used to hold the modifiers cross refd by weapon effect and structureStrength
extern STRUCTSTRENGTH_MODIFIER asStructStrengthModifier[WE_NUMEFFECTS][
NUM_STRUCT_STRENGTH];
extern void handleAbandonedStructures(void);
int getMaxDroids(int player);
@ -266,8 +254,6 @@ unsigned structureBodyBuilt(STRUCTURE const *psStruct); ///< Returns the maximu
extern UDWORD structureBody(const STRUCTURE *psStruct);
extern UDWORD structureArmour(STRUCTURE_STATS *psStats, UBYTE player);
extern UDWORD structureResistance(STRUCTURE_STATS *psStats, UBYTE player);
/*this returns the Base Body points of a structure - regardless of upgrade*/
extern UDWORD structureBaseBody(const STRUCTURE *psStructure);
extern void hqReward(UBYTE losingPlayer, UBYTE rewardPlayer);
@ -375,10 +361,6 @@ bool IsStatExpansionModule(STRUCTURE_STATS const *psStats);
bool structureIsBlueprint(STRUCTURE *psStructure);
bool isBlueprint(BASE_OBJECT *psObject);
/*checks that the structure stats have loaded up as expected - must be done after
all StructureStats parts have been loaded*/
extern bool checkStructureStats(void);
/*returns the power cost to build this structure*/
extern UDWORD structPowerToBuild(const STRUCTURE* psStruct);
@ -413,11 +395,6 @@ static inline int structJammerPower(const STRUCTURE* psObj)
return objJammerPower((const BASE_OBJECT*)psObj);
}
static inline int structConcealment(const STRUCTURE* psObj)
{
return objConcealment((const BASE_OBJECT*)psObj);
}
static inline Rotation structureGetInterpolatedWeaponRotation(STRUCTURE *psStructure, int weaponSlot, uint32_t time)
{
return interpolateRot(psStructure->asWeaps[weaponSlot].prevRot, psStructure->asWeaps[weaponSlot].rot, psStructure->prevTime, psStructure->time, time);
@ -514,5 +491,30 @@ static inline STRUCTURE *castStructure(SIMPLE_OBJECT *psObject) { re
// Returns STRUCTURE const * if structure or NULL if not.
static inline STRUCTURE const *castStructure(SIMPLE_OBJECT const *psObject) { return isStructure(psObject)? (STRUCTURE const *)psObject : (STRUCTURE const *)NULL; }
static inline int getBuildingResearchPoints(STRUCTURE *psStruct)
{
return psStruct->pStructureType->upgrade[psStruct->player].research * (psStruct->capacity + 1);
}
static inline int getBuildingProductionPoints(STRUCTURE *psStruct)
{
return psStruct->pStructureType->upgrade[psStruct->player].production * (psStruct->capacity + 1);
}
static inline int getBuildingPowerPoints(STRUCTURE *psStruct)
{
int power = psStruct->pStructureType->upgrade[psStruct->player].power;
return power + power * psStruct->capacity / 2;
}
static inline int getBuildingRepairPoints(STRUCTURE *psStruct)
{
return psStruct->pStructureType->upgrade[psStruct->player].repair;
}
static inline int getBuildingRearmPoints(STRUCTURE *psStruct)
{
return psStruct->pStructureType->upgrade[psStruct->player].rearm;
}
#endif // __INCLUDED_SRC_STRUCTURE_H__

View File

@ -113,14 +113,7 @@ struct STRUCTURE_STATS : public BASE_STATS
the structure*/
UDWORD height; /*The height above/below the terrain - negative
values denote below the terrain*/
UDWORD armourValue; /*The armour value for the structure - can be
upgraded */
UDWORD bodyPoints; /*The structure's body points - A structure goes
off-line when 50% of its body points are lost*/
UDWORD powerToBuild; /*How much power the structure requires to build*/
UDWORD resistance; /*The number used to determine whether a
structure can resist an enemy takeover -
0 = cannot be attacked electrically*/
std::vector<iIMDShape *> pIMD; // The IMDs to draw for this structure, for each possible number of modules.
iIMDShape *pBaseIMD; /*The base IMD to draw for this structure */
struct ECM_STATS *pECM; /*Which ECM is standard for the structure -
@ -133,8 +126,18 @@ struct STRUCTURE_STATS : public BASE_STATS
struct WEAPON_STATS *psWeapStat[STRUCT_MAXWEAPS];
SDWORD defaultFunc; /*The default function*/
std::vector<struct FUNCTION *> asFuncList; ///< List of pointers to allowable functions - unalterable
struct
{
short research;
short repair;
short power;
short production;
short rearm;
short armour;
short thermal;
short hitpoints;
short resistance; // resist enemy takeover; 0 = immune
} upgrade[MAX_PLAYERS], base;
};
enum STRUCT_STATES
@ -163,7 +166,6 @@ struct RESEARCH_FACILITY
RESEARCH * psSubjectPending; // The subject the structure is going to work on when the GAME_RESEARCHSTATUS message is received.
StatusPending statusPending; ///< Pending = not yet synchronised.
unsigned pendingCount; ///< Number of messages sent but not yet processed.
UDWORD researchPoints; /* Research Points produced per research cycle*/
RESEARCH * psBestTopic; // The topic with the most research points that was last performed
UDWORD timeStartHold; /* The time the research facility was put on hold*/
};
@ -174,8 +176,6 @@ struct FACTORY
{
uint8_t productionLoops; ///< Number of loops to perform. Not synchronised, and only meaningful for selectedPlayer.
UBYTE loopsPerformed; /* how many times the loop has been performed*/
int productionOutput; /* Droid Build Points Produced Per
Build Cycle*/
DROID_TEMPLATE * psSubject; ///< The subject the structure is working on.
DROID_TEMPLATE * psSubjectPending; ///< The subject the structure is going to working on. (Pending = not yet synchronised.)
StatusPending statusPending; ///< Pending = not yet synchronised.
@ -197,7 +197,6 @@ struct RES_EXTRACTOR
struct POWER_GEN
{
UDWORD multiplier; ///< Factor to multiply output by - percentage
struct STRUCTURE * apResExtractors[NUM_POWER_MODULES]; ///< Pointers to associated oil derricks
};
@ -205,7 +204,6 @@ class DROID_GROUP;
struct REPAIR_FACILITY
{
UDWORD power; // Repair rate. Nothing to do with power.
BASE_OBJECT *psObj; /* Object being repaired */
FLAG_POSITION *psDeliveryPoint; /* Place for the repaired droids to assemble at */
@ -216,7 +214,6 @@ struct REPAIR_FACILITY
struct REARM_PAD
{
UDWORD reArmPoints; /* rearm points per cycle */
UDWORD timeStarted; /* Time reArm started on current object */
BASE_OBJECT *psObj; /* Object being rearmed */
UDWORD timeLastUpdated; /* Time rearm was last updated */
@ -324,28 +321,11 @@ struct ProductionRunEntry
};
typedef std::vector<ProductionRunEntry> ProductionRun;
/* structure stats which can be upgraded by research*/
struct STRUCTURE_UPGRADE
{
UWORD armour;
UWORD body;
UWORD resistance;
};
/* wall/Defence structure stats which can be upgraded by research*/
struct WALLDEFENCE_UPGRADE
{
UWORD armour;
UWORD body;
};
struct UPGRADE
{
UWORD modifier; //% to increase the stat by
};
typedef UPGRADE RESEARCH_UPGRADE;
typedef UPGRADE PRODUCTION_UPGRADE;
typedef UPGRADE REPAIR_FACILITY_UPGRADE;
typedef UPGRADE POWER_UPGRADE;
typedef UPGRADE REARM_UPGRADE;

View File

@ -498,7 +498,7 @@ static void processVisibilitySelf(BASE_OBJECT *psObj)
{
int viewer;
if (psObj->type != OBJ_FEATURE && psObj->sensorRange > 0)
if (psObj->type != OBJ_FEATURE && objSensorRange(psObj) > 0)
{
// one can trivially see oneself
setSeenBy(psObj, psObj->player, UBYTE_MAX);
@ -545,7 +545,7 @@ static void processVisibilityVision(BASE_OBJECT *psViewer)
// get all the objects from the grid the droid is in
// Will give inconsistent results if hasSharedVision is not an equivalence relation.
static GridList gridList; // static to avoid allocations.
gridList = gridStartIterateUnseen(psViewer->pos.x, psViewer->pos.y, psViewer->sensorRange, psViewer->player);
gridList = gridStartIterateUnseen(psViewer->pos.x, psViewer->pos.y, objSensorRange(psViewer), psViewer->player);
for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi)
{
BASE_OBJECT *psObj = *gi;
@ -769,7 +769,7 @@ bool lineOfFire(const SIMPLE_OBJECT* psViewer, const BASE_OBJECT* psTarget, int
}
// 2d distance
int distance = iHypot(removeZ(psTarget->pos - psViewer->pos));
int range = proj_GetLongRange(psStats);
int range = proj_GetLongRange(psStats, psViewer->player);
if (proj_Direct(psStats))
{
/** direct shots could collide with ground **/
@ -971,32 +971,3 @@ static int checkFireLine(const SIMPLE_OBJECT* psViewer, const BASE_OBJECT* psTar
}
}
void objSensorCache(BASE_OBJECT *psObj, SENSOR_STATS *psSensor)
{
if (psSensor)
{
psObj->sensorRange = sensorRange(psSensor, psObj->player);
}
else if (psObj->type == OBJ_DROID || psObj->type == OBJ_STRUCTURE)
{
// Give them the default sensor if not
psObj->sensorRange = sensorRange(asSensorStats + aDefaultSensor[psObj->player], psObj->player);
}
else
{
psObj->sensorRange = 0;
}
}
void objEcmCache(BASE_OBJECT *psObj, ECM_STATS *psEcm)
{
if (psEcm)
{
psObj->ECMMod = ecmRange(psEcm, psObj->player);
}
else
{
psObj->ECMMod = 0;
}
}

View File

@ -23,6 +23,7 @@
#include "objectdef.h"
#include "raycast.h"
#include "stats.h"
#define LINE_OF_FIRE_MINIMUM 5
@ -75,20 +76,28 @@ static inline bool visObjInRange(BASE_OBJECT *psObj1, BASE_OBJECT *psObj2, SDWOR
static inline int objSensorRange(const BASE_OBJECT* psObj)
{
return psObj->sensorRange;
if (psObj->type == OBJ_DROID)
{
return asSensorStats[((DROID*)psObj)->asBits[COMP_SENSOR].nStat].upgrade[psObj->player].range;
}
else if (psObj->type == OBJ_STRUCTURE)
{
return ((STRUCTURE *)psObj)->pStructureType->pSensor->upgrade[psObj->player].range;
}
return 0;
}
static inline int objJammerPower(const BASE_OBJECT* psObj)
{
return psObj->ECMMod;
if (psObj->type == OBJ_DROID)
{
return asECMStats[((DROID*)psObj)->asBits[COMP_ECM].nStat].upgrade[psObj->player].range;
}
else if (psObj->type == OBJ_STRUCTURE)
{
return ((STRUCTURE*)psObj)->pStructureType->pECM->upgrade[psObj->player].range;
}
return 0;
}
static inline int objConcealment(const BASE_OBJECT* psObj)
{
return psObj->ECMMod;
}
void objSensorCache(BASE_OBJECT *psObj, SENSOR_STATS *psSensor);
void objEcmCache(BASE_OBJECT *psObj, ECM_STATS *psEcm);
#endif // __INCLUDED_SRC_VISIBILITY__