 |
Cheat Engine The Official Site of Cheat Engine
|
| View previous topic :: View next topic |
| Author |
Message |
bknight2602 Grandmaster Cheater
Reputation: 0
Joined: 08 Oct 2012 Posts: 591
|
Posted: Sun Feb 08, 2026 8:16 am Post subject: functions not recognized nor run |
|
|
[quote="AylinCE"] | bknight2602 wrote: | I had tried that but alas that has an error also ...
The error that is apparent at first glance:
Define first, then call, use!
|
Well let us redefine the issue. Some of this code was in the game written by someone else. I only added other parts to define aspects for me namely AddSkills() and addperks(). Those are the functions that don't work, and you will note they are in the sequence of define first and the run. I played the game last night and remembered addperks did not work either.
| Quote: |
In your case, the following is happening:
| Code: | function TownCounter1()
print("Towncount of player1 = ",Town_count1()," with main hero:",h1 );
print(h1);
if Town_count1() == 8 and IsHeroAlive(h1) == 1 then -->> nil ! -->>> Town_count1() (Undefined)
---- ...
end
-- It's defined below, but attempts are being made to use it in the lines above ...
function Town_count1()
count = 0;
return count;
end; |
Try using it like this:
| Code: | -- Define:
function Town_count1()
count = 0;
return count;
end;
function TownCounter1()
print("Towncount of player1 = ",Town_count1()," with main hero:",h1 );
print(h1);
if Town_count1() == 8 and IsHeroAlive(h1) == 1 then -->> success -->>> Town_count1() (Defined at the top!)
---- ...
end |
These pieces of code work even though they are out of sequence.
|
The game code worked until I inserted my lines, even though they were out of sequence. So lets get back to my question, first how to call a function and you answered that one. Thank you.
When the line was changed to AddSkills() (and addperks()) the game reports a nil value calling either function. Why? How to rectify?
It must be stated that after I removed the calls except in the line near the bottom
| Code: |
Trigger(PLAYER_ADD_HERO_TRIGGER,PLAYER_1, "AddSkills"); | The game code runs with no errors. When a hero is hired the game reports attempting to call a nil value.
ETA: Here is the original code sequence that works
| Code: |
town_array = {"T1","T2","T3","T4", "T5","T6","T7","T8"};
town_array.n = 8;
count = 0;
countx= 0;
y = GetPlayerHeroes(1);
h1 = y[0];
a = GetPlayerHeroes(2);
h2 = a[0];
function TownCounter1()
print("Towncount of player1 = ",Town_count1()," with main hero:",h1 );
print(h1);
if Town_count1() == 8 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,610350);
elseif Town_count1() == 7 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,244140);
SetAIPlayerAttractor("T8", 1, 1);
elseif Town_count1() == 6 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,97650);
SetAIPlayerAttractor("T7", 1, 1);
elseif Town_count1() == 5 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,39060);
SetAIPlayerAttractor("T6", 1, 1);
elseif Town_count1() == 4 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,15620);
SetAIPlayerAttractor("T5", 1, 1);
elseif Town_count1() == 3 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,6250);
SetAIPlayerAttractor("T4", 1, 1);
elseif Town_count1() == 2 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,2500);
SetAIPlayerAttractor("T3", 1, 1);
print("hero1 166exp");
elseif Town_count1() == 1 and IsHeroAlive(h1) == 1 then
ChangeHeroStat(h1,0,1000);
SetAIPlayerAttractor("T2", 1, 1);
print(" hero1 50exp");
end;
end;
function Town_count1()
count = 0;
for i=1, town_array.n do
if ( GetObjectOwner(town_array[i]) == PLAYER_1 ) then
count = count + 1;
end;
end;
return count;
end;
function TownCounter2()
print( "Towncount of player2 = ",Town_count2()," with mainhero:", h2 );
if Town_count2() == 8 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,61035);
elseif Town_count2() == 7 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,24414);
SetAIPlayerAttractor("T8", 2, 1);
elseif Town_count2() == 6 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,9765);
SetAIPlayerAttractor("T7", 2, 1);
elseif Town_count2() == 5 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,3096);
SetAIPlayerAttractor("T6", 2, 1);
elseif Town_count2() == 4 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,1562);
SetAIPlayerAttractor("T5", 2, 1);
elseif Town_count2() == 3 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,625);
SetAIPlayerAttractor("T4", 2, 1);
elseif Town_count2() == 2 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,250);
SetAIPlayerAttractor("T3", 2, 1);
elseif Town_count2() == 1 and IsHeroAlive(h2) == 1 then
ChangeHeroStat(h2,0,100);
SetAIPlayerAttractor("T2", 2, 1);
end;
end;
function Town_count2()
countx = 0;
for i=1, town_array.n do
if ( GetObjectOwner(town_array[i]) == PLAYER_2 ) then
countx = countx + 1;
end;
end;
return countx;
end;
function SwitchTown1()
if GetObjectOwner("T1") == 2 then
TransformTown("T1", 4);
end;
end;
function SwitchTown2()
if GetObjectOwner("T2") == 1 then
TransformTown("T2", 0);
print("T2 = heaven");
elseif GetObjectOwner("T2") == 2 then --and GetObjectOwner("T7") == 2 and GetObjectOwner("T6") == 2 and GetObjectOwner("T5") == 2 and GetObjectOwner("T4") == 2 and GetObjectOwner("T3") == 2 then
TransformTown("T2", 4);
print("T2 = necro");
end;
end;
function SwitchTown3()
if GetObjectOwner("T3") == 1 then
TransformTown("T3", 0);
print("T3 = heaven");
elseif GetObjectOwner("T3") == 2 then --and GetObjectOwner("T7") == 2 and GetObjectOwner("T6") == 2 and GetObjectOwner("T5") == 2 and GetObjectOwner("T4") == 2 then
TransformTown("T3", 4);
print("t3 = necro");
end;
end;
function SwitchTown4()
if GetObjectOwner("T4") == 1 then --and GetObjectOwner("T2") == 1 and GetObjectOwner("T3") == 1 then
TransformTown("T4", 0);
print("T4=Heaven");
elseif GetObjectOwner("T4") == 2 then --and GetObjectOwner("T7") == 2 and GetObjectOwner("T6") == 2 then
TransformTown("T4", 4);
print("T4 = Necro");
end;
end;
function SwitchTown5()
if GetObjectOwner("T5") == 1 then --and GetObjectOwner("T2") == 1 and GetObjectOwner("T3") == 1 then
TransformTown("T5", 0);
print("T5=Heaven");
elseif GetObjectOwner("T5") == 2 then --and GetObjectOwner("T7") == 2 and GetObjectOwner("T6") == 2 then
TransformTown("T5", 4);
print("T5 = Necro");
end;
end;
function SwitchTown6()
if GetObjectOwner("T6") == 1 then --and GetObjectOwner("T2") == 1 and GetObjectOwner("T3") == 1 and GetObjectOwner("T4") == 1 and GetObjectOwner("T5") == 1 then
TransformTown("T6", 0);
print("T6=Heaven");
elseif GetObjectOwner("T6") == 2 then --and GetObjectOwner("T7") == 2 then
TransformTown("T6", 4);
print("T6 = Necro");
end;
end;
function SwitchTown7()
if GetObjectOwner("T7") == 1 then --and GetObjectOwner("T2") == 1 and GetObjectOwner("T3") == 1 and GetObjectOwner("T4") == 1 and GetObjectOwner("T5") == 1 and GetObjectOwner("T6") == 1 then
TransformTown("T7", 0);
print("T7=Heaven");
elseif GetObjectOwner("T7") == 2 then
TransformTown("T7", 4);
print("T7 = Necro");
end;
end;
function SwitchTown8()
if GetObjectOwner("T8") == 1 then
TransformTown("T8", 0);
end;
end;
Trigger(OBJECT_CAPTURE_TRIGGER, "T1", "SwitchTown1")
Trigger(OBJECT_CAPTURE_TRIGGER, "T2", "SwitchTown2")
Trigger(OBJECT_CAPTURE_TRIGGER, "T3", "SwitchTown3")
Trigger(OBJECT_CAPTURE_TRIGGER, "T4", "SwitchTown4")
Trigger(OBJECT_CAPTURE_TRIGGER, "T5", "SwitchTown5")
Trigger(OBJECT_CAPTURE_TRIGGER, "T6", "SwitchTown6")
Trigger(OBJECT_CAPTURE_TRIGGER, "T7", "SwitchTown7")
Trigger(OBJECT_CAPTURE_TRIGGER, "T8", "SwitchTown8")
Trigger(NEW_DAY_TRIGGER,"Test");
function Test()
y = GetPlayerHeroes(1);
h1 = y[0];
a = GetPlayerHeroes(2);
h2 = a[0];
print(count);
print(countx);
TownCounter1()
TownCounter2()
end;
|
|
|
| Back to top |
|
 |
