Advice on LUA

RenaissanceFan

Warlord
Joined
Mar 15, 2011
Messages
125
Hello again. I've managed to get my new units running, and I have an idea of what needs to be written in the LUA script, but I don't know how to call the function.

The idea is this: every time my ship sinks (destroys, not damages) an enemy ship, there will be a chance for gaining some gold. If I put this, would it work? (I copied it from Conquest of the New World)

Spoiler :
if (Game.Rand(100, "Ship Gold Bonus Roll") < 70) then
local iGoldBonus = 100;
player:ChangeGold(iGoldBonus);
end


And, if the above code is OK, how do I call it whenever the ship sinks an enemy?
 
Well, you need a LOT more than just that little bit of code. What you've written there gives a certain player a 70% chance of gaining 100 gold, but that's all it does.

First, you need to set "player" somehow.
Second, obviously, you need to put it in an Event.

The main events for combat is RunCombatSim, although there's also an EndCombatSim. RCS has in it the ID of the attacking and defending players, the IDs of the units involved, how many HP of damage each started the fight with, how many each ended with, and how many total HP each had to begin with. So it should be pretty easy to check to see if the attacker civ is the right civ type, then see if the unit is the right type (if you want this to be tied to ANY naval unit, you can either use the UnitCombatClass or the Domain type), then check to see if the opposing unit's end damage is equal to or greater than its max HP, and then do this logic if all of the above are true. Then repeat the checks for the defending player.

