Heroes of Might and Magic Community
visiting hero! Register | Today's Posts | Games | Search! | FAQ/Rules | AvatarList | MemberList | Profile


Age of Heroes Headlines:  
5 Oct 2016: Heroes VII development comes to an end.. - read more
6 Aug 2016: Troubled Heroes VII Expansion Release - read more
26 Apr 2016: Heroes VII XPack - Trial by Fire - Coming out in June! - read more
17 Apr 2016: Global Alternative Creatures MOD for H7 after 1.8 Patch! - read more
7 Mar 2016: Romero launches a Piano Sonata Album Kickstarter! - read more
19 Feb 2016: Heroes 5.5 RC6, Heroes VII patch 1.7 are out! - read more
13 Jan 2016: Horn of the Abyss 1.4 Available for Download! - read more
17 Dec 2015: Heroes 5.5 update, 1.6 out for H7 - read more
23 Nov 2015: H7 1.4 & 1.5 patches Released - read more
31 Oct 2015: First H7 patches are out, End of DoC development - read more
5 Oct 2016: Heroes VII development comes to an end.. - read more
[X] Remove Ads
LOGIN:     Username:     Password:         [ Register ]
HOMM1: info forum | HOMM2: info forum | HOMM3: info mods forum | HOMM4: info CTG forum | HOMM5: info mods forum | MMH6: wiki forum | MMH7: wiki forum
Heroes Community > Heroes 5 - Modders Workshop > Thread: Programming help, please
Thread: Programming help, please
bknight2602
bknight2602


Hired Hero
posted October 11, 2013 05:18 PM

Programming help, please

I'm attempting to program some script when an enemy attacks.  I want to use AddCreature function, but all I get when the script compiles and the start of a map is something like a nil function.  I know it only works in combat situations so how do I use it and get by the error message?

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 11, 2013 05:37 PM

Could you paste the script where you are using this function? It could be useful for finding what is wrong.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 12, 2013 12:50 AM

This probably won't help you, however
AddCreature(1, 44, 100, 5, 5)

It needs to be after combat has started.  I used Start() and Prepare() like:
if Start() then--Prepare()
AddCreature(1, 44, 100, 5, 5)
end;
Upon compile error something like the function is nil or doesn't exist

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 12, 2013 11:53 AM

I don't think that your problem is with AddCreature function, but with Start() and Prepare() functions. You are trying to use those functions in if statement, and they are not to be used like that. I believe that nil error comes from there: statement if Start() implies that start must return boolean, ant it doesn't.

Start() and Prepare() functions are called at the beggining of battle, you don't call them explicitely. What you can do is to 'overload' them:

function Start()
your code here;
end;

function Prepare()
your code here;
end;

Good examples are combat scripts from academy scenario 5 in Heroes 5 vanilla (when Godric, Raelag, Findan and Zehir fight Biara and Demon Sovereign), because they are all scripted. I hope this helps a bit.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 12, 2013 04:16 PM
Edited by bknight2602 at 16:22, 12 Oct 2013.

Actually I had tried that without success.  I tried it again this morning:
function anycombat()
while 1 do
function Start()
if IsHuman(1)  == 1 then
dc = GetDefenderCreatures();
for i = 0, length(dc) - 1 do
if dc == 30 then
AddCreature(1, 30, 100, 15, 15);
elseif dc == 1 then
AddCreature(1, 4, 100, 15, 15);
end;
end;
end;
end;
end;
end;

startThread(anycombat);

Note the code shown is not correct there are square brackets after the dc's with and i in the brackets.

Without the while statement nothing happened on a combat, so I entered the while statement.  When the game loads normally and the selected bonus screen is finished the dialog cutscene plays(good thing the code seems to compile and the game compiled without the while statement).  After the cutscene is finished the game freezes with music playing in the back ground.  Ctrl-Alt-Delete shut down the game.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 12, 2013 11:19 PM