AylinCE Grandmaster Cheater Supreme
Reputation: 37
Joined: 16 Feb 2017 Posts: 1554
|
Posted: Sun Feb 08, 2026 10:42 am Post subject: |
|
|
The error persists because even if you define the sequence, there are two critical issues that commonly trigger a 'nil value' in HoMM V scripting when using triggers.
1. The Argument Pass Issue When you use Trigger(PLAYER_ADD_HERO_TRIGGER, PLAYER_1, "AddSkills");, the game engine automatically passes the name of the hero being hired as an argument to that function.
If your function is defined without a parameter, it can't handle the incoming data.
2. Case Sensitivity & Scope Lua is strictly case-sensitive.
If there is even a single letter difference between the trigger string "AddSkills" and the function AddSkills(), it will return nil.
Recommended Fix
You should restructure your added functions like this (place them above the triggers):
| Code: | -- Use a parameter (e.g., 'hero') to catch the name from the trigger
function AddSkills(hero)
print("Assigning skills to: ", hero);
-- Ensure you are using the 'hero' variable provided by the trigger
-- Example: GiveHeroSkill(hero, 1);
end
function addperks(hero)
print("Assigning perks to: ", hero);
-- Perk logic here...
end |
Why it failed before: In your original working code, you were using global variables like h1 and h2 which were defined at the start.
However, when a new hero is hired via PLAYER_ADD_HERO_TRIGGER, that hero isn't h1 or h2 yet.
The game tries to find a function that can accept the new hero's name, finds a mismatch or a nil reference, and crashes the script.
Checklist:
Make sure function AddSkills(hero) is defined before the Trigger line.
Verify that the spelling in the Trigger matches the function name exactly.
Check if you are calling any other variables inside AddSkills that might be nil at the moment the hero is hired.
_________________
|
|
| Back to top |
|
 |
