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

<a href="http://www.game-advertising-online.com/" target=_blank>Game Advertising Online</a><br> banner requires iframes

LOGIN:     Username:     Password:         [ Register ]
HOMM1: info forum | HOMM2: info forum | HOMM3: info forum | HOMM4: info forum | HOMM5: info forum | MMH6: wiki forum | MMH7: wiki forum
Heroes Community > Heroes 3.5 - WoG and Beyond > Thread: ERM-->LUA
Thread: ERM-->LUA
Salamandre
Salamandre


Honorable
Undefeatable Hero
posted October 28, 2010 08:06 PM

ERM-->LUA

Thread created for LarvaExotech user.
____________

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

Tavern Dweller
posted October 28, 2010 10:06 PM

Hello!

I would want to introduce a new thing for Heroes 3 WOG, ERA Platworm by Berserker.

Its a .DLL file, still in development, which replaces standard ERM scripts with .LUA scripts.

I have already said why LUA is better than ERM in other topic, so I'll just quote myself:

Quote:

I cannot create my own temat for that so I will write here.

I'm developing a DLL for ERA platworm with LUA Scripting system instead of regular ERM. The cons of this solution are great:

> more language flexibility, allowing to create much better things with LUA (tables, iteration, datatypes etc)

> system reads all .LUA files from .\Data\Lua\ directory and scripts have their own variables, so one script won't mess another like in ERM (even with official 3.58f+script update, there are many variables used by several scripts at once and messing game, causing glitches like ballista named "The first aid tent heals ETC hitpoints" or creatures turning into first aid tents after battle, and even a glitch with 4095 wandering monsters (entering battle = CRASH). with LUA there is NO WAY for scripts to mess up themeselves as every script is handled by his own interface.

> also other "indexed" things like !!FU numbers are overlapping from script to script

> better looking code

> more interesting functions like including other files, math functions (like power, abs, min, max), even saving/loading things on xml, ini files, controlling mouse pointer, running winapi functions and much more

> better random generator as it now supports FOUR random generators:
* doGenerateRandomNumber(min, max) - generates random number using !!VR:T erm function
* lua math.random(min, max) - generates random number using LUA library function
* RandomNumber(min, max, seed) - generates random number using Pascal random number generator
* BoxMuller(min, max) - generates random number using box muller alghoritm

> MUCH more easier to develop a script for H3, a typical newbie-scripter dont have to read 32523523 pages of ERM manual and choosing clean variables from 358f_Claimed.txt, instead he runs a notepad and start writing

> I'm planning to develop a script editor for that as well

For now system works stable, and allows to use around 90% of "triggers" and around 40% of "receivers" from ERM (its using ERM interface). Also I icluded few nice things from this forum (like lua function that allows shooting with non-shooters, by Salamandre). It works like a some kind of wrapper:

instead of ERM -> Heroes3
we got LUA -> ERM -> Heroes3



The project is not finished, its still in development. If someone wants to check a BETA, UNTESTED and UNFINISHED LUAErm mod, here is the link:

http://www.speedyshare.com/files/24922358/_LUA_ERM.rar

Install instructions:

1. THIS REQUIRES A PLATWORM ERA 1.6 OR 1.8 BY BERSERKER. ENGLISH COMMUNITY VERSION IS ENOUGH TO MAKE IT WORK. IT CAN BE DOWNLOADED FROM WOGARCHIVE.RU AND PERHAPS FROM OTHER SITES.

2. RENAME YOUR HEROES3\DATA\S\ FOLDER TO SOMETHING OTHER (AS BACKUP), BECAUSE ALL SCRIPTS HAVE TO BE DELETED

< ~-- VERY IMPORTANT --~ >
3. MAKE SURE THAT IN YOUR DATA\S\ DIRECTORY, THERE ARE NO ERM SCRIPTS
< ~-- VERY IMPORTANT --~ >

4. UNPACK ARCHIVE INTO ROOT HEROES3 FOLDER

5. IF CORRECT, FILES WILL BE THERE:

> Heroes3\Celtica.dll
> Heroes3\lua.dll
> Heroes3\lualib.dll
> Heroes3\luareceivers.txt
> Heroes3\luatriggers.txt
> Heroes3\Data\lua\test.lua
> Heroes3\Data\lua\xxx.lua
> Heroes3\Data\lua\global\global.lua
> Heroes3\s\Script00.erm

6. LAUCH GAME AND START A SCENARIO. IF CORRENT, A DEBUG.TXT FILE WILL BE CREATED IN ROOT H3 DIRECTORY.

But beware! It wasnt supposed to be released now, its just untested and still in development. I have uploaded it, because I wanted to show that I'm doing real thing, not only words.

Most of receivers are still untested and not guarantee to work. The most part that's done are !!OB, !!UN, !!MO, !!SN and similar. The list of lua functions are in text files luareceivers.txt and luatriggers.txt.

---

How this does work?

After Heroes3 map is started, Celtica.dll is called from ERM. For now all scripts in .\Data\Lua\ directory are parsed and translated into byte code by LUA library. Now on certain events (90% of triggers are working now), lua functions from all files are called. LUA Functions are handled by Celtica.dll which passes variables out and in and calls standard ERM !!FU's from Script00.erm. The script00.erm should not be modified as its now only used as a engine.

Also few notes:

> saving and loading game is still not implemented. scripts should work after loading game, but its not handled and variables will get reset after loading. its just still not done yet.

> lua comments are strict and must start with two -- chars

> list of lua functions sometimes refer to "pos" as parameters/function results. pos is a lua table with three fiels - X,Y,Z.
in order to delete an object from pos 25/22/0, you must create a pos table and push it into function:

local ourBadPos = {x=25, y=22, z=0}
doDeleteObject(TRUE, ourBadPos)

if position is passed as parameter from a function, you can refer to it by typing this in script:

ourBadPos.x = 55  --this will set X of ourBadPos to 55
local mySuperVar = ourBadPos.y  --this will set mySuperVar equal to Y of ourBadPos


other parameters are mostly string and integer-based. for example function

function onHeroMove(hero, pos)

hero is a number from 0..155 indicating hero ID.

> global.lua is a special file which is ALWAYS parsed as primary file for all script. it contains few definitions to make scripting more useful, if you need some constants, there is a good list in global.lua
for example, you don't have to remember which color is which number - you can only write PLAYER_BLUE and this will equal 1 (as 1 = blue for Heroes3 and ERM)

> if script is not doing anything, make sure that it have loaded properly. scripts are not parsed in runtime, they are translated to bytecode during loading - this means that if there is a syntax error in code, it wont load at all, just drop an error in debug.txt file.

Thats all from my side. Thanks.

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


Promising
Legendary Hero
fallen artist
posted October 29, 2010 01:34 AM

Nice try, wish you luck!
____________

The future of Heroes 3 is here!

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


Adventuring Hero
New Hero
posted October 29, 2010 10:31 PM

Dang. I'm excited for this!
____________

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


Hired Hero
posted October 30, 2010 06:45 AM

Hi. Nice try indeed. GrayFace in 3.59 used wrapper for ZVS function ProcessErm to dinamically execute ERM commands, cause wrappers to ERM triggers (!?FU) are very expensive.

Something like this could be used:
http://pastebin.com/L17Gvfh0

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

Tavern Dweller
posted October 30, 2010 09:16 AM

Hi!

When I see an pascal+assembler, I'm almost sure that I'm talking with creator of ERA Platworm.

Of course, passing this with !?FU is expensive and deletes whole original ERM structure (I mean - created scripts).

If you could give me an example of using it, I would very appreciate it.

I have analyzed shortly your code, but i'm not sure what pointer should be passed into ErmStructure (perhaps nil?), Params etc.

When I have a opportunity to meet u in this topic, I would also want to ask:

It is possible to change amount of Z-variables, or to dynamically "create" a Z-Var from address. I know that ERM has some range checking but if it would be turned off, using var z1001, game would glitch/crash or it would just use a "string" from memory address z1000 + 512 (size of one string)?

I'm asking about it, because I could calculate and reserve mine range of Z vars, because some Z vars need to remain the same in whole game or they will mess up text - for example changing creature name with UN:G. The only way to set this is to bind a z-variable into it, but when variable is changed later, then ingame creature name is changed as well.

This limits an use of LUA which is approved by me because of messing scripts with other variables, but z-binding into names etc totally mess up things.

If it would be static bind, one z-var for one creature etc, then even 1000 z vars would be not enough to support 151 heroes, 170+ creatures * 3 (singluar, plural, description), + 200 arficats, +28 * 4 secondary skill texts etc.

Dynamic binding (for example - if someone changes griffin name then z1 stores this name from here on out and its stored in some list that customized griffin = z1. If someone other will change artifact name, it would be stored in first "free" z-var and this is var z2, and so on. This is what i'm planning to do, but its still limited, I mean, all of these scripts can only change ingame texts 1000 times and then engine would run off variables. This is very limited but I cannot figure how to pass this. Thats why I'm asking for help.

Thanks,
Larva

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


Hired Hero
posted October 30, 2010 01:33 PM

// Platform (not worm )
Quote:
If you could give me an example of using it, I would very appreciate it.

Still not finished to use practically. Just a piece of draw. The main problem is filling command parameters with appropriate values. I don't find ZVS code pretty clear.

There is another variant. All triggers are registered in linked list, so having many triggers slows down the code. ExecErmCmd works fine and the only thing we need is to know addresses of parsed receivers.
0x27F9548 - pointer to the first trigger structure.
526 - offset to trigger's first command structure.
Assume we have one trigger in scriptXX.erm (!?FU70000). We can find it address by looping through trigger list (GetFuncTriggerAddr(FuncN: INTEGER): INTEGER from Era sources). From that point we are able to call N-th command of the trigger directly.
668 - size of TErmCommand structure.

Sum up:
1) Get address of the first trigger: 0x27F9548*
2) Loop through the list (the first field of trigger structure is address of the next element, the next is trigger ID = 70000 in our case) and find our magic trigger (say, !?FU70000).
3) Calculate address of necessary command (TriggerAddr + 526 + (N-1) * 668).
4) Call ExecErmCmd.

Example script00.erm contents:
...
!?FU70000;
!!HEv1/v2/v3:C0/v4/d/d/d; 0-th
!!HEv1/v2/v3:C0/d/v4/d/d; 1-th
!!HEv1/v2/v3:C0/d/d/v4/d; 2-th
!!HEv1/v2/v3:C0/d/d/d/v4; 3-th
!!IF:Mz1;                 4-th
...

About z,v,w-vars. They are declared statically in current exe versions. So there is no way to enlarge the arrays. Perhaps, it would be better to write some AllocStringBlock function, which would return first free z-index. Scripts would call it at map start, allocating some vars and using them later in game. That is what you call dinamic binding.

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


Hired Hero
posted November 01, 2010 02:31 PM
Edited by Bers at 16:12, 09 Dec 2010.

Exec Erm ERA Plugin v1.0.
Download page
LicenŮe: Open Source.

Dll "ExecErm.dll" exports two functions:

FUNCTION SetErmExecTrigger (TriggerId: INTEGER): BOOLEAN;
PROCEDURE ExecErmCmdByInd (ErmCommandInd: INTEGER);

Both functions use PASCAL calling convention which is equal to STDCALL for one parameter routines. It's supposed that you write all commands in one trigger in erm file, call SetErmExecTrigger at map start and load (!?PI, !?GM1) and call ExecErmCmdByInd directly from your Delphi/C/C++ code or, as in example, from ERM using ERA service.

Example:

ZVSE
!?FU70000;
!!IF:M^You are bad^;  0-th This phrase will NOT be shown
!!IF:M^You are good^; 1-st This phrase WILL be shown

!?CM0;                RMB on adventure screen
!!CM:R0;              Disable default reaction
!!VRz1:S^ErmExec.dll^;        DLL name
!!VRz2:S^SetErmExecTrigger^;  Functions names
!!VRz3:S^ExecErmCmdByInd^;
!!SN:Lz1/?v2;                 Load dll
!!SN:Av2/z2/?v3;              Get "SetErmExecTrigger" address
!!SN:Av2/z3/?v4;              Get "ExecErmCmdByInd" address
!!SN:Ev3/0/70000;             Call SetErmExecTrigger(70000)
!!SN:Ev4/0/1;                 Call ExecErmCmdByInd(1)

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


Known Hero
posted December 05, 2010 04:29 PM
Edited by GrayFace at 16:31, 05 Dec 2010.

Larva, how is it going? This sounds very interesting and in many ways resembles what I've done for 3.59. I didn't do human-readable names for ERM receivers and triggers, so I'm particularly interested in that part and in rewritten scripts. In 3.59 ERM scripts run well, but it would still be cool to have scripts in Lua. When you do the rewriting please pay attention to any things that depend on number of towns being 9 or on specific commanders numbers etc. Also, contact me when you rewrite things like Living Scrolls. There's an internal Heroes function that can be used when the target of a scroll is chosen.

Quote:
gold = getPlayerResource(PLAYER_RED, RESOURCE_GOLD)

I'd suggest something like this:
gold = Player.GetResource("red", "gold")
or
player.red.getResource("gold")

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


Adventuring Hero
Lurking About...
posted December 05, 2010 07:57 PM

Quote:
Larva, how is it going? This sounds very interesting and in many ways resembles what I've done for 3.59. I didn't do human-readable names for ERM receivers and triggers, so I'm particularly interested in that part and in rewritten scripts. In 3.59 ERM scripts run well, but it would still be cool to have scripts in Lua. When you do the rewriting please pay attention to any things that depend on number of towns being 9 or on specific commanders numbers etc. Also, contact me when you rewrite things like Living Scrolls. There's an internal Heroes function that can be used when the target of a scroll is chosen.

Quote:
gold = getPlayerResource(PLAYER_RED, RESOURCE_GOLD)

I'd suggest something like this:
gold = Player.GetResource("red", "gold")
or
player.red.getResource("gold")


Sorry for stupid question but is WoG 3.59 out?
____________
Question Convention

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


Promising
Legendary Hero
fallen artist
posted December 06, 2010 01:38 AM

Quote:
gold = getPlayerResource(PLAYER_RED, RESOURCE_GOLD)

I'd suggest something like this:
gold = Player.GetResource("red", "gold")
or
player.red.getResource("gold")


No. Passing arguments as strings is much, much slower.
____________

The future of Heroes 3 is here!

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


Known Hero
posted December 06, 2010 06:47 AM

Quote:
Sorry for stupid question but is WoG 3.59 out?

No, still have some plans before release.

Quote:
No. Passing arguments as strings is much, much slower.

Not in Lua.

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


Promising
Legendary Hero
fallen artist
posted December 06, 2010 10:39 AM

I would like to hear an explanation
____________

The future of Heroes 3 is here!

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


Known Hero
posted December 24, 2010 03:23 PM

Quote:
I would like to hear an explanation

There's a global cache of strings, each string is unique. So, it's just a pointer and when strings are compared for equality it's just a comparison of pointers.

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


Hired Hero
posted December 26, 2010 09:08 AM

It cannot be. Cause any string assignment will invalidate the cache.

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


Known Hero
posted January 21, 2011 06:24 PM
Edited by GrayFace at 18:25, 21 Jan 2011.

How come? Assignment is a simple pointer assignment plus a call to one of garbage collector's functions. And strings are immutable.

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


Hired Hero
posted January 22, 2011 12:32 PM

When you generate string randomly/read it from external source, each assigment will have to search for such string in cash and add it in case of error? The slowest language?

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


Known Hero
posted January 23, 2011 11:48 AM

Quote:
When you generate string randomly/read it from external source, each assigment will have to search for such string in cash and add it in case of error?

Yes, each time a new string is created. Strings must not be concatenated character by character in any language. In Lua comparisons of strings are more frequent than creation, so this speeds things up.

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


Adventuring Hero
Current Russian President
posted January 30, 2011 02:37 AM

Can you give here a new link? I want to download LUA for WoG, but download link http://www.speedyshare.com/files/24922358/_LUA_ERM.rar is inactive
____________

 Send Instant Message | Send E-Mail | View Profile | PP | Quote Reply | Link
< Prev Thread . . . Next Thread >
Post New Poll †† Post New Topic †† Post New Reply

Page compiled in 0.1522 seconds