Under no circumstances should the burn duration of the flamethrower be random. Introducing a random element with such a wide range of outcomes can cause drastically divergent gameplay.
There is no reason for it to not be a set duration. Make it five second or ten seconds or whatever, but make it static.
if they really want the it to be based on a percent per sec they could set the per trial probability so that it equals out to the intent of kStopFireProbability.
@hyperrift: that's definitely the classic (and reliable) way of doing things.
One thing to consider though is that gorge spray is supposed to put out flames. <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//SpitSpray.lua function SpitSpray:HealEntities(player) if isHealPlayer then // Put out entities on fire targetEntity:SetGameEffectMask(kGameEffect.OnFire, false)<!--c2--></div><!--ec2-->
<!--quoteo(post=1823337:date=Jan 12 2011, 03:08 AM:name=jbaker8935)--><div class='quotetop'>QUOTE (jbaker8935 @ Jan 12 2011, 03:08 AM) <a href="index.php?act=findpost&pid=1823337"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->if they really want the it to be based on a percent per sec they could set the per trial probability so that it equals out to the intent of kStopFireProbability.
i think i got this right. ie. n trials for a sec would equal the kStopFireProbability<!--QuoteEnd--></div><!--QuoteEEnd--> Yeah that works out right. = 0.047586204 Doing the linear interpolation between 0.9 and 1.2 seconds (trials 3 and 4) for 1 second, yields a chance very close to 0.15. But that still yields a static stopFireChance, which still leads to a non-linear cumulative chance... So at 3 seconds, for example, it isn't a 45% chance, it's a 38.6% chance. But if that's okay, then that's okay. <img src="http://img841.imageshack.us/img841/5475/ns2burningputoutchance2.png" border="0" class="linked-image" />
<!--quoteo(post=1823335:date=Jan 11 2011, 02:43 PM:name=hyperrift)--><div class='quotetop'>QUOTE (hyperrift @ Jan 11 2011, 02:43 PM) <a href="index.php?act=findpost&pid=1823335"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Under no circumstances should the burn duration of the flamethrower be random. Introducing a random element with such a wide range of outcomes can cause drastically divergent gameplay.
There is no reason for it to not be a set duration. Make it five second or ten seconds or whatever, but make it static.<!--QuoteEnd--></div><!--QuoteEEnd-->
I have to agree on this. I'm a big TF2 fan, and the pyro's flamethrower will keep a victim burning for the same amount of time. (or similar at least - I've never timed it, but it's never gone on and on forever or ended really fast) A player on fire generally can tell if they're in danger of dying from the burn or not. If they're not in danger, they can continue play and not worry about feeling cheated that they just kept burning. If they know they're in trouble, it adds a fun layer of urgency trying to find a method to put the fire out. (water, health pack, medic, a friendly airblast, jarate, whatever)
Let the player know what to expect, don't randomly pull the rug out from under them. It's not fun, and you can't "learn" a good consistent response fire except to panic and hope you don't die this time.
McGlaspiewww.team156.comJoin Date: 2010-07-26Member: 73044Members, Super Administrators, Forum Admins, NS2 Developer, NS2 Playtester, Squad Five Blue, Squad Five Silver, Squad Five Gold, Reinforced - Onos, WC 2013 - Gold, Subnautica Playtester
edited January 2011
After glancing at the source code, the following comment just makes me cringe:
"// See if we catch anyone else on fire"
Even with correcting the burn time issue, having things catch other things on fire would be insane. FT would completely cancel out Hydras and make it dangerous for alien players to "run back to base to heal". I hope I'm just being pessimistic.
It's always been a feature under consideration. But that's why they've put it under comments. If they decide to try it, they just need to remove the commenting. There are a number of other features that are 'done', but disabled like this (as well as features that are planned but incomplete).
<!--quoteo(post=1823338:date=Jan 11 2011, 02:08 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 11 2011, 02:08 PM) <a href="index.php?act=findpost&pid=1823338"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Yeah that works out right. = 0.047586204 Doing the linear interpolation between 0.9 and 1.2 seconds (trials 3 and 4) for 1 second, yields a chance very close to 0.15. But that still yields a static stopFireChance, which still leads to a non-linear cumulative chance... So at 3 seconds, for example, it isn't a 45% chance, it's a 38.6% chance. But if that's okay, then that's okay.<!--QuoteEnd--></div><!--QuoteEEnd-->
right. it only helps making the tuning more accurate (ie you could change the effects interval without impacting outcome). the usual cumulative probability formula applies.
<!--quoteo(post=1823278:date=Jan 11 2011, 07:10 AM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 11 2011, 07:10 AM) <a href="index.php?act=findpost&pid=1823278"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Well, each hydra does do the following actions each think. <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->OnThink -> AcquireTarget -> GetSortedTargetList -> GetTargetValid -> AttackTarget -> CreateSpikeProjectile -> [...] -> OR Alert -> GetIsEnemyNearby -> SetNextThink<!--c2--></div><!--ec2--> GetSortedTargetList seems the most intensive, but the origin and the range are put into the function from the beginning, so it shouldn't be scanning everything on the map. There are a few instances (33, so relatively few) in the code of "GetGamerules():GetEntities(arguments)", but I can't figure out how they work as I can't find the function "GetEntities(arguments)". The closest is "GetEntitiesIsA(arguments)", and I wonder why the hydra doesn't use the function "GetEntitiesIsAInRadius(arguments)", as the arguments match: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Entity.lua function GetEntitiesIsaInRadius(className, teamNumber, origin, radius, checkXZOnly, visibleOnly, log)
//Hydra_Server.lua function Hydra:GetSortedTargetList() local targets = GetGamerules():GetEntities("LiveScriptActor", GetEnemyTeamNumber(self:GetTeamNumber()), hydraAttackOrigin, Hydra.kRange)<!--c2--></div><!--ec2--> It's the same case for sentries, as well. Could this be the source of the problem, or are my searching skills not enough? I figure if it weren't working, hydras and sentries wouldn't work at all though, so I don't know... :/ Unless it's managing to scan every target on the map regardless...<!--QuoteEnd--></div><!--QuoteEEnd-->
I just had another look at this, I see what you mean, the function doesn't exist as far as i can see. I checked all the logical lua files and i can't find it. I went to GetGamerules() and then followed that to Entity which then was referring to GetEntitiesIsa("..."). The variables are slightly different as well as if they are meant to be passing the intended thing but theres nothing linking them together.
Totally agree though, if it was broken i wouldn't be having my ass handed to me when i walk around corners in game.
Would be interested what the team say..
<!--quoteo(post=1823352:date=Jan 11 2011, 07:58 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 11 2011, 07:58 PM) <a href="index.php?act=findpost&pid=1823352"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->It's always been a feature under consideration. But that's why they've put it under comments. If they decide to try it, they just need to remove the commenting. There are a number of other features that are 'done', but disabled like this (as well as features that are planned but incomplete).<!--QuoteEnd--></div><!--QuoteEEnd-->
I think that's the beauty of adding new features like this, you can tinker or totally remove them. It's not like NS1 failed without a FT.
<!--quoteo(post=1823374:date=Jan 12 2011, 05:28 AM:name=jbaker8935)--><div class='quotetop'>QUOTE (jbaker8935 @ Jan 12 2011, 05:28 AM) <a href="index.php?act=findpost&pid=1823374"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->right. it only helps making the tuning more accurate (ie you could change the effects interval without impacting outcome). the usual cumulative probability formula applies.<!--QuoteEnd--></div><!--QuoteEEnd--> Yeah, that makes sense. It's a good approach.
<!--quoteo(post=1823406:date=Jan 12 2011, 08:05 AM:name=Slickk-)--><div class='quotetop'>QUOTE (Slickk- @ Jan 12 2011, 08:05 AM) <a href="index.php?act=findpost&pid=1823406"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I just had another look at this, I see what you mean, the function doesn't exist as far as i can see. I checked all the logical lua files and i can't find it. I went to GetGamerules() and then followed that to Entity which then was referring to GetEntitiesIsa("..."). The variables are slightly different as well as if they are meant to be passing the intended thing but theres nothing linking them together.
Totally agree though, if it was broken i wouldn't be having my ass handed to me when i walk around corners in game.
Would be interested what the team say..<!--QuoteEnd--></div><!--QuoteEEnd--> I'd definitely like to get a comment on this.
<!--quoteo(post=1823415:date=Jan 12 2011, 09:06 AM:name=MOOtant)--><div class='quotetop'>QUOTE (MOOtant @ Jan 12 2011, 09:06 AM) <a href="index.php?act=findpost&pid=1823415"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Less tables more graphs, please.<!--QuoteEnd--></div><!--QuoteEEnd--> Tables are better for raw values, graphs are good for looking at comparisons, and local and global trends. I could always label relevant data points though. I'll definitely consider it.
Ahh, I see how it works. Shared.lua loads NS2Gamerules.lua; GetGameRules() in Gamerules_Global.lua checks for the installed gamerules, or else uses the default: Gamerules.lua. So whenever it uses GetGameRules():GetEntities(), it's using the GetEntities function from NS2Gamerules.lua.
You cant spent res if you only got the exact amount to buy the thing you wish... you have to wait until you get +1 res.
Example, I got 5 res and want to upgrade a Res Tower... => Not possible until i got at least 6 res. even tho it only costs 5res... I dont think thats the way it should be...
I never liked the parasite + 2 bites mechanic in NS1. It was a quick fix to early game balance problems that unfairly punished newer players that didn't know the trick. IMO parasite shouldn't be a combat tool, it should only be used for its actual purpose: tracking marines.
Koruyo: Retracted. I had a theory, realised it was wrong as the code should actually be working with those operators. So my new theory is that it's displaying the wrong amount of carbon available. Haven't checked this, but it seems most likely.
See: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Commander_Server.lua // Handle tech tree actions that cost carbon if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsBuild() or techNode:GetIsEnergyBuild()) then local costsEnergy = techNode:GetIsEnergyBuild() local teamCarbon = team:GetCarbon() local energy = entity:GetEnergy() if (not costsEnergy and cost <= teamCarbon) or (costsEnergy and cost <= energy) then [...] else self:TriggerNotEnoughResourcesAlert() end
// Handle plasma-based abilities elseif(techNode:GetIsAction() or techNode:GetIsBuy()) then local playerPlasma = self:GetPlasma() if(cost == nil or cost <= playerPlasma) then [...] else self:TriggerNotEnoughResourcesAlert() end [...] end<!--c2--></div><!--ec2--> Personally I would have used teamCarbon >= cost, and playerPlasma >= cost, as it's more intuitive, but it shouldn't make a difference, I don't think.
I'm still stumped as to how <b>different things</b> are specified as costing carbon, energy or plasma. I've been searching but I can't find it. I've been searching mostly in regards to the 20 <b>Carbon</b> cost of the Sentry - I know that not everything costs Carbon as commander (which was one theory as to how it might be broken, if it is indeed broken), because the energy costs of MACs still works as it should. So far I can only figure out resource requirements, and subtracting from resources (given a resource type, or action type). The actual resource type (e.g. Carbon) or action type (e.g. GetIsBuild()) for an item still eludes me.
Is "nil" the same as "0" in lua, or are they different concepts?
<!--quoteo(post=1823867:date=Jan 13 2011, 02:44 PM:name=Zek)--><div class='quotetop'>QUOTE (Zek @ Jan 13 2011, 02:44 PM) <a href="index.php?act=findpost&pid=1823867"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I never liked the parasite + 2 bites mechanic in NS1. It was a quick fix to early game balance problems that unfairly punished newer players that didn't know the trick. IMO parasite shouldn't be a combat tool, it should only be used for its actual purpose: tracking marines.<!--QuoteEnd--></div><!--QuoteEEnd--> Death to parasite (<b>after</b> two bites) is utter humiliation, though. It <b>has</b> to be that way. :P
PlasmaJoin Date: 2003-04-26Member: 15855Members, Constellation, Squad Five Blue
Harimau, I wonder if its just rounding - I think you get partial resources (eg 0.1?) every few seconds, perhaps something is rounded on the UI (rounded up) when you don't really have 20 res, you may really have 19.7 res at that very moment.
That's actually what I was thinking. So in his case, where it said he had "5" res, maybe he had 4.9 (rounds up to 5), and when he had "6" res, maybe he had 5.1 (rounds up to 6). Just as an example. The obvious solution, then, is just to round down instead.
Edit: Yep. No idea. The game adds 1 (whole) carbon every 12 seconds (length of the update interval), per resource tower, beginning 4 seconds after the resource tower is built. Basically, there's no rounding involved, so there's no issue with rounding. It's plain and simple addition.
For those who are interested in the relevant code (I worked backwards, so that's why the order is reversed): <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//GUIResourceDisplay.lua function GUICommanderManager:CreateResourceDisplay() local settingsTable = { } settingsTable.Width = GUICommanderManager.kResourceDisplayWidth settingsTable.BackgroundAnchorX = GUIItem.Middle settingsTable.BackgroundAnchorY = GUIItem.Top settingsTable.X = -settingsTable.Width / 2 settingsTable.Y = GUICommanderManager.kResourceDisplayOffset self.resourceDisplay = GUIResourceDisplay() self.resourceDisplay:Initialize(settingsTable) end
//Player_Server.lua function GUIResourceDisplay:Update(deltaTime) self.plasmaText:SetText(ToString(PlayerUI_GetPlayerResources())) self.carbonText:SetText(ToString(PlayerUI_GetTeamResources())) self.towerText:SetText(ToString(CommanderUI_GetTeamHarvesterCount())) end
//Player.lua function PlayerUI_GetTeamResources() local player = Client.GetLocalPlayer() if player then return player:GetDisplayTeamCarbon() end return 0 end
function Player:GetDisplayTeamCarbon() local displayTeamCarbon = self.teamCarbon if(Client and self.resourceDisplay) then displayTeamCarbon = self.animatedCarbonDisplay:GetDisplayValue() end return displayTeamCarbon
end
function Player:AddCarbon(amount) self.teamCarbon = math.max(math.min(self.teamCarbon + amount, kMaxResources), 0) end
//ResourceTower_Server.lua function ResourceTower:UpdateOnThink() ... if(team ~= nil) then team:AddCarbon(ResourceTower.kCarbonInjection) end ... end
function ResourceTower:GetUpdateInterval() return kResourceTowerResourceInterval end
function ResourceTower:OnThink() if self:GetIsBuilt() and self:GetIsAlive() and (self:GetAttached() ~= nil) and self:GetIsActive() and (self:GetAttached():GetAttached() == self) and GetGamerules():GetGameStarted() then self:UpdateOnThink() end Structure.OnThink(self) self:SetNextThink(self:GetUpdateInterval())
end
function ResourceTower:OnConstructionComplete() Structure.OnConstructionComplete(self) self:SetNextThink(ResourceTower.kBuildDelay) end
Regarding the above post, could there be a mismatch between what the server and client displays? (Confirmations always go through the server though.)
Just adding the backlog. Discuss.
<u>Resource Usage (Different Types)</u> All buttons are 'tech nodes' Press a button, For example, tracking the carbon cost of a sentry... <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// using: //TechTree_Server.lua function TechTree:AddBuildNode(techId, prereq1, prereq2) local techNode = TechNode() techNode:Initialize(techId, kTechType.Build, prereq1, prereq2) techNode.requiresTarget = true self:AddNode(techNode) end // so: //MarineTeam.lua self.techTree:AddBuildNode(kTechId.Sentry, kTechId.None, kTechId.None) // reads techId (specified), and prereqs, then // initialises kTechType.Build (specifies buildable) as well as techId, and prereqs // then using: Technode.lua function TechNode:GetIsBuild() return self.techType == kTechType.Build end // returns "true" if techtype is a buildable // so: //Commander_Server.lua // Handle tech tree actions that cost carbon if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsBuild() or techNode:GetIsEnergyBuild()) then local costsEnergy = techNode:GetIsEnergyBuild() local teamCarbon = team:GetCarbon() local energy = entity:GetEnergy() if (not costsEnergy and cost <= teamCarbon) or (costsEnergy and cost <= energy) then if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsEnergyBuild()) then success = self:AttemptToResearchOrUpgrade(techNode, force) if success then keepProcessing = false end elseif(techNode:GetIsBuild()) then success = self:AttemptToBuild(techId, position, pickVec, false) if success then keepProcessing = false end end if success then if costsEnergy then entity:SetEnergy(entity:GetEnergy() - cost) else team:AddCarbon(-cost) end Shared.PlayPrivateSound(self, Commander.kSpendCarbonSoundName, nil, 1.0, self:GetOrigin()) end else self:TriggerNotEnoughResourcesAlert() end // checks if research, upgrade, buildable or energy buildable // checks if enough carbon or enough energy // builds sentry and subtracts cost; or triggers "not enough resources" alert<!--c2--></div><!--ec2--> (Thanks Darkster.)
Because of the way the GUI is written now, there should never be a mismatch between the resource stated and the resource used, this is always dependent on the "technode type": <u>Resources (Tooltips)</u> For example, tracking plasma cost of an item: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Technode.lua // Returns: 0 = carbon, 1 = plasma, 2 = energy (from CommanderUI_MenuButtonTooltip). Returns nil if none required. function TechNode:GetResourceType() // Carbon if self.techType == kTechType.Research or self.techType == kTechType.Upgrade or self.techType == kTechType.Build then return 0 // Plasma elseif self.techType == kTechType.Buy or self.techType == kTechType.Manufacture then return 1 // Energy elseif self.techType == kTechType.Action or self.techType == kTechType.EnergyBuild or self.techType == kTechType.Activation then return 2 end return nil end // use GetResourceType, if kTechType.Buy, returns 1
//Commander_Buttons.lua function CommanderUI_MenuButtonTooltip(index) if techNode then resourceType = techNode:GetResourceType() end return {tooltipText, hotkey, cost, requiresText, enablesText, tooltipInfo, resourceType} // use CommanderUI_MenuButtonTooltip(), returns ..., resourceType
//GUICommanderButtons.lua function GUICommanderButtons:UpdateTooltip(tooltipButtonIndex) local tooltipData = CommanderUI_MenuButtonTooltip(tooltipButtonIndex) local typeNumber = tooltipData[7] self.tooltip:UpdateData(text, hotKey, costNumber, requires, enabled, info, typeNumber) end
//GUICommanderTooltip.lua function GUICommanderTooltip:UpdateData(text, hotkey, costNumber, requires, enables, info, typeNumber) self.resourceIcon:SetTexturePixelCoordinates(0, typeNumber * GUICommanderTooltip.kResourceIconTextureHeight, GUICommanderTooltip.kResourceIconTextureWidth, (typeNumber + 1) * GUICommanderTooltip.kResourceIconTextureHeight) self.cost:SetColor(GUICommanderTooltip.kResourceColors[typeNumber + 1]) end // won't bother tracking any further, pretty sure this just prints the plasma icon<!--c2--></div><!--ec2-->
<u>Technode Types</u> Some comments from TechNode.lua: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// Represents one item in the tech tree. They also characterize the behavior when triggering that kind of action. // Tech nodes are of the following types: // // Order (Move, Default) - No cost, requires positional // Research (eg, research siege) - Costs carbon, queued from a structure, non-positional // Upgrade (eg, upgrade command station) - Like research but can be performed more than once // Action (eg, medpack, drifter flare) - Optionally costs energy, optional position, optionally must be researched // Buy (eg, create siege cannon from factory, player buy weapon) - Costs plasma, position implied from buyer or originating structure (unless targeted). Requires target for commander. // Build (eg, build structure from drifter) - Costs carbon, requires position // EnergyBuild (add to manufacture queue, create unit when done) - Costs energy, takes time to complete, no position (MACs, Drifters). Only use for AI units that don't need a position. // Manufacture (add to manufacture queue, create unit when done) - Costs plasma, takes time to complete, no position (ARCs) // Activation (eg, deploy/undeploy siege) - Optionally costs energy, optional position // Menu - No cost, no position<!--c2--></div><!--ec2-->
<u>MedPacks, the Armoury, and AddHealth</u> <!--quoteo(post=1824110:date=Jan 14 2011, 05:08 AM:name=Kouji_San)--><div class='quotetop'>QUOTE (Kouji_San @ Jan 14 2011, 05:08 AM) <a href="index.php?act=findpost&pid=1824110"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><!--quoteo(post=1824100:date=Jan 14 2011, 04:33 AM:name=Stele007)--><div class='quotetop'>QUOTE (Stele007 @ Jan 14 2011, 04:33 AM) <a href="index.php?act=findpost&pid=1824100"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I could be wrong, but I believe right now medpacks do heal armor.<!--QuoteEnd--></div><!--QuoteEEnd--> It seems to only repair armor, when your health is also below 100 and there seems to be a bug. When your health is at 100, but your armor is not at full, you still pick up medkits, while not repairing your armor.
Reported this at <a href="http://getsatisfaction.com/unknownworlds/topics/medkits_being_picked_up_at_full_health" target="_blank">Getsatisaction</a> <!--QuoteEnd--></div><!--QuoteEEnd--> <!--quoteo(post=1824197:date=Jan 14 2011, 10:23 AM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 14 2011, 10:23 AM) <a href="index.php?act=findpost&pid=1824197"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Medpacks and the Armoury use the same function: AddHealth The function adds both health and armour (but health first).
In the case of both the Armoury and the Medpack, it checks if you're alive and, if you have less than max hp OR less than max armour. Medpack also checks whether you are parasited, and removes it if you are.
AddHealth takes an amount (50 for the medpack), adds that to your health, but if your health was 70 for example, it'd only add 30 (because maxhealth is 100), but the remainder (20) would go onto your armour.
I'm not sure why the medpack doesn't add more armour when you're on maxhp though, it's supposed to. The armoury works properly anyway.
Also, can anyone confirm that the medpack does remove parasite?<!--QuoteEnd--></div><!--QuoteEEnd--> <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//MedPack_Server.lua function MedPack:OnTouch(player) ... // If player has less than full health or is parasited if( (player:GetHealth() < player:GetMaxHealth()) or (player:GetArmor() < player:GetMaxArmor()) or player:GetGameEffectMask(kGameEffect.Parasite) ) then player:AddHealth(MedPack.kHealth) player:SetGameEffectMask(kGameEffect.Parasite, false) ...
//Armory_Server.lua function Armory:ResupplyPlayer(player) local resuppliedPlayer = false // Heal player first if( (player:GetHealth() < player:GetMaxHealth()) or (player:GetArmor() < player:GetMaxArmor()) ) then player:AddHealth(Armory.kHealAmount) player:TriggerEffects("armory_health") resuppliedPlayer = true end ...
//LiveScriptActor_Server.lua function LiveScriptActor:AddHealth(health, playSound) ... if self:GetIsAlive() and ((self.health < self:GetMaxHealth()) or (self.armor < self:GetMaxArmor())) then // Add health first, then armor if we're full local healthAdded = math.min(health, self:GetMaxHealth() - self.health) self.health = math.min(math.max(0, self.health + healthAdded), self:GetMaxHealth()) local healthToAddToArmor = health - healthAdded if(healthToAddToArmor > 0) then self.armor = math.min(math.max(0, self.armor + healthToAddToArmor), self:GetMaxArmor()) end ...<!--c2--></div><!--ec2-->
<u>Lerk Spores</u> <!--quoteo(post=1823853:date=Jan 13 2011, 02:03 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 13 2011, 02:03 PM) <a href="index.php?act=findpost&pid=1823853"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->From the perspective of the code: It has to do with the armour/damage system**. Although the damage type is 'biological' (read: does not affect structures or exoskeletons), the same damage is applied in the same way as the 'normal' damage type**, to these biological targets: 7 damage, every 0.5 seconds, for 6 seconds (from SporeCloud.lua), i.e. 12 ticks of 7 damage (alternatively can be expressed as 14 damage per second, from Balance.lua - haven't checked which is used, but I assume SporeCloud.lua): <img src="http://img3.imageshack.us/img3/7808/ns2sporevsmarine.png" border="0" class="linked-image" /> ** <b>This is because there isn't (yet) any specific code applied</b> for damage types other than 'heavy' (e.g. pistol), 'light' (e.g. sentry), and 'normal' (e.g. rifle, bite, swipe, most attacks), but 'normal' damage-dealing also includes every non-'heavy' and non-'light' damage type. These all use the same code, really, but have different HealthPerArmor values: 1 for heavy, 2 for normal, 4 for light. The higher the number, the more health that 1 point of armour protects.
I would imagine that 'biological' would have a zero HealthPerArmor value, i.e. 1 point of armor protects no health. Knowing this, this is actually very easy to code. (This is one approach.) <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// add to Balance.lua: kHealthPointsPerArmorBiological = 0
// change to Balance.lua: kSporesDamageType = kDamageType.Biological
// add to function LiveScriptActor:GetHealthPerArmor(damageType) elseif damageType == kDamageType.Biological then healthPerArmor = kHealthPointsPerArmorBiological<!--c2--></div><!--ec2--> So: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local absorbPercentage = self:GetArmorAbsorbPercentage(damageType) healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, absorbPercentage * damage ) armorPointsUsed = healthPointsBlocked / self:GetHealthPerArmor(damageType) healthPointsUsed = damage - healthPointsBlocked => local absorbPercentage = self:GetArmorAbsorbPercentage(damageType) healthPointsBlocked = math.min(0 * self.armor, absorbPercentage * damage ) = 0 armorPointsUsed = 0 / 0 = ? healthPointsUsed = damage - 0 = damage<!--c2--></div><!--ec2--> That middle line that tries to equate zero divided by zero could become a problem though. You could easily add an if statement to fix it where: IF self:GetHealthPerArmor(damageType) == 0, THEN armorPointsUsed = 0, ELSE do the same as before.
An alternative approach is to set absorbPercentage to zero: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// change to Balance.lua: kSporesDamageType = kDamageType.Biological
// modify function LiveScriptActor:GetArmorAbsorbPercentage(damageType) if damageType == kDamageType.Falling or damageType == kDamageType.Biological then armorAbsorbPercentage = 0<!--c2--></div><!--ec2--> So: <!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local absorbPercentage = self:GetArmorAbsorbPercentage(damageType) healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, absorbPercentage * damage ) armorPointsUsed = healthPointsBlocked / self:GetHealthPerArmor(damageType) healthPointsUsed = damage - healthPointsBlocked => local absorbPercentage = 0 healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, 0 * damage ) = 0 armorPointsUsed = 0 / self:GetHealthPerArmor(damageType) = 0 healthPointsUsed = damage - 0 = damage<!--c2--></div><!--ec2--> In either approach, healthPointsBlocked is 0, so spores do full damage to health, and amorPointsUsed is 0, so no damage to armour.
<b>No armour effects on spores seems to already be planned though</b>: // Armor is best at absorbing melee damage, less against projectiles and not effective for gas/breathing damage from LiveScriptActor_Server.lua<!--QuoteEnd--></div><!--QuoteEEnd-->
<!--quoteo(post=1824681:date=Jan 16 2011, 08:46 AM:name=Antonio Gramscix420)--><div class='quotetop'>QUOTE (Antonio Gramscix420 @ Jan 16 2011, 08:46 AM) <a href="index.php?act=findpost&pid=1824681"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->an analysis of your face: i dont' like it.<!--QuoteEnd--></div><!--QuoteEEnd--> If that's you, I can say the same back.
So it is possible for a marine to 3 shot a skulk in melee range with a Rifle (although rifle butt attack is slower than bite, but the marine is more likely to land hits due to the range bonus). Now that it takes a Skulk 3 bites to kill a marine, marines are no longer instant free meals, even in melee range.
The problem is that <b>Marines can jump over Skulks in melee fights</b> (it's not much of a fight if they aren't in melee), often confusing the skulk, combined with their <b>superior range</b>(even melee range), give Marines a big advantage in melee fights. As a result, I'm seeing more rifle butt kills than ever.
You see more rifle butt kills because hit detection while moving/dodging got worse => making marines use melee more often after getting a few lucky hits with the rifle.
=> You have a lot jump around situations that shouldnt be there... i had fights alone as a marine against 3 skulks that lasted nearly a 1min because nobody could hit the other and we where just jumping around.
Lerks are now more or less unkillable if not played like a static turret by a noob.
IF players can move, fights take a lot longer in 161, if they cant... marines shoot your ass faster than you can say "oh shi.t"
Armor is still bugged in 162, but not in the same way
Damage varies depending on whether you have armor or not. If you have armor, you'll take less total damage than if you have no armor. It affects both marines and aliens.
For example, an armor 0 marine against a whip, one hit deals 15 health and 9 armor, for a total of 33 damage. When you have no armor, it will deal 50 damage.
This is probably why it feels easier to kill skulks in 162. They die in 4 pistol hits (3 in secondary mode).
That's not wrong. This is the <b>intended</b> way. Armour blocks more damage (and is consumed less) than health, because it's not 1 to 1.
For example, In your example, a whip deals 50 damage, correct? The whip does 'light' damage, so the damage blocked per point of armour is 4. The armour absorption percentage is 70%. So 50 damage is split into: 70% goes to armour, 30% goes to health. or, 35 goes to armour, 15 goes to health. But the damage blocked per point of armour is 4, so of the 35 damage that goes to armour, only 35/4 armour points are consumed: 8.75 (rounded up to 9)
In summary: the marine's armour absorbs 35 damage, but 8.75 (or 9) points of armour are consumed. Direct health damage is 15.
I addressed the pistol thing earlier. Lemme bring up a quote.
<!--quoteo(post=1822825:date=Jan 9 2011, 01:33 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 9 2011, 01:33 PM) <a href="index.php?act=findpost&pid=1822825"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><u>Edit2</u>: <u>Pistol vs skulk</u>: Taking into account that HealthPerArmor for pistol is 1 (Heavy damage-type), ironically pistol damage on skulks actually works properly:
I think that the best option for a marine currently, considering the uselessness of the rifle, is to just take skulks out with the pistol: 3 well-placed shots with alt-fire mode. Hell, don't marines run out of rifle ammunition then have to kill skulks with the pistol anyway?<!--QuoteEnd--></div><!--QuoteEEnd-->
In short, it's not exactly 'easier to kill skulks', the problem is that it isn't a level playing field. Marines can now fire and register hits, but skulks can't bite and register hits, especially with crazy marine hopping. It's not exactly easier to kill skulks, it's just hard for skulks to kill marines; once the playing field is level, they should have about an equal chance against one another.
twilitebluebug stalkerJoin Date: 2003-02-04Member: 13116Members, NS2 Playtester, Squad Five Blue
Lag compensation seems to be working well, as I actually get a lot of kills on laggy (ping >300) servers. Fast moving Skulks tend to warp from one location to another, and I can get the shots in when they appear to pause after each jump.
The problem lies with client interpolation, I think.
Comments
There is no reason for it to not be a set duration. Make it five second or ten seconds or whatever, but make it static.
stopFireChance = 1 - (1 - kStopFireProbability) ^ (PlayingTeam.kUpdateGameEffectsInterval)
i think i got this right. ie. n trials for a sec would equal the kStopFireProbability
One thing to consider though is that gorge spray is supposed to put out flames.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//SpitSpray.lua
function SpitSpray:HealEntities(player)
if isHealPlayer then
// Put out entities on fire
targetEntity:SetGameEffectMask(kGameEffect.OnFire, false)<!--c2--></div><!--ec2-->
<!--quoteo(post=1823337:date=Jan 12 2011, 03:08 AM:name=jbaker8935)--><div class='quotetop'>QUOTE (jbaker8935 @ Jan 12 2011, 03:08 AM) <a href="index.php?act=findpost&pid=1823337"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->if they really want the it to be based on a percent per sec they could set the per trial probability so that it equals out to the intent of kStopFireProbability.
stopFireChance = 1 - (1 - kStopFireProbability) ^ (PlayingTeam.kUpdateGameEffectsInterval)
i think i got this right. ie. n trials for a sec would equal the kStopFireProbability<!--QuoteEnd--></div><!--QuoteEEnd-->
Yeah that works out right.
= 0.047586204
Doing the linear interpolation between 0.9 and 1.2 seconds (trials 3 and 4) for 1 second, yields a chance very close to 0.15.
But that still yields a static stopFireChance, which still leads to a non-linear cumulative chance... So at 3 seconds, for example, it isn't a 45% chance, it's a 38.6% chance.
But if that's okay, then that's okay.
<img src="http://img841.imageshack.us/img841/5475/ns2burningputoutchance2.png" border="0" class="linked-image" />
There is no reason for it to not be a set duration. Make it five second or ten seconds or whatever, but make it static.<!--QuoteEnd--></div><!--QuoteEEnd-->
I have to agree on this. I'm a big TF2 fan, and the pyro's flamethrower will keep a victim burning for the same amount of time. (or similar at least - I've never timed it, but it's never gone on and on forever or ended really fast) A player on fire generally can tell if they're in danger of dying from the burn or not. If they're not in danger, they can continue play and not worry about feeling cheated that they just kept burning. If they know they're in trouble, it adds a fun layer of urgency trying to find a method to put the fire out. (water, health pack, medic, a friendly airblast, jarate, whatever)
Let the player know what to expect, don't randomly pull the rug out from under them. It's not fun, and you can't "learn" a good consistent response fire except to panic and hope you don't die this time.
"// See if we catch anyone else on fire"
Even with correcting the burn time issue, having things catch other things on fire would be insane. FT would completely cancel out Hydras and make it dangerous for alien players to "run back to base to heal". I hope I'm just being pessimistic.
There are a number of other features that are 'done', but disabled like this (as well as features that are planned but incomplete).
= 0.047586204
Doing the linear interpolation between 0.9 and 1.2 seconds (trials 3 and 4) for 1 second, yields a chance very close to 0.15.
But that still yields a static stopFireChance, which still leads to a non-linear cumulative chance... So at 3 seconds, for example, it isn't a 45% chance, it's a 38.6% chance.
But if that's okay, then that's okay.<!--QuoteEnd--></div><!--QuoteEEnd-->
right. it only helps making the tuning more accurate (ie you could change the effects interval without impacting outcome). the usual cumulative probability formula applies.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->OnThink
-> AcquireTarget
-> GetSortedTargetList
-> GetTargetValid
-> AttackTarget
-> CreateSpikeProjectile
-> [...]
-> OR Alert
-> GetIsEnemyNearby
-> SetNextThink<!--c2--></div><!--ec2-->
GetSortedTargetList seems the most intensive, but the origin and the range are put into the function from the beginning, so it shouldn't be scanning everything on the map.
There are a few instances (33, so relatively few) in the code of "GetGamerules():GetEntities(arguments)", but I can't figure out how they work as I can't find the function "GetEntities(arguments)". The closest is "GetEntitiesIsA(arguments)", and I wonder why the hydra doesn't use the function "GetEntitiesIsAInRadius(arguments)", as the arguments match:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Entity.lua
function GetEntitiesIsaInRadius(className, teamNumber, origin, radius, checkXZOnly, visibleOnly, log)
//Hydra_Server.lua
function Hydra:GetSortedTargetList()
local targets = GetGamerules():GetEntities("LiveScriptActor", GetEnemyTeamNumber(self:GetTeamNumber()), hydraAttackOrigin, Hydra.kRange)<!--c2--></div><!--ec2-->
It's the same case for sentries, as well.
Could this be the source of the problem, or are my searching skills not enough? I figure if it weren't working, hydras and sentries wouldn't work at all though, so I don't know... :/ Unless it's managing to scan every target on the map regardless...<!--QuoteEnd--></div><!--QuoteEEnd-->
I just had another look at this, I see what you mean, the function doesn't exist as far as i can see.
I checked all the logical lua files and i can't find it. I went to GetGamerules() and then followed that to Entity which then was referring to GetEntitiesIsa("...").
The variables are slightly different as well as if they are meant to be passing the intended thing but theres nothing linking them together.
Totally agree though, if it was broken i wouldn't be having my ass handed to me when i walk around corners in game.
Would be interested what the team say..
<!--quoteo(post=1823352:date=Jan 11 2011, 07:58 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 11 2011, 07:58 PM) <a href="index.php?act=findpost&pid=1823352"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->It's always been a feature under consideration. But that's why they've put it under comments. If they decide to try it, they just need to remove the commenting.
There are a number of other features that are 'done', but disabled like this (as well as features that are planned but incomplete).<!--QuoteEnd--></div><!--QuoteEEnd-->
I think that's the beauty of adding new features like this, you can tinker or totally remove them. It's not like NS1 failed without a FT.
<!--quoteo(post=1823374:date=Jan 12 2011, 05:28 AM:name=jbaker8935)--><div class='quotetop'>QUOTE (jbaker8935 @ Jan 12 2011, 05:28 AM) <a href="index.php?act=findpost&pid=1823374"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->right. it only helps making the tuning more accurate (ie you could change the effects interval without impacting outcome). the usual cumulative probability formula applies.<!--QuoteEnd--></div><!--QuoteEEnd-->
Yeah, that makes sense. It's a good approach.
<!--quoteo(post=1823406:date=Jan 12 2011, 08:05 AM:name=Slickk-)--><div class='quotetop'>QUOTE (Slickk- @ Jan 12 2011, 08:05 AM) <a href="index.php?act=findpost&pid=1823406"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I just had another look at this, I see what you mean, the function doesn't exist as far as i can see.
I checked all the logical lua files and i can't find it. I went to GetGamerules() and then followed that to Entity which then was referring to GetEntitiesIsa("...").
The variables are slightly different as well as if they are meant to be passing the intended thing but theres nothing linking them together.
Totally agree though, if it was broken i wouldn't be having my ass handed to me when i walk around corners in game.
Would be interested what the team say..<!--QuoteEnd--></div><!--QuoteEEnd-->
I'd definitely like to get a comment on this.
<!--quoteo(post=1823415:date=Jan 12 2011, 09:06 AM:name=MOOtant)--><div class='quotetop'>QUOTE (MOOtant @ Jan 12 2011, 09:06 AM) <a href="index.php?act=findpost&pid=1823415"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Less tables more graphs, please.<!--QuoteEnd--></div><!--QuoteEEnd-->
Tables are better for raw values, graphs are good for looking at comparisons, and local and global trends. I could always label relevant data points though. I'll definitely consider it.
You cant spent res if you only got the exact amount to buy the thing you wish... you have to wait until you get +1 res.
Example, I got 5 res and want to upgrade a Res Tower... => Not possible until i got at least 6 res. even tho it only costs 5res... I dont think thats the way it should be...
Retracted.
I had a theory, realised it was wrong as the code should actually be working with those operators. So my new theory is that it's displaying the wrong amount of carbon available. Haven't checked this, but it seems most likely.
See:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Commander_Server.lua
// Handle tech tree actions that cost carbon
if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsBuild() or techNode:GetIsEnergyBuild()) then
local costsEnergy = techNode:GetIsEnergyBuild()
local teamCarbon = team:GetCarbon()
local energy = entity:GetEnergy()
if (not costsEnergy and cost <= teamCarbon) or (costsEnergy and cost <= energy) then
[...]
else
self:TriggerNotEnoughResourcesAlert()
end
// Handle plasma-based abilities
elseif(techNode:GetIsAction() or techNode:GetIsBuy()) then
local playerPlasma = self:GetPlasma()
if(cost == nil or cost <= playerPlasma) then
[...]
else
self:TriggerNotEnoughResourcesAlert()
end
[...]
end<!--c2--></div><!--ec2-->
Personally I would have used teamCarbon >= cost, and playerPlasma >= cost, as it's more intuitive, but it shouldn't make a difference, I don't think.
I'm still stumped as to how <b>different things</b> are specified as costing carbon, energy or plasma. I've been searching but I can't find it. I've been searching mostly in regards to the 20 <b>Carbon</b> cost of the Sentry - I know that not everything costs Carbon as commander (which was one theory as to how it might be broken, if it is indeed broken), because the energy costs of MACs still works as it should.
So far I can only figure out resource requirements, and subtracting from resources (given a resource type, or action type). The actual resource type (e.g. Carbon) or action type (e.g. GetIsBuild()) for an item still eludes me.
Is "nil" the same as "0" in lua, or are they different concepts?
<!--quoteo(post=1823867:date=Jan 13 2011, 02:44 PM:name=Zek)--><div class='quotetop'>QUOTE (Zek @ Jan 13 2011, 02:44 PM) <a href="index.php?act=findpost&pid=1823867"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I never liked the parasite + 2 bites mechanic in NS1. It was a quick fix to early game balance problems that unfairly punished newer players that didn't know the trick. IMO parasite shouldn't be a combat tool, it should only be used for its actual purpose: tracking marines.<!--QuoteEnd--></div><!--QuoteEEnd-->
Death to parasite (<b>after</b> two bites) is utter humiliation, though. It <b>has</b> to be that way. :P
I could be wrong about that part though.
Edit: Yep. No idea. The game adds 1 (whole) carbon every 12 seconds (length of the update interval), per resource tower, beginning 4 seconds after the resource tower is built. Basically, there's no rounding involved, so there's no issue with rounding. It's plain and simple addition.
For those who are interested in the relevant code (I worked backwards, so that's why the order is reversed):
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//GUIResourceDisplay.lua
function GUICommanderManager:CreateResourceDisplay()
local settingsTable = { }
settingsTable.Width = GUICommanderManager.kResourceDisplayWidth
settingsTable.BackgroundAnchorX = GUIItem.Middle
settingsTable.BackgroundAnchorY = GUIItem.Top
settingsTable.X = -settingsTable.Width / 2
settingsTable.Y = GUICommanderManager.kResourceDisplayOffset
self.resourceDisplay = GUIResourceDisplay()
self.resourceDisplay:Initialize(settingsTable)
end
//Player_Server.lua
function GUIResourceDisplay:Update(deltaTime)
self.plasmaText:SetText(ToString(PlayerUI_GetPlayerResources()))
self.carbonText:SetText(ToString(PlayerUI_GetTeamResources()))
self.towerText:SetText(ToString(CommanderUI_GetTeamHarvesterCount()))
end
//Player.lua
function PlayerUI_GetTeamResources()
local player = Client.GetLocalPlayer()
if player then
return player:GetDisplayTeamCarbon()
end
return 0
end
function Player:GetDisplayTeamCarbon()
local displayTeamCarbon = self.teamCarbon
if(Client and self.resourceDisplay) then
displayTeamCarbon = self.animatedCarbonDisplay:GetDisplayValue()
end
return displayTeamCarbon
end
function Player:AddCarbon(amount)
self.teamCarbon = math.max(math.min(self.teamCarbon + amount, kMaxResources), 0)
end
//ResourceTower_Server.lua
function ResourceTower:UpdateOnThink()
...
if(team ~= nil) then
team:AddCarbon(ResourceTower.kCarbonInjection)
end
...
end
function ResourceTower:GetUpdateInterval()
return kResourceTowerResourceInterval
end
function ResourceTower:OnThink()
if self:GetIsBuilt() and self:GetIsAlive() and (self:GetAttached() ~= nil) and self:GetIsActive() and (self:GetAttached():GetAttached() == self) and GetGamerules():GetGameStarted() then
self:UpdateOnThink()
end
Structure.OnThink(self)
self:SetNextThink(self:GetUpdateInterval())
end
function ResourceTower:OnConstructionComplete()
Structure.OnConstructionComplete(self)
self:SetNextThink(ResourceTower.kBuildDelay)
end
//ResourceTower.lua
ResourceTower.kCarbonInjection = 1
ResourceTower.kBuildDelay = 4
//Balance.lua
kResourceTowerResourceInterval = 12<!--c2--></div><!--ec2-->
Just adding the backlog. Discuss.
<u>Resource Usage (Different Types)</u>
All buttons are 'tech nodes'
Press a button,
For example, tracking the carbon cost of a sentry...
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// using:
//TechTree_Server.lua
function TechTree:AddBuildNode(techId, prereq1, prereq2)
local techNode = TechNode()
techNode:Initialize(techId, kTechType.Build, prereq1, prereq2)
techNode.requiresTarget = true
self:AddNode(techNode)
end
// so:
//MarineTeam.lua
self.techTree:AddBuildNode(kTechId.Sentry, kTechId.None, kTechId.None)
// reads techId (specified), and prereqs, then
// initialises kTechType.Build (specifies buildable) as well as techId, and prereqs
// then using:
Technode.lua
function TechNode:GetIsBuild()
return self.techType == kTechType.Build
end
// returns "true" if techtype is a buildable
// so:
//Commander_Server.lua
// Handle tech tree actions that cost carbon
if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsBuild() or techNode:GetIsEnergyBuild()) then
local costsEnergy = techNode:GetIsEnergyBuild()
local teamCarbon = team:GetCarbon()
local energy = entity:GetEnergy()
if (not costsEnergy and cost <= teamCarbon) or (costsEnergy and cost <= energy) then
if(techNode:GetIsResearch() or techNode:GetIsUpgrade() or techNode:GetIsEnergyBuild()) then
success = self:AttemptToResearchOrUpgrade(techNode, force)
if success then
keepProcessing = false
end
elseif(techNode:GetIsBuild()) then
success = self:AttemptToBuild(techId, position, pickVec, false)
if success then
keepProcessing = false
end
end
if success then
if costsEnergy then
entity:SetEnergy(entity:GetEnergy() - cost)
else
team:AddCarbon(-cost)
end
Shared.PlayPrivateSound(self, Commander.kSpendCarbonSoundName, nil, 1.0, self:GetOrigin())
end
else
self:TriggerNotEnoughResourcesAlert()
end
// checks if research, upgrade, buildable or energy buildable
// checks if enough carbon or enough energy
// builds sentry and subtracts cost; or triggers "not enough resources" alert<!--c2--></div><!--ec2-->
(Thanks Darkster.)
Because of the way the GUI is written now, there should never be a mismatch between the resource stated and the resource used, this is always dependent on the "technode type":
<u>Resources (Tooltips)</u>
For example, tracking plasma cost of an item:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//Technode.lua
// Returns: 0 = carbon, 1 = plasma, 2 = energy (from CommanderUI_MenuButtonTooltip). Returns nil if none required.
function TechNode:GetResourceType()
// Carbon
if self.techType == kTechType.Research or self.techType == kTechType.Upgrade or self.techType == kTechType.Build then
return 0
// Plasma
elseif self.techType == kTechType.Buy or self.techType == kTechType.Manufacture then
return 1
// Energy
elseif self.techType == kTechType.Action or self.techType == kTechType.EnergyBuild or self.techType == kTechType.Activation then
return 2
end
return nil
end
// use GetResourceType, if kTechType.Buy, returns 1
//Commander_Buttons.lua
function CommanderUI_MenuButtonTooltip(index)
if techNode then
resourceType = techNode:GetResourceType()
end
return {tooltipText, hotkey, cost, requiresText, enablesText, tooltipInfo, resourceType}
// use CommanderUI_MenuButtonTooltip(), returns ..., resourceType
//GUICommanderButtons.lua
function GUICommanderButtons:UpdateTooltip(tooltipButtonIndex)
local tooltipData = CommanderUI_MenuButtonTooltip(tooltipButtonIndex)
local typeNumber = tooltipData[7]
self.tooltip:UpdateData(text, hotKey, costNumber, requires, enabled, info, typeNumber)
end
//GUICommanderTooltip.lua
function GUICommanderTooltip:UpdateData(text, hotkey, costNumber, requires, enables, info, typeNumber)
self.resourceIcon:SetTexturePixelCoordinates(0, typeNumber * GUICommanderTooltip.kResourceIconTextureHeight,
GUICommanderTooltip.kResourceIconTextureWidth,
(typeNumber + 1) * GUICommanderTooltip.kResourceIconTextureHeight)
self.cost:SetColor(GUICommanderTooltip.kResourceColors[typeNumber + 1])
end
// won't bother tracking any further, pretty sure this just prints the plasma icon<!--c2--></div><!--ec2-->
<u>Technode Types</u>
Some comments from TechNode.lua:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// Represents one item in the tech tree. They also characterize the behavior when triggering that kind of action.
// Tech nodes are of the following types:
//
// Order (Move, Default) - No cost, requires positional
// Research (eg, research siege) - Costs carbon, queued from a structure, non-positional
// Upgrade (eg, upgrade command station) - Like research but can be performed more than once
// Action (eg, medpack, drifter flare) - Optionally costs energy, optional position, optionally must be researched
// Buy (eg, create siege cannon from factory, player buy weapon) - Costs plasma, position implied from buyer or originating structure (unless targeted). Requires target for commander.
// Build (eg, build structure from drifter) - Costs carbon, requires position
// EnergyBuild (add to manufacture queue, create unit when done) - Costs energy, takes time to complete, no position (MACs, Drifters). Only use for AI units that don't need a position.
// Manufacture (add to manufacture queue, create unit when done) - Costs plasma, takes time to complete, no position (ARCs)
// Activation (eg, deploy/undeploy siege) - Optionally costs energy, optional position
// Menu - No cost, no position<!--c2--></div><!--ec2-->
<!--quoteo(post=1824110:date=Jan 14 2011, 05:08 AM:name=Kouji_San)--><div class='quotetop'>QUOTE (Kouji_San @ Jan 14 2011, 05:08 AM) <a href="index.php?act=findpost&pid=1824110"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><!--quoteo(post=1824100:date=Jan 14 2011, 04:33 AM:name=Stele007)--><div class='quotetop'>QUOTE (Stele007 @ Jan 14 2011, 04:33 AM) <a href="index.php?act=findpost&pid=1824100"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->I could be wrong, but I believe right now medpacks do heal armor.<!--QuoteEnd--></div><!--QuoteEEnd-->
It seems to only repair armor, when your health is also below 100 and there seems to be a bug. When your health is at 100, but your armor is not at full, you still pick up medkits, while not repairing your armor.
Reported this at <a href="http://getsatisfaction.com/unknownworlds/topics/medkits_being_picked_up_at_full_health" target="_blank">Getsatisaction</a>
<!--QuoteEnd--></div><!--QuoteEEnd-->
<!--quoteo(post=1824197:date=Jan 14 2011, 10:23 AM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 14 2011, 10:23 AM) <a href="index.php?act=findpost&pid=1824197"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->Medpacks and the Armoury use the same function: AddHealth
The function adds both health and armour (but health first).
In the case of both the Armoury and the Medpack, it checks if you're alive and, if you have less than max hp OR less than max armour. Medpack also checks whether you are parasited, and removes it if you are.
AddHealth takes an amount (50 for the medpack), adds that to your health, but if your health was 70 for example, it'd only add 30 (because maxhealth is 100), but the remainder (20) would go onto your armour.
I'm not sure why the medpack doesn't add more armour when you're on maxhp though, it's supposed to. The armoury works properly anyway.
Also, can anyone confirm that the medpack does remove parasite?<!--QuoteEnd--></div><!--QuoteEEnd-->
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->//MedPack_Server.lua
function MedPack:OnTouch(player)
...
// If player has less than full health or is parasited
if( (player:GetHealth() < player:GetMaxHealth()) or (player:GetArmor() < player:GetMaxArmor()) or player:GetGameEffectMask(kGameEffect.Parasite) ) then
player:AddHealth(MedPack.kHealth)
player:SetGameEffectMask(kGameEffect.Parasite, false)
...
//Armory_Server.lua
function Armory:ResupplyPlayer(player)
local resuppliedPlayer = false
// Heal player first
if( (player:GetHealth() < player:GetMaxHealth()) or (player:GetArmor() < player:GetMaxArmor()) ) then
player:AddHealth(Armory.kHealAmount)
player:TriggerEffects("armory_health")
resuppliedPlayer = true
end
...
//LiveScriptActor_Server.lua
function LiveScriptActor:AddHealth(health, playSound)
...
if self:GetIsAlive() and ((self.health < self:GetMaxHealth()) or (self.armor < self:GetMaxArmor())) then
// Add health first, then armor if we're full
local healthAdded = math.min(health, self:GetMaxHealth() - self.health)
self.health = math.min(math.max(0, self.health + healthAdded), self:GetMaxHealth())
local healthToAddToArmor = health - healthAdded
if(healthToAddToArmor > 0) then
self.armor = math.min(math.max(0, self.armor + healthToAddToArmor), self:GetMaxArmor())
end
...<!--c2--></div><!--ec2-->
<u>Lerk Spores</u>
<!--quoteo(post=1823853:date=Jan 13 2011, 02:03 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 13 2011, 02:03 PM) <a href="index.php?act=findpost&pid=1823853"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec-->From the perspective of the code: It has to do with the armour/damage system**. Although the damage type is 'biological' (read: does not affect structures or exoskeletons), the same damage is applied in the same way as the 'normal' damage type**, to these biological targets:
7 damage, every 0.5 seconds, for 6 seconds (from SporeCloud.lua), i.e. 12 ticks of 7 damage (alternatively can be expressed as 14 damage per second, from Balance.lua - haven't checked which is used, but I assume SporeCloud.lua):
<img src="http://img3.imageshack.us/img3/7808/ns2sporevsmarine.png" border="0" class="linked-image" />
** <b>This is because there isn't (yet) any specific code applied</b> for damage types other than 'heavy' (e.g. pistol), 'light' (e.g. sentry), and 'normal' (e.g. rifle, bite, swipe, most attacks), but 'normal' damage-dealing also includes every non-'heavy' and non-'light' damage type. These all use the same code, really, but have different HealthPerArmor values: 1 for heavy, 2 for normal, 4 for light. The higher the number, the more health that 1 point of armour protects.
I would imagine that 'biological' would have a zero HealthPerArmor value, i.e. 1 point of armor protects no health. Knowing this, this is actually very easy to code.
(This is one approach.)
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// add to Balance.lua:
kHealthPointsPerArmorBiological = 0
// change to Balance.lua:
kSporesDamageType = kDamageType.Biological
// add to function LiveScriptActor:GetHealthPerArmor(damageType)
elseif damageType == kDamageType.Biological then
healthPerArmor = kHealthPointsPerArmorBiological<!--c2--></div><!--ec2-->
So:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local absorbPercentage = self:GetArmorAbsorbPercentage(damageType)
healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, absorbPercentage * damage )
armorPointsUsed = healthPointsBlocked / self:GetHealthPerArmor(damageType)
healthPointsUsed = damage - healthPointsBlocked
=>
local absorbPercentage = self:GetArmorAbsorbPercentage(damageType)
healthPointsBlocked = math.min(0 * self.armor, absorbPercentage * damage ) = 0
armorPointsUsed = 0 / 0 = ?
healthPointsUsed = damage - 0 = damage<!--c2--></div><!--ec2-->
That middle line that tries to equate zero divided by zero could become a problem though. You could easily add an if statement to fix it where:
IF self:GetHealthPerArmor(damageType) == 0, THEN armorPointsUsed = 0, ELSE do the same as before.
An alternative approach is to set absorbPercentage to zero:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->// change to Balance.lua:
kSporesDamageType = kDamageType.Biological
// modify function LiveScriptActor:GetArmorAbsorbPercentage(damageType)
if damageType == kDamageType.Falling or damageType == kDamageType.Biological then
armorAbsorbPercentage = 0<!--c2--></div><!--ec2-->
So:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1--> local absorbPercentage = self:GetArmorAbsorbPercentage(damageType)
healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, absorbPercentage * damage )
armorPointsUsed = healthPointsBlocked / self:GetHealthPerArmor(damageType)
healthPointsUsed = damage - healthPointsBlocked
=>
local absorbPercentage = 0
healthPointsBlocked = math.min(self:GetHealthPerArmor(damageType) * self.armor, 0 * damage ) = 0
armorPointsUsed = 0 / self:GetHealthPerArmor(damageType) = 0
healthPointsUsed = damage - 0 = damage<!--c2--></div><!--ec2-->
In either approach, healthPointsBlocked is 0, so spores do full damage to health, and amorPointsUsed is 0, so no damage to armour.
<b>No armour effects on spores seems to already be planned though</b>:
// Armor is best at absorbing melee damage, less against projectiles and not effective for gas/breathing damage
from LiveScriptActor_Server.lua<!--QuoteEnd--></div><!--QuoteEEnd-->
<img src="http://www.threadbombing.com/data/media/13/75378-TrollFace.png" border="0" class="linked-image" />
Im sorry - i had to :((
If that's you, I can say the same back.
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->Skulk.Lua:
Skulk.kViewOffsetHeight = .55
Player.Lua:
Player.kJumpHeight = 1 //Marines have the same jump height<!--c2--></div><!--ec2-->
The problem arises when:
<!--c1--><div class='codetop'>CODE</div><div class='codemain'><!--ec1-->BiteLeap.lua:
BiteLeap.kRange = .6
Axe.lua:
Axe.kRange = 1.0 // Hmmm
Rifle.lua:
Rifle.kButtRange = 1.5 // Whoa
////////////////////////////////////////////////
Balance.lua
//Have to take these into account as well
kRifleMeleeDamage = 35
kRifleMeleeDamageType = kDamageType.Normal
kRifleMeleeFireDelay = 0.7
kBiteDamage = 75
kBiteDamageType = kDamageType.Normal
kBiteFireDelay = 0.45<!--c2--></div><!--ec2-->
So it is possible for a marine to 3 shot a skulk in melee range with a Rifle (although rifle butt attack is slower than bite, but the marine is more likely to land hits due to the range bonus). Now that it takes a Skulk 3 bites to kill a marine, marines are no longer instant free meals, even in melee range.
The problem is that <b>Marines can jump over Skulks in melee fights</b> (it's not much of a fight if they aren't in melee), often confusing the skulk, combined with their <b>superior range</b>(even melee range), give Marines a big advantage in melee fights. As a result, I'm seeing more rifle butt kills than ever.
=> You have a lot jump around situations that shouldnt be there... i had fights alone as a marine against 3 skulks that lasted nearly a 1min because nobody could hit the other and we where just jumping around.
Lerks are now more or less unkillable if not played like a static turret by a noob.
IF players can move, fights take a lot longer in 161, if they cant... marines shoot your ass faster than you can say "oh shi.t"
Damage varies depending on whether you have armor or not. If you have armor, you'll take less total damage than if you have no armor. It affects both marines and aliens.
For example, an armor 0 marine against a whip, one hit deals 15 health and 9 armor, for a total of 33 damage. When you have no armor, it will deal 50 damage.
This is probably why it feels easier to kill skulks in 162. They die in 4 pistol hits (3 in secondary mode).
For example,
In your example, a whip deals 50 damage, correct?
The whip does 'light' damage, so the damage blocked per point of armour is 4.
The armour absorption percentage is 70%.
So 50 damage is split into:
70% goes to armour, 30% goes to health.
or, 35 goes to armour, 15 goes to health.
But the damage blocked per point of armour is 4, so of the 35 damage that goes to armour, only 35/4 armour points are consumed: 8.75 (rounded up to 9)
In summary: the marine's armour absorbs 35 damage, but 8.75 (or 9) points of armour are consumed. Direct health damage is 15.
I addressed the pistol thing earlier. Lemme bring up a quote.
<!--quoteo(post=1822825:date=Jan 9 2011, 01:33 PM:name=Harimau)--><div class='quotetop'>QUOTE (Harimau @ Jan 9 2011, 01:33 PM) <a href="index.php?act=findpost&pid=1822825"><{POST_SNAPBACK}></a></div><div class='quotemain'><!--quotec--><u>Edit2</u>:
<u>Pistol vs skulk</u>:
Taking into account that HealthPerArmor for pistol is 1 (Heavy damage-type), ironically pistol damage on skulks actually works properly:
Default fire mode:
shot 1: damage = 20 -> healthpointsblocked = 10 (min(10,14)) -> armorpointsused = 10 (<b>0</b> remaining) -> healthpointsused = 10 (<b>60</b> remaining)
shot 2: damage = 20 -> healthpointsblocked = 0 (min(0,14)) -> armorpointused = 0 (<b>0</b> remaining) -> healthpointsused = 20 (<b>40</b> remaining)
shot 3: damage = 20 -> healthpointsblocked = 0 (min(0,14)) -> armorpointused = 0 (<b>0</b> remaining) -> healthpointsused = 20 (<b>20</b> remaining)
shot 4: damage = 20 -> healthpointsblocked = 0 (min(0,14)) -> armorpointused = 0 (<b>0</b> remaining) -> healthpointsused = 20 (<b>0</b> remaining)
Ostensibly can be done in 0.4 seconds: faster than a skulk can bite (0.45 seconds).
Alternate fire mode:
shot 1: damage = 30 -> healthpointsblocked = 10 (min(10,21)) -> armorpointsused = 10 (<b>0</b> remaining) -> healthpointsused = 20 (<b>50</b> remaining)
shot 2: damage = 30 -> healthpointsblocked = 0 (min(0,21)) -> armorpointsused = 0 (<b>0</b> remaining) -> healthpointsused = 30 (<b>20</b> remaining)
shot 3: damage = 30 -> healthpointsblocked = 0 (min(0,21)) -> armorpointsused = 0 (<b>0</b> remaining) -> healthpointsused = 30 (<b>0</b> remaining)
Ostensibly can be done in 0.6 seconds.
I think that the best option for a marine currently, considering the uselessness of the rifle, is to just take skulks out with the pistol: 3 well-placed shots with alt-fire mode. Hell, don't marines run out of rifle ammunition then have to kill skulks with the pistol anyway?<!--QuoteEnd--></div><!--QuoteEEnd-->
In short, it's not exactly 'easier to kill skulks', the problem is that it isn't a level playing field. Marines can now fire and register hits, but skulks can't bite and register hits, especially with crazy marine hopping. It's not exactly easier to kill skulks, it's just hard for skulks to kill marines; once the playing field is level, they should have about an equal chance against one another.
The problem lies with client interpolation, I think.