bknight2602 Grandmaster Cheater
Reputation: 0
Joined: 08 Oct 2012 Posts: 591
|
Posted: Sun Feb 08, 2026 12:51 pm Post subject: |
|
|
| AylinCE wrote: | The error persists because even if you define the sequence, there are two critical issues that commonly trigger a 'nil value' in HoMM V scripting when using triggers.
1. The Argument Pass Issue When you use Trigger(PLAYER_ADD_HERO_TRIGGER, PLAYER_1, "AddSkills");, the game engine automatically passes the name of the hero being hired as an argument to that function.
If your function is defined without a parameter, it can't handle the incoming data.
2. Case Sensitivity & Scope Lua is strictly case-sensitive.
If there is even a single letter difference between the trigger string "AddSkills" and the function AddSkills(), it will return nil.
Recommended Fix
You should restructure your added functions like this (place them above the triggers):
|
1. The trigger is exact from documentation. This is a bit of code developed many years ago and functions correctly in all games tested, except this particular map , albeit I have not tested all games.
2. Case sensitivity works "everywhere" and has not created issues. | Quote: |
| Code: | -- Use a parameter (e.g., 'hero') to catch the name from the trigger
function AddSkills(hero)
print The functions are encountered before the triggers("Assigning skills to: ", hero);
-- Ensure you are using the 'hero' variable provided by the trigger
-- Example: GiveHeroSkill(hero, 1);
end
function addperks(hero)
print("Assigning perks to: ", hero);
-- Perk logic here...
end |
Why it failed before: In your original working code, you were using global variables like h1 and h2 which were defined at the start.
However, when a new hero is hired via PLAYER_ADD_HERO_TRIGGER, that hero isn't h1 or h2 yet.
The game tries to find a function that can accept the new hero's name, finds a mismatch or a nil reference, and crashes the script.
Checklist:
Make sure function AddSkills(hero) is defined before the Trigger line.
Verify that the spelling in the Trigger matches the function name exactly.
Check if you are calling any other variables inside AddSkills that might be nil at the moment the hero is hired. |
Basically, you are telling me that my code AddSkills won't work because of the h1 and h2
I can live with that and ramification of not having my code execute. I do have another question that does crop up from time to time I have alsways in my code set playernames = GetPlayerNames(# of player) then later I assign player with all the goodies in for loops using playernames[i]. Some times this craters as I get an error code telling me wrong number of arguments or nil arguments from that declaration. That is normally fixed by just restarting map. But the question why this occurs sometimes but all the time as it works most of the time. Is it just a quirk in how codes are interpreted by the game?
Thanks
|
|
| Back to top |
|
 |
AylinCE Grandmaster Cheater Supreme
Reputation: 37
Joined: 16 Feb 2017 Posts: 1554
|
Posted: Mon Feb 09, 2026 9:12 am Post subject: |
|
|
The issue you're describing with GetPlayerNames is a classic 'race condition' in game scripting.
It’s not necessarily a quirk of how the code is interpreted, but rather when it is interpreted.
Here is why it happens intermittently:
Initialization Timing:
When a map first loads, the script starts executing immediately.
Sometimes, the script reaches the GetPlayerNames line before the game engine has fully initialized the player slots or retrieved the network data (especially in multiplayer or maps with complex AI setups).
If the engine isn't 'ready,' it returns a nil or an unexpected number of arguments.
Memory State: When you restart the map, the game engine is already 'warm' and the data is often already cached in memory, which is why a restart usually fixes it.
How to make it more stable:
Instead of calling it globally at the very top of the script, try wrapping it in a small delay or calling it inside a specific initialization function.
For example:
| Code: | -- Instead of just: playernames = GetPlayerNames(8)
-- Try checking if it exists before using it in your loops:
function SafeInit()
playernames = GetPlayerNames(8);
if playernames ~= nil then
for i, name in playernames do
-- assign your goodies here
end
else
-- If it fails, we can trigger a small timer to try again in 1 second
print("Warning: Player data not ready, retrying...");
end
end
-- Call this after the map has had a moment to breathe
Trigger(NEW_DAY_TRIGGER, "SafeInit"); |
Basically, if the code works 'most of the time,' your logic is correct, but your timing is just a bit too fast for the game engine's loading process.
Moving these assignments away from the 'instant-load' phase and into a trigger (like the first NEW_DAY or a specific Timer) usually solves these ghost errors permanently.
_________________
|
|
| Back to top |
|
 |
bknight2602 Grandmaster Cheater
Reputation: 0
Joined: 08 Oct 2012 Posts: 591
|
Posted: Sat Feb 14, 2026 12:27 pm Post subject: |
|
|
I will try moving the GetPlayerHeroes() further down and implementing your "delay"
There is a issue that I think I see, when a hero is hired GetPlayerHeroes will add the new hero to the table and length will change also, but if GetPlayerHeroes isn't rerun it will be wrong, correct?
|
|
| Back to top |
|
 |
AylinCE Grandmaster Cheater Supreme
Reputation: 37
Joined: 16 Feb 2017 Posts: 1554
|
Posted: Sun Feb 15, 2026 8:46 am Post subject: |
|
|
You hit the nail on the head! You are absolutely correct:
GetPlayerHeroes() returns a static table (a snapshot) of the heroes present at the exact moment the function is called.
If a player hires a new hero 5 minutes later, your playernames or playerheroes table will not automatically update. It doesn't have a "live link" to the game engine's memory; it’s just a copy of what existed at Time X.
To keep your script accurate, you have two main options:
1. The "Polling" Method (Simple but slightly heavier)
Instead of running the check once at the start, you run your logic inside a recurring trigger (e.g., every day or every few turns).
| Code: | function UpdateHeroData()
local heroes = GetPlayerHeroes(8)
-- Refresh your logic here
end
-- Set a timer or a recurring trigger to call this regularly |
2. The "Event-Based" Method (Cleaner)
If the game engine supports it, you can link your function to a specific event, such as a hero recruitment trigger. This way, the table only updates when it actually needs to.
3. Global vs Local Scope
If you want to access the latest data across different functions, make sure you aren't shadowing your variables. Update a global table so that all your other functions are reading the most recent "snapshot."
Quick Tip: If you're looping through these tables frequently, always check the current length using the # operator (if it's a standard Lua table) or the game's specific count function right before the loop starts.
Moving the initialization further down will solve your "nil" race condition, but keeping it inside a repeatable function will solve your "stale data" problem.
Good luck with the implementation!
_________________
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|