Quote:
function anycombat()
while 1 do
function Start()
if IsHuman(1)  == 1 then
dc = GetDefenderCreatures();
for i = 0, length(dc) - 1 do
if dc == 30 then
AddCreature(1, 30, 100, 15, 15);
elseif dc == 1 then
AddCreature(1, 4, 100, 15, 15);
end;
end;
end;
end;
end;
end;


Well I think few things are off here. First, the reason why this freezes is following: you put while 1 do, but you dont put any sleep() function in your anycombat(). You have to put sleep() in order to give other threads chance to do some job. Second, you can't declare function start() in another function (anycombat()). start() should be declared similar to anycombat(), not in body of another function.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 13, 2013 12:56 AM

I didn't know one must put a sleep() in a while 1 do, thanks.
However that didn't solve the question.  While awaiting some replies I tinkered and toyed with the code, the last being.
function Start()
while 1 do
if IsHuman(1) == 1 then
print("The defending side is human");
dc = GetDefenderCreatures();
for i = 0, length(dc) - 1 do
if dc == 30 then
AddCreature(1, 30, 100, 15, 15);
break;
elseif dc == 1 then
AddCreature(1, 4, 100, 15, 15);
break;
end;
end;
else
print("The attacking side is human");
end;
end;
end;

Unfortunately when the coded was compiled I did receive and error message that: Value was nil when getting global with name IsHuman: attempt to call a nil value.  During combat the prepare, start IsHuman don't give error messages.
In fact all the codes listed in the combat documentation don't work outside of combat, the only one that doesn't give the error is Start().
Now inside combat when Start() and Prepare() are evoked through the console nothing happens, but no error code either.

I did more tweaking and any of the commands ouside combat gave the same error message, including AddCreature.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 13, 2013 01:10 PM
Edited by frostymuaddib at 17:30, 13 Oct 2013.

The reason why you get nil for IsHuman() is that this function returns true/false and you check that it returns 1. My guess is that kua searches for function IsHuman() that returns int, and can't find it and says it is nil. Try with just if IsHuman(1) then.

Here are two scripts from heroes 5 campaigns that are used for combat, they may help you:

First script
Second script

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 13, 2013 05:09 PM

The second file was a xdb files pointing to the script of the same name. I assume you mean the lua from C6M5, if that is so thanks I have it but never looked at it.
I find a command SummonCreature(DEFENDER, 20, 55 + d * 5, 7, 12);, which is not in the documentation.  That may be the secret.  I'll give it a try.
The first, not sure which mission it is from but that gives some help as it has Finish(ATTACKER); another undocumented command.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 13, 2013 05:32 PM

Sorry for the wrong file, I wasn't looking at the extension. I fixed the link. As for undocumented functions, there is a fine thread about them.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 13, 2013 06:43 PM

Yes looked at that and posted the same question as in this thread, because the rules would not allow me to post a new topic.
Both of what I mentioned aren't in his list.  I wonder how many more exist to the developers.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 14, 2013 01:09 AM
Edited by bknight2602 at 02:22, 14 Oct 2013.

frostymuaddib said:
The reason why you get nil for IsHuman() is that this function returns true/false and you check that it returns 1. My guess is that kua searches for function IsHuman() that returns int, and can't find it and says it is nil. Try with just if IsHuman(1) then.

Here are two scripts from heroes 5 campaigns that are used for combat, they may help you:

[url=http://www.speedyshare.com/TvF3R/Godric.lua]First script[/url]
[url=http://speedy.sh/Wsg66/biara-raelag.lua]Second script[/url]



When you invoke the function IsHuman(1) in the console and if the computer AI hero is attacking then the value is 1.  That is why I searched for 1.
In the Godric code there is a line:
len = length(GetDefenderCreatures());  My last attempt yesterday when I kept getting the error on IsHuman, I commented the IsHuman out and ran this:
dc = GetDefenderCreatures(); and got the same type of error as the IsHuman.  I don't understand how one compiles and error and the other one doesn't.  But I never checked the console when running that particular mission.  BTW which mission is it from?
Anyway I started to re-code and come up with a stumbling block, namely I'm trying to make a generic code that would work on any map and I don't know which side is the DEFENDER or ATTACKER.  The two examples you passed dealt with a specific hero(s) nit generic.  I still need to be able to do that.

I will try your suggestion with the IsHuman and post another reply.

EDIT: Tried two different codes:
1. if IsHuman(1) then
2. Took out all the commands after @Start() and put in
dc = length(GetDefenderCreatures() - 1)
In both cases the same error occurred, after the cut scene finished and the console opened:
Value was NIL when getting global with name 'IsHuman' or 'GetDefenderCreatures'.  Attempt to call a nil value

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 14, 2013 01:17 PM

Quote:
When you invoke the function IsHuman(1) in the console and if the computer AI hero is attacking then the value is 1.  That is why I searched for 1.


Well in documantation it says nil and not nil, but it wouldn't be the first time documents were wrong.

Quote:
BTW which mission is it from?


It is from the last mission for Markal (I think it is C3M5) when he is fighting Godric in Academy town.

Quote:
Anyway I started to re-code and come up with a stumbling block, namely I'm trying to make a generic code that would work on any map and I don't know which side is the DEFENDER or ATTACKER.  The two examples you passed dealt with a specific hero(s) nit generic.  I still need to be able to do that.


I'm sorry I can't be of much help here then, because all the combat scripting I did was concerning some specific hero. I will experiment with this a little if I have the time (my exams are killing me at the moment ) and will let you know the results.

The only other reason I can think of for getting nil when calling those functions would be to call them outside of combat, but I doubt that is the case.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 14, 2013 02:44 PM

Good luck on the exams.  
I can't answer your question about the call, although from experience if one tries to invoke a combat function the same error occurs.  Conversely if map scripts are attempted while in combat the same error message occurs.

Try mission C3M2 as the wizards attack on day 3 or 4.

I ran C3M5 and I believe you to be correct that was the code you sent.  There were SOMANY errors in the console I don't know if the AddCreatures were one of the errors.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
frostymuaddib
frostymuaddib


Promising
Supreme Hero
育碧是白痴
posted October 15, 2013 10:21 PM

I remembered something that may be useful to you. You should check data.pak/scripts/combat-startup.lua. That script should be called every time a combat starts. I think that if you want to call a script for every combat, you should add it here (in Prepare() and Start()). Also I think you can override most of these methods. I haven't had time to try that though. Keep in mind that this is more modding than mapmaking.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
bknight2602
bknight2602


Hired Hero
posted October 16, 2013 12:57 AM

frostymuaddib said:
I remembered something that may be useful to you. You should check data.pak/scripts/combat-startup.lua. That script should be called every time a combat starts. I think that if you want to call a script for every combat, you should add it here (in Prepare() and Start()). Also I think you can override most of these methods. I haven't had time to try that though. Keep in mind that this is more modding than mapmaking.

[code]
doFile("/scripts/combat-common.lua")

function IsHuman(side) return GetHost(side) == HUMAN end
function IsComputer(side) return GetHost(side) == COMPUTER end

MODE_NORMAL = 0
MODE_MANUAL = 1
MODE_AUTO = 2

ATTACKER = 0
DEFENDER = 1

HERO = 0
CREATURE = 1
WAR_MACHINE = 2
BUILDING = 3
SPELL_SPAWN = 4

function IsAttacker(unit) return GetUnitSide(unit) == ATTACKER end
function IsDefender(unit) return GetUnitSide(unit) == DEFENDER end
function IsHero(unit) return GetUnitType(unit) == HERO end
function IsCreature(unit) return GetUnitType(unit) == CREATURE end
function IsWarMachine(unit) return GetUnitType(unit) == WAR_MACHINE end
function IsBuilding(unit) return GetUnitType(unit) == BUILDING end
function IsSpellSpawn(unit) return GetUnitType(unit) == SPELL_SPAWN end

function GetHero(side)
local units = GetUnits(side, HERO)
local units_count = length(units)
if (units_count > 1) then
_ERRORMESSAGE('Internal error: army has more than one hero')
end
for index, unit in units do
return unit
end
return nil
end
-- Warning!!! Do not remove variables 'temp' in these functions:
-- due the lua engine error game may (and probably will) crash.
function GetCreatures(side) local temp = GetUnits(side, CREATURE) return temp end
function GetWarMachines(side) local temp = GetUnits(side, WAR_MACHINE) return temp end
function GetBuildings(side) local temp = GetUnits(side, BUILDING) return temp end
function GetSpellSpawns(side) local temp = GetUnits(side, SPELL_SPAWN) return temp end

function GetAttackerHero() local temp = GetHero(ATTACKER) return temp end
function GetDefenderHero() local temp = GetHero(DEFENDER) return temp end
function GetAttackerCreatures() local temp = GetCreatures(ATTACKER) return temp end
function GetDefenderCreatures() local temp = GetCreatures(DEFENDER) return temp end
function GetAttackerWarMachines() local temp = GetWarMachines(ATTACKER) return temp end
function GetDefenderWarMachines() local temp = GetWarMachines(DEFENDER) return temp end
function GetAttackerBuildings() local temp = GetBuildings(ATTACKER) return temp end
function GetDefenderBuildings() local temp = GetBuildings(DEFENDER) return temp end
function GetAttackerSpellSpawns() local temp = GetSpellSpawns(ATTACKER) return temp end
function GetDefenderSpellSpawns() local temp = GetSpellSpawns(DEFENDER) return temp end

function GetWarMachine(side, type)
local units = GetWarMachines(side)
for index, unit in units do
if GetWarMachineType(unit) == type then
return unit
end
end
return nil
end
function GetAttackerWarMachine(type) local temp = GetWarMachine(ATTACKER, type) return temp end
function GetDefenderWarMachine(type) local temp = GetWarMachine(DEFENDER, type) return temp end

function GetBuilding(side, type)
local units = GetBuildings(side)
for index, unit in units do
if GetBuildingType(unit) == type then
return unit
end
end
return nil
end
function GetAttackerBuilding(type) local temp = GetBuilding(ATTACKER, type) return temp end
function GetDefenderBuilding(type) local temp = GetBuilding(DEFENDER, type) return temp end


function createCombatAliases()
   --
   -- abilitiy IDs
   --
   ABILITY_BATTLE_DIVE = 15;
   ABILITY_BATTLE_DIVE_FINISH = 27;
   ABILITY_LAY_HANDS = 16;
   ABILITY_RESURRECT_ALLIES = 17;
   ABILITY_SCATTER_SHOT = 14;
   -- Inferno
   ABILITY_GATING = 155;
   ABILITY_FEAR = 143;
   ABILITY_SUMMON_BALOR = 146;
   ABILITY_EXPLOSION = 147;
   ABILITY_EXPLOSION_EFFECT = 148;
   ABILITY_CHAIN_SHOT_END_EFFECT = 150;
   ABILITY_MANA_DESTROY = 160;
   ABILITY_MANA_STEAL = 157;
   ABILITY_TELEPORTING_MOVE = 163;
   -- Necropolis
   ABILITY_LIFE_DRAIN = 168;
   ABILITY_MANA_DRAIN = 169;
   ABILITY_DEATH_CLOUD = 170;
   ABILITY_HARM_TOUCH = 171;


BUILDING_WALL = 1
BUILDING_GATE = 2
BUILDING_LEFT_TOWER = 3
BUILDING_BIG_TOWER = 4
BUILDING_MOAT = 5
BUILDING_RIGHT_TOWER = 6
BUILDING_MAGIC_WALL = 7


   --
   -- Animation Action Types
   --
   --INVISIBLE = 0
   IDLE = 1
   ONESHOT_STILL = 2
   ONESHOT = 3
   --MOVE = 4
   NON_ESSENTIAL = 5

   --
   -- dumb command aliasing
   --
   ExecConsoleCommand = consoleCmd

   ShowCombatHighlighting = showHighlighting;

   MoveCombatUnit = commandMove;
   AttackCombatUnit = commandMoveAttack;
   ShootCombatUnit = commandShot;
   UseCombatAbility = commandDoSpecial;
   DefendCombatUnit = commandDefend;
   GetCombatPosition = pos;
   SetCombatPosition = displace;
   IsCombatUnit = exist;
   AddCombatUnit = addUnit;
   RemoveCombatUnit = removeUnit;
end

function createTutorialAliases()
   -- tutorials
   --ShowTutorialMode = toggleTutorialMode
   --HideTutorialMode = toggleTutorialMode
   ShowTutorialMessage = showMessage;
   HideTutorialMessage = clearMessage;
end


function Prepare() end
function DoPrepare() -- FIXME: remove this
Prepare()
return nil
end

function Start() end
function DoStart() -- FIXME: remove this
Start()
return nil
end


function AttackerHeroMove(heroName) return nil end
function AttackerCreatureMove(creatureName) return nil end
function AttackerWarMachineMove(warMachineName) return nil end
function DefenderHeroMove(heroName) return nil end
function DefenderCreatureMove(creatureName) return nil end
function DefenderWarMachineMove(warMachineName) return nil end
function DefenderBuildingMove(buildingName) return nil end

function AttackerUnitMove(unitName)
local temp = nil
if IsHero(unitName) then
temp = AttackerHeroMove(unitName)
elseif IsCreature(unitName) then
temp = AttackerCreatureMove(unitName)
elseif IsWarMachine(unitName) then
temp = AttackerWarMachineMove(unitName)
elseif IsBuilding(unitName) then
temp = DefenderBuildingMove(unitName)
end
return temp
end
function DefenderUnitMove(unitName)
local temp = nil
if IsHero(unitName) then
temp = DefenderHeroMove(unitName)
elseif IsCreature(unitName) then
temp = DefenderCreatureMove(unitName)
elseif IsWarMachine(unitName) then
temp = DefenderWarMachineMove(unitName)
elseif IsBuilding(unitName) then
temp = DefenderBuildingMove(unitName)
end
return temp
end

function UnitMove(unitName)
local temp = nil
if IsAttacker(unitName) then
temp = AttackerUnitMove(unitName)
elseif IsDefender(unitName) then
temp = DefenderUnitMove(unitName)
end
return temp
end

function AttackerHeroDeath(heroName) end
function AttackerCreatureDeath(creatureName) end
function AttackerWarMachineDeath(warMachineName) end
function AttackerSpellSpawnDeath(buildingName) end
function DefenderHeroDeath(heroName) end
function DefenderCreatureDeath(creatureName) end
function DefenderWarMachineDeath(warMachineName) end
function DefenderBuildingDeath(buildingName) end
function DefenderSpellSpawnDeath(buildingName) end

function AttackerUnitDeath(unitName)
if IsHero(unitName) then
AttackerHeroDeath(unitName)
elseif IsCreature(unitName) then
AttackerCreatureDeath(unitName)
elseif IsWarMachine(unitName) then
AttackerWarMachineDeath(unitName)
elseif IsBuilding(unitName) then
DefenderBuildingDeath(unitName)
elseif IsSpellSpawn(unitName) then
AttackerSpellSpawnDeath(unitName)
end
end
function DefenderUnitDeath(unitName)
if IsHero(unitName) then
DefenderHeroDeath(unitName)
elseif IsCreature(unitName) then
DefenderCreatureDeath(unitName)
elseif IsWarMachine(unitName) then
DefenderWarMachineDeath(unitName)
elseif IsBuilding(unitName) then
DefenderBuildingDeath(unitName)
elseif IsSpellSpawn(unitName) then
DefenderSpellSpawnDeath(unitName)
end
end

function UnitDeath(unitName)
if IsAttacker(unitName) then
AttackerUnitDeath(unitName)
elseif IsDefender(unitName) then
DefenderUnitDeath(unitName)
end
end
[/code]

Gak almost every combat script.  I shall add it, although I don't understand how it won' t give and error message on line 3.
I had forgotten about the data.pak.  Do you remember where the statup bonus items are listed? I tinkered with some about 2 years ago but lost my lap and don't have my notes.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Jump To: « Prev Thread . . . Next Thread »
Post New Poll    Post New Topic    Post New Reply

Page compiled in 0.0763 seconds