If you really want to see an example of this and don't want to wait a few hours, over in my mod (Crazy Spatz), there's a file "SpatzUnit.lua" that includes a routine that does something similar to this (but it's a bit more complicated than just adding gold). Otherwise I can try to post a bit of it when I get home.
 
Otherwise I can try to post a bit of it when I get home.

I'd be very grateful. Also, would it be structured like this (obviously, it's not correct, but I'm a total beginner in LUA)?

Spoiler :
GameEvents.RunCombatSim (function(iAttPlayer, iAttUnitID, iDefPlayer, iDefUnitID)

local AttPlayer = Players[iAttPlayer];
local Ship = player:GetUnitByID(iAttUnitID);
local DefPlayer = Players[iDefPlayer];
local EnemyShip = player:GetUnitByID(iDefUnitID);

if (Ship:GetDamage() < Ship:GetMaxHP()) then

if (EnemyShip:GetDamage >= EnemyShip:GetMaxHP()) then

if (Ship:GetUnitType() == GameInfoTypes["UNIT_GALLEON"]) then
if (Game.Rand(100, "Gold Bonus Chance Roll") < 70) then
local iGoldBonus = Game.Rand(30,"Gold Bonus Roll");
AttPlayer:ChangeGold(iGoldBonus);
end

end
end
end

end);
 
Okay, here's what I have, trimmed down heavily of course. And it's a bit old; I don't use the GameInfoTypes references, and I don't use the GetUnitByID function. So it could be streamlined a bit. And if the loop logic makes no sense, it's because I've trimmed out quite a few bits.

Specifically, this code does three things:
1> Checks for the "Critical Strike" promotion, which gives a unit a 10% chance of dealing an additional 5 damage to its opponent (unless its opponent is a city)
2> Checks for the "Spontaneous Healing" promotion, which gives a unit a 10% chance of healing 5 damage at the start of a fight
3> Checks for the Psi unit combat class. Psi units' strength shifts up or down by up to 25%, based on the base strength of the opposing unit (unless its opponent is a city OR is another Psi unit).

Spoiler :
Code:
function SpatzStartCombat(iAttackingPlayer, iAttackingUnit, iAttackingUnitDamage, iAttackingUnitFinalDamage, iAttackingUnitMaxHitPoints, iDefendingPlayer, iDefendingUnit, iDefendingUnitDamage, iDefendingUnitFinalDamage, iDefendingUnitMaxHitPoints, bContinuation)

	critID = 0;
	healID = 0;
	synthID = 0;
	for row in GameInfo.UnitPromotions() do
		if( row.Type == "PROMOTION_CRITICAL_STRIKE" ) then
			critID = row.ID;
		end
		if( row.Type == "PROMOTION_SPONTANEOUS_HEALING" ) then
			healID = row.ID;
		end
		if( row.Type == "PROMOTION_SYNTHESIS" ) then
			synthID = row.ID;
		end
	end
-- If you're just using my mod, these will be promotions #161, 162, and 163
--	print("In StartCombat");

	if( iAttackingUnit ~= -1 ) then
		aPlayer = Players[iAttackingPlayer];
		for pUnit in aPlayer:Units() do
			if( pUnit:GetID() == iAttackingUnit ) then
				aUnit = pUnit;
			end
		end
		aType = aUnit:GetUnitType();
		aName = GameInfo.Units[aType].Type
		aCombatClass = GameInfo.Units[aType].CombatClass;
		aSTR = math.max(GameInfo.Units[aType].Combat, GameInfo.Units[aType].RangedCombat);

		if( aUnit:IsHasPromotion(healID) ) then
-- 10% chance of healing 5 damage
			local diceroll = Map.Rand(10, "Spontaneous Healing chance");
			if( diceroll == 0 ) then
				print("Troll critical heal!");
				aUnit:ChangeDamage(-5,aPlayer);
			end
		end
	end

	if( iDefendingUnit ~= -1 ) then
		dPlayer = Players[iDefendingPlayer];
		for pUnit in dPlayer:Units() do
			if( pUnit:GetID() == iDefendingUnit ) then
				dUnit = pUnit;
			end
		end
		dType = dUnit:GetUnitType();
		dName = GameInfo.Units[dType].Type
		dCombatClass = GameInfo.Units[dType].CombatClass;
		dSTR = math.max(GameInfo.Units[dType].Combat, GameInfo.Units[dType].RangedCombat);

		if( dUnit:IsHasPromotion(healID) ) then
-- 10% chance of healing 5 damage
			local diceroll = Map.Rand(10, "Spontaneous Healing chance");
			if( diceroll == 0 ) then
				print("Troll critical heal!");
				dUnit:ChangeDamage(-5,dPlayer);
			end
		end
	end

-- The spontaneous healing promotion is the only one that doesn't depend on its opponent.  For the others, we need to ensure they don't trigger when fighting a city.
	if( iAttackingUnit ~= -1 and iDefendingUnit ~= -1 ) then
		if( aUnit:IsHasPromotion(critID) ) then
-- 10% chance of +5 damage
			local diceroll = Map.Rand(10, "Critical Strike chance");
			if( diceroll == 0 ) then
				print("Ranger critical hit!");
				dUnit:ChangeDamage(5,dPlayer);
			end
		end
		if( aCombatClass == "UNITCOMBAT_PSI" and dCombatClass ~= "UNITCOMBAT_PSI" ) then
			if( dSTR > (1.25*aSTR) ) then
				aSTR_new = 1.25*aSTR;
			elseif( dSTR < (0.75*aSTR) ) then
				aSTR_new = 0.75*aSTR;
			else
				aSTR_new = dSTR;
			end
			print("Psi attack change! Old: ",aSTR,"  New: ",aSTR_new);
			aUnit:SetBaseCombatStrength(aSTR_new);
--			aSTR = aSTR_new;
		end

-- Now, alter the defending unit.
		if( dUnit:IsHasPromotion(critID) ) then
-- 10% chance of +5 damage
			local diceroll = Map.Rand(10, "Critical Strike chance");
			if( diceroll == 0 ) then
				print("Ranger critical hit!");
				aUnit:ChangeDamage(5,aPlayer);
			end
		end
		if( dCombatClass == "UNITCOMBAT_PSI" and aCombatClass ~= "UNITCOMBAT_PSI" ) then
			if( aSTR > (1.25*dSTR) ) then
				dSTR_new = 1.25*dSTR;
			elseif( aSTR < (0.75*dSTR) ) then
				dSTR_new = 0.75*dSTR;
			else
				dSTR_new = aSTR;
			end
			print("Psi defense change! Old: ",dSTR,"  New: ",dSTR_new);
			dUnit:SetBaseCombatStrength(dSTR_new);
		end
	end
end
Events.RunCombatSim.Add( SpatzStartCombat );

So in your case, you'd just want to compare the "iAttackingUnitFinalDamage" and "iAttackingUnitMaxHitPoints" entries (and the corresponding ones for the defender) within the function call to see if enough damage was dealt to kill the unit, and if so, then award the money.

Now, you'll note I check the attacking and defending units for -1. That's because if a unit attacks a city, or vice versa, it calls this function as well, but there's no unit ID for cities, so they all just get listed as -1 with no indication about WHICH city it was. So before you go running your GetUnitByID function, you need to make sure it's not -1 first, or else I don't know WHAT it'll do.
 
Yes. In fact, that's part of the problem; for my own mod, I wanted certain parts of it to NOT trigger on a ranged attack. It's easy enough to check whether the attacking unit has a ranged attack rating, but there's no way to be sure he's actually using it, since ranged units can still attack in melee unless they have a specific negative promotion.

I suppose you could just check to see if the attacker takes damage in the course of that combat, which'd tell you whether it was a ranged attack or not. But that's not really the best method either.
 
This may sound dumb, but could you make a step-by-step guide for that? My objective is a chance of 70% of giving a random amount of gold ($10-$30) if the galleon sinks a ship with its ranged attack.

Thanks in advance.
 
Back
Top Bottom