Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


functions not recognized nor run

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting
View previous topic :: View next topic  
Author Message
bknight2602
Grandmaster Cheater
Reputation: 0

Joined: 08 Oct 2012
Posts: 591

PostPosted: Sun Feb 08, 2026 8:16 am    Post subject: functions not recognized nor run Reply with quote

[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
View user's profile Send private message Yahoo Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1554

PostPosted: Sun Feb 08, 2026 10:42 am    Post subject: Reply with quote

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.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
bknight2602
Grandmaster Cheater
Reputation: 0

Joined: 08 Oct 2012
Posts: 591

PostPosted: Sun Feb 08, 2026 12:51 pm    Post subject: Reply with quote

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
View user's profile Send private message Yahoo Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1554

PostPosted: Mon Feb 09, 2026 9:12 am    Post subject: Reply with quote

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.

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
bknight2602
Grandmaster Cheater
Reputation: 0

Joined: 08 Oct 2012
Posts: 591

PostPosted: Sat Feb 14, 2026 12:27 pm    Post subject: Reply with quote

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
View user's profile Send private message Yahoo Messenger
AylinCE
Grandmaster Cheater Supreme
Reputation: 37

Joined: 16 Feb 2017
Posts: 1554

PostPosted: Sun Feb 15, 2026 8:46 am    Post subject: Reply with quote

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!

_________________
Hi Hitler Different Trainer forms for you!
https://forum.cheatengine.org/viewtopic.php?t=619279
Enthusiastic people: Always one step ahead
Do not underestimate me Master: You were a beginner in the past
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> Cheat Engine Lua Scripting All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites