Scr to Lua decompiler?

Discuss anything that is related to OpenArcanum.
User avatar
Crypton
Arronax's Best Friend
Arronax's Best Friend
Posts: 420
Joined: Wed Jul 08, 2009 5:04 am
Location: Abyss
Contact:

Scr to Lua decompiler?

Post by Crypton » Thu Oct 07, 2010 11:58 am

Hi everybody,

how about converting Arcanum's scripts (.scr) into Lua scripts? sounds good right? It is possible, but it will be hard to write such converter/decompiler. Especially those goto line commands and other actions looks hard to decompile.

I ask myself if it won't be easier to just convert .scr scripts from binary to text format, and then manually rewrite that into Lua scripts.

What do you think? :think: I you can, give me some tips/suggestions. Thank you.

Have a nice day.

User avatar
Koorac
Ailing Wolf
Ailing Wolf
Posts: 48
Joined: Sat Jul 11, 2009 10:06 pm

Re: Scr to Lua decompiler?

Post by Koorac » Thu Oct 07, 2010 12:47 pm

Probably converting to human-radable and then doing the conversion manually would be the better solution since it will be a hell of a lot of work to create a perfect converter.

User avatar
Crypton
Arronax's Best Friend
Arronax's Best Friend
Posts: 420
Joined: Wed Jul 08, 2009 5:04 am
Location: Abyss
Contact:

Re: Scr to Lua decompiler?

Post by Crypton » Thu Oct 07, 2010 3:27 pm

Koorac wrote:Probably converting to human-radable and then doing the conversion manually would be the better solution since it will be a hell of a lot of work to create a perfect converter.
Hi Koorac! long time no see... I'm glad that you are back ;)

I made that binary to text converter, but it seems that rewriting output files to lua script will be lot of dirty work.

Here is converted script "01000praetor.scr":

Code: Select all

File: 01000praetor.scr
Local flags: 00000000
Script flags: 00000000
Counters: 00,00,00,00

{Line: 0}
if ({Global Var[1004]} <= {Number[1]}) then
    goto line {Number[5]}


{Line: 1}
loop for {Everyone in vicinity}


{Line: 2}
if ({Current looped object} is wielding item named {Number[6408]}) then
    do nothing
else (goto line {Number[4]})


{Line: 3}
if (npc {Current looped object} is a monster of specie {Anyone in group PC and NPC (SP)[15822304]}) then
    goto line {Number[97]}
else (goto line {Number[5]})

.....
more at http://pastebin.com/AYF6fC7s
What do you think?

I think that it could be simplified a lot, and converted to lua as much as possible.

User avatar
Koorac
Ailing Wolf
Ailing Wolf
Posts: 48
Joined: Sat Jul 11, 2009 10:06 pm

Re: Scr to Lua decompiler?

Post by Koorac » Sat Oct 09, 2010 1:03 pm

Well I guess this can easily be improved, but it will be difficult to have a perfect representation since I think LUA has no goto statement (I have no experience with LUA but I highly doubt it).

User avatar
Crypton
Arronax's Best Friend
Arronax's Best Friend
Posts: 420
Joined: Wed Jul 08, 2009 5:04 am
Location: Abyss
Contact:

Re: Scr to Lua decompiler?

Post by Crypton » Mon Oct 11, 2010 7:09 pm

Koorac wrote:Well I guess this can easily be improved, but it will be difficult to have a perfect representation since I think LUA has no goto statement (I have no experience with LUA but I highly doubt it).
Even if there is some kind of goto statement available, we should avoid using it, its damn stuff from hell. (I never used it in delphi or cpp, even I could...)

Anyway, I think that first of all, we should design a new scripting api for Lua, so for every .scr action/condition, there should be corresponding lua function, then we will be able to "easily" convert that .scr scripts into lua scripts, and tweak them manually if needed.

You said that you have no experience with lua, me neither, which means that we have two options: wait, till somebody else offers to do it, or start to learn lua and do that by ourselves.

I'm for second option, what about you?:P I'll start with some action translation:

Code: Select all

"do nothing" - no translation, maybe write only comment "--nothing"

"return and SKIP default" - "return" or "coroutine.yield()"
"return and RUN default" - convert "default" to function, run it and "return" from script.

"goto line (num)" - convert all lines till this goto action to function(?) and call it.

"dialog (num)" - what does this command?

"remove this script" - removes script from memory(?), function "script.remove()"
"change this script to script (num)" - "script.setId(num)"
"call script (num) at line (num2) with triggerer (obj) and attachee (obj2)" - this will be hard!?!

"set local flag (num) to true" - "script.getFlag(num).enable()"
"clear local flag (num)" - "script.getFlag(num).disable()"

"(num) = (num)" - assign operator, local a = b
"(num) = (num) + (num)" - add operator
"(num) = (num) - (num)" - sub operator
"(num) = (num) * (num)" - mul operator
"(num) = (num) / (num)" - div operator

"(obj) = (obj2)" - assign operator, shallow copy or id assign(?)

"set PC (obj) quest (num) to state (num2)" - "script.getPlayer(obj).getQuest(num).setState(num2)"

"set quest (num) to global state (num2)" - "script.getQuest(num).setState(num2)"

"loop for (obj)" - "for obj do"
"loop end" - "end"
"loop break" - "break"

"have critter (obj) become a follower of (obj2)" - "script.getPlayer(obj2).addFollower(obj)"
"have critter (obj) stop following his leader" - "script.getNpc(obj).stopFollowing()"

"float line (num) above (obj)" - "script.getObject(obj).setFloatText(text from line num)"
"print line (num) with a message class of (num2)" - "script.print(num2, text from line num)"

"add blessing (num) to (obj)" - "script.getObject(obj).addBlessing(num)"
"remove blessing (num) from (obj)" - "script.getObject(obj).removeBlessing(num)"

"add curse (num) to (obj)" - "script.getObject(obj).addCurse(num)"
"remove curse (num) from (obj)" - "script.getObject(obj).removeCurse(num)"



----------REST IS BELOW----------

"reaction of npc (obj) to pc (obj): store in (num)" - 
"reaction of npc (obj) to pc (obj): set to (num)" - 
"reaction of npc (obj) to pc (obj): adjust by (num)" - 

"armor of (obj): get in (num)" - 
"stat (num) of (obj): store in (num)" - 
"object type of (obj): store in (num)" - 
"gold of (obj): adjust by (num)" - 
"combat: (obj) attacks (obj)" - 
"random number (num) to (num): store in (num)" - 
"social class of npc (obj): store in (num)" - 
"origin of npc (obj): store in (num)" - 
"transform Attachee into basic prototype (num)" - 
"transfer item named (num) from (obj) to (obj)" - 
"story state: store in (num)" - 
"story state: set to (num)" - 
"teleport (obj) to map (num) at X:(num) Y:(num)" - 
"set day standpoint of critter (obj) to X:(num) Y:(num) on this map" - 
"set night standpoint of critter (obj) to X:(num) Y:(num) on this map" - 
"skill (num) of (obj): store in (num)" - 
"spells: have (obj) cast spell (num) on (obj)" - 
"mark map location (num) of pc (obj) as known" - 
"rumor: set rumor (num) for pc (obj)" - 
"rumor: quell rumor (num) for pc (obj)" - 
"create object with basic prototype (num) near (obj)" - 
"lock state of (obj): set to (num)" - 
"call script (num) at line (num) with triggerer (obj) and attachee (obj) in (num) seconds" - 
"call script (num) at line (num) with triggerer (obj) and attachee (obj) at second (num)" - 
"toggle (obj) state on/off" - 
"toggle (obj) invulnerability" - 
"kill (obj)" - 
"change art num of (obj) to (num)" - 
"damage (obj) for (num) points of type (num) damage" - 
"spells: cast spell (num) on (obj)" - 
"have (obj) perform animation (num)" - 
"give (obj) xps for a quest level (num)" - 
"written UI start: book (num) for reader (obj)" - 
"written UI start: image (num) for reader (obj)" - 
"create item with basic prototype (num) inside (obj)" - 
"have critter (obj) wait for his leader" - 
"destroy (obj)" - 
"have critter (obj) walk to X:(num) Y:(num)" - 
"weapon of (obj): get in (num)" - 
"distance between (obj) and (obj): get in (num)" - 
"reputation: give (obj) the reputation (num)" - 
"reputation: remove from (obj) the reputation (num)" - 
"have critter (obj) run to X:(num) Y:(num)" - 
"heal (obj) for (num) points" - 
"heal (obj) for (num) fatigue points" - 
"give (obj) the effect (num) with cause (num)" - 
"remove from (obj) the effect (num)" - 
"have (obj) use (obj) on (obj) using skill (num) with modifier (num)" - 
"magic/tech: adjust (num) by item (obj) used by (obj) on (obj): store in (num)" - 
"call script attached to (obj) at point (num) at line (num) with triggerer (obj)" - 
"play sound (num)" - 
"play sound (num) at (obj)" - 
"area of (obj): store in (num)" - 
"newspaper: queue (num) with priority (num)" - 
"newspaper: float current headline over (obj)" - 
"play sound scheme (num) and (num)" - 
"toggle (obj) open/closed" - 
"faction of npc (obj): store in (num)" - 
"scroll distance: store in (num)" - 
"magic/tech: adjust (num) by item (obj) used by (obj): store in (num)" - 
"rename (obj) as (num)" - 
"have (obj) instantly become prone" - 
"written start in (obj) set to (num)" - 
"get location of (obj) and store X in (num) and Y in (num)" - 
"day: store days since startup in (num)" - 
"hour: store current game hour in (num)" - 
"minute: store current game minute in (num)" - 
"change script attached to (obj) at point (num) to script (num)" - 
"set global flag (num) to true" - 
"clear global flag (num)" - 
"fade and teleport: pass (num) seconds, play (num) sound, play (num) movie, and teleport (obj) to map (num) at X:(num) Y:(num)" - 
"fade: pass (num) seconds, play (num) sound, and play (num) movie, with (num) seconds during fade" - 
"spell eye candy: play (num) on (obj)" - 
"hour: store hours since startup in (num)" - 
"toggle the blocked state of sector at location X:(num) and Y:(num)" - 
"hit points of (obj): store current in (num) and maximum in (num)" - 
"fatigue of critter (obj): store current in (num) and maximum in (num)" - 
"combat: force (obj) to stop attacking" - 
"toggle monster generator (num) on/off" - 
"armor coverage of item (obj): store in (num)" - 
"give (obj) spell mastery in college (num)" - 
"unfog townmap (num)" - 
"written UI start: plaque (num) for reader (obj)" - 
"have (obj) try to steal 100 coins from (obj)" - 
"spell eye candy: stop (num) on (obj)" - 
"grant one fate point to (obj)" - 
"spells: have (obj) cast free spell (num) on (obj)" - 
"set PC (obj) quest (num) to state unbotched" - 
"script eye candy: play (num) on (obj)" - 
"spells: have (obj) cast unresistable spell (num) on (obj)" - 
"spells: have (obj) cast free and unresistable spell (num) on (obj)" - 
"touch art (num)" - 
"script eye candy: stop (num) on (obj)" - 
"remove from time queue the call to script (num) with attachee (obj)" - 
"destroy item named (num) in inventory of (obj)" - 
"toggle item (obj) inventory display on/off" - 
"heal (obj) for (num) poison points" - 
"schematic UI start: display for (obj)" - 
"spells: stop spell (num) on (obj)" - 
"slideshow: queue slide (num)" - 
"end game and play slides" - 
"rotation of (obj): set to (num)" - 
"faction of npc (obj): set to (num)" - 
"drain (num) charges from (obj)" - 
"spells: cast unresistable spell (num) on (obj)" - 
"stat (num) of (obj): adjust by (num)" - 
"damage (obj) unresistably for (num) points of type (num) damage" - 
"autolevel scheme for (obj): change to (num)" - 
"set day standpoint of critter (obj) to X:(num) Y:(num) on map (num)" - 
"set night standpoint of critter (obj) to X:(num) Y:(num) on map (num)" -
Feel free to translate anything from rest section or contribute with better translation for already translated actions. :mrgreen:

User avatar
Koorac
Ailing Wolf
Ailing Wolf
Posts: 48
Joined: Sat Jul 11, 2009 10:06 pm

Re: Scr to Lua decompiler?

Post by Koorac » Mon Oct 11, 2010 9:12 pm

ZeroBot wrote: Even if there is some kind of goto statement available, we should avoid using it, its damn stuff from hell. (I never used it in delphi or cpp, even I could...)
+1
however it could be used to get something usable quickly :D



ZeroBot wrote: Anyway, I think that first of all, we should design a new scripting api for Lua, so for every .scr action/condition, there should be corresponding lua function, then we will be able to "easily" convert that .scr scripts into lua scripts, and tweak them manually if needed.

You said that you have no experience with lua, me neither, which means that we have two options: wait, till somebody else offers to do it, or start to learn lua and do that by ourselves.

I'm for second option, what about you?:P I'll start with some action translation:
Well second option sounds better :P
ZeroBot wrote:

Code: Select all

"do nothing" - no translation, maybe write only comment "--nothing"

"return and SKIP default" - "return" or "coroutine.yield()"
"return and RUN default" - convert "default" to function, run it and "return" from script.

"goto line (num)" - convert all lines till this goto action to function(?) and call it.

"dialog (num)" - what does this command?

"remove this script" - removes script from memory(?), function "script.remove()"
"change this script to script (num)" - "script.setId(num)"
"call script (num) at line (num2) with triggerer (obj) and attachee (obj2)" - this will be hard!?!

"set local flag (num) to true" - "script.getFlag(num).enable()"
"clear local flag (num)" - "script.getFlag(num).disable()"

"(num) = (num)" - assign operator, local a = b
"(num) = (num) + (num)" - add operator
"(num) = (num) - (num)" - sub operator
"(num) = (num) * (num)" - mul operator
"(num) = (num) / (num)" - div operator

"(obj) = (obj2)" - assign operator, shallow copy or id assign(?)

"set PC (obj) quest (num) to state (num2)" - "script.getPlayer(obj).getQuest(num).setState(num2)"

"set quest (num) to global state (num2)" - "script.getQuest(num).setState(num2)"

"loop for (obj)" - "for obj do"
"loop end" - "end"
"loop break" - "break"

"have critter (obj) become a follower of (obj2)" - "script.getPlayer(obj2).addFollower(obj)"
"have critter (obj) stop following his leader" - "script.getNpc(obj).stopFollowing()"

"float line (num) above (obj)" - "script.getObject(obj).setFloatText(text from line num)"
"print line (num) with a message class of (num2)" - "script.print(num2, text from line num)"

"add blessing (num) to (obj)" - "script.getObject(obj).addBlessing(num)"
"remove blessing (num) from (obj)" - "script.getObject(obj).removeBlessing(num)"

"add curse (num) to (obj)" - "script.getObject(obj).addCurse(num)"
"remove curse (num) from (obj)" - "script.getObject(obj).removeCurse(num)"



----------REST IS BELOW----------

"reaction of npc (obj) to pc (obj): store in (num)" - 
"reaction of npc (obj) to pc (obj): set to (num)" - 
"reaction of npc (obj) to pc (obj): adjust by (num)" - 

"armor of (obj): get in (num)" - 
"stat (num) of (obj): store in (num)" - 
"object type of (obj): store in (num)" - 
"gold of (obj): adjust by (num)" - 
"combat: (obj) attacks (obj)" - 
"random number (num) to (num): store in (num)" - 
"social class of npc (obj): store in (num)" - 
"origin of npc (obj): store in (num)" - 
"transform Attachee into basic prototype (num)" - 
"transfer item named (num) from (obj) to (obj)" - 
"story state: store in (num)" - 
"story state: set to (num)" - 
"teleport (obj) to map (num) at X:(num) Y:(num)" - 
"set day standpoint of critter (obj) to X:(num) Y:(num) on this map" - 
"set night standpoint of critter (obj) to X:(num) Y:(num) on this map" - 
"skill (num) of (obj): store in (num)" - 
"spells: have (obj) cast spell (num) on (obj)" - 
"mark map location (num) of pc (obj) as known" - 
"rumor: set rumor (num) for pc (obj)" - 
"rumor: quell rumor (num) for pc (obj)" - 
"create object with basic prototype (num) near (obj)" - 
"lock state of (obj): set to (num)" - 
"call script (num) at line (num) with triggerer (obj) and attachee (obj) in (num) seconds" - 
"call script (num) at line (num) with triggerer (obj) and attachee (obj) at second (num)" - 
"toggle (obj) state on/off" - 
"toggle (obj) invulnerability" - 
"kill (obj)" - 
"change art num of (obj) to (num)" - 
"damage (obj) for (num) points of type (num) damage" - 
"spells: cast spell (num) on (obj)" - 
"have (obj) perform animation (num)" - 
"give (obj) xps for a quest level (num)" - 
"written UI start: book (num) for reader (obj)" - 
"written UI start: image (num) for reader (obj)" - 
"create item with basic prototype (num) inside (obj)" - 
"have critter (obj) wait for his leader" - 
"destroy (obj)" - 
"have critter (obj) walk to X:(num) Y:(num)" - 
"weapon of (obj): get in (num)" - 
"distance between (obj) and (obj): get in (num)" - 
"reputation: give (obj) the reputation (num)" - 
"reputation: remove from (obj) the reputation (num)" - 
"have critter (obj) run to X:(num) Y:(num)" - 
"heal (obj) for (num) points" - 
"heal (obj) for (num) fatigue points" - 
"give (obj) the effect (num) with cause (num)" - 
"remove from (obj) the effect (num)" - 
"have (obj) use (obj) on (obj) using skill (num) with modifier (num)" - 
"magic/tech: adjust (num) by item (obj) used by (obj) on (obj): store in (num)" - 
"call script attached to (obj) at point (num) at line (num) with triggerer (obj)" - 
"play sound (num)" - 
"play sound (num) at (obj)" - 
"area of (obj): store in (num)" - 
"newspaper: queue (num) with priority (num)" - 
"newspaper: float current headline over (obj)" - 
"play sound scheme (num) and (num)" - 
"toggle (obj) open/closed" - 
"faction of npc (obj): store in (num)" - 
"scroll distance: store in (num)" - 
"magic/tech: adjust (num) by item (obj) used by (obj): store in (num)" - 
"rename (obj) as (num)" - 
"have (obj) instantly become prone" - 
"written start in (obj) set to (num)" - 
"get location of (obj) and store X in (num) and Y in (num)" - 
"day: store days since startup in (num)" - 
"hour: store current game hour in (num)" - 
"minute: store current game minute in (num)" - 
"change script attached to (obj) at point (num) to script (num)" - 
"set global flag (num) to true" - 
"clear global flag (num)" - 
"fade and teleport: pass (num) seconds, play (num) sound, play (num) movie, and teleport (obj) to map (num) at X:(num) Y:(num)" - 
"fade: pass (num) seconds, play (num) sound, and play (num) movie, with (num) seconds during fade" - 
"spell eye candy: play (num) on (obj)" - 
"hour: store hours since startup in (num)" - 
"toggle the blocked state of sector at location X:(num) and Y:(num)" - 
"hit points of (obj): store current in (num) and maximum in (num)" - 
"fatigue of critter (obj): store current in (num) and maximum in (num)" - 
"combat: force (obj) to stop attacking" - 
"toggle monster generator (num) on/off" - 
"armor coverage of item (obj): store in (num)" - 
"give (obj) spell mastery in college (num)" - 
"unfog townmap (num)" - 
"written UI start: plaque (num) for reader (obj)" - 
"have (obj) try to steal 100 coins from (obj)" - 
"spell eye candy: stop (num) on (obj)" - 
"grant one fate point to (obj)" - 
"spells: have (obj) cast free spell (num) on (obj)" - 
"set PC (obj) quest (num) to state unbotched" - 
"script eye candy: play (num) on (obj)" - 
"spells: have (obj) cast unresistable spell (num) on (obj)" - 
"spells: have (obj) cast free and unresistable spell (num) on (obj)" - 
"touch art (num)" - 
"script eye candy: stop (num) on (obj)" - 
"remove from time queue the call to script (num) with attachee (obj)" - 
"destroy item named (num) in inventory of (obj)" - 
"toggle item (obj) inventory display on/off" - 
"heal (obj) for (num) poison points" - 
"schematic UI start: display for (obj)" - 
"spells: stop spell (num) on (obj)" - 
"slideshow: queue slide (num)" - 
"end game and play slides" - 
"rotation of (obj): set to (num)" - 
"faction of npc (obj): set to (num)" - 
"drain (num) charges from (obj)" - 
"spells: cast unresistable spell (num) on (obj)" - 
"stat (num) of (obj): adjust by (num)" - 
"damage (obj) unresistably for (num) points of type (num) damage" - 
"autolevel scheme for (obj): change to (num)" - 
"set day standpoint of critter (obj) to X:(num) Y:(num) on map (num)" - 
"set night standpoint of critter (obj) to X:(num) Y:(num) on map (num)" -
Feel free to translate anything from rest section or contribute with better translation for already translated actions. :mrgreen:
Sounds quite good however I have no idea what your planned scripting API looks like so I can not judge it

evillive
Bunny
Bunny
Posts: 7
Joined: Mon Oct 04, 2010 12:21 am

Re: Scr to Lua decompiler?

Post by evillive » Mon Oct 11, 2010 10:47 pm

"goto line (num)" - convert all lines till this goto action to function(?) and call it.
This is wrong. After function call, execution continues from next operator, while with goto statement - it's not.
It is possible to automatically translate goto statements, but there is no anything like case/switch statement in LUA.
So my suggestion is not to try convert old scripts, but to write interpreter for original .scr files - this should be pretty easy. If someone would like to edit or replace old .scr script, then he either can edit .scr file or manually translate it to lua script and make changes in it (if there are two scripts: old style and lua, the lua one should have priority).

User avatar
Koorac
Ailing Wolf
Ailing Wolf
Posts: 48
Joined: Sat Jul 11, 2009 10:06 pm

Re: Scr to Lua decompiler?

Post by Koorac » Tue Oct 12, 2010 4:23 pm

Interesting, would have never thought of that.
Well you can use an if/else if/else chain instead of a switch so it could be a solution

evillive
Bunny
Bunny
Posts: 7
Joined: Mon Oct 04, 2010 12:21 am

Re: Scr to Lua decompiler?

Post by evillive » Tue Oct 12, 2010 5:09 pm

Koorac wrote:Interesting, would have never thought of that.
Well you can use an if/else if/else chain instead of a switch so it could be a solution
Actually, you are right, but the resulting script will be absolutely unmaintainable, so i still can't see the point to do this.

User avatar
Crypton
Arronax's Best Friend
Arronax's Best Friend
Posts: 420
Joined: Wed Jul 08, 2009 5:04 am
Location: Abyss
Contact:

Re: Scr to Lua decompiler?

Post by Crypton » Tue Oct 12, 2010 5:40 pm

evillive wrote:
"goto line (num)" - convert all lines till this goto action to function(?) and call it.
This is wrong. After function call, execution continues from next operator, while with goto statement - it's not.
It is possible to automatically translate goto statements, but there is no anything like case/switch statement in LUA.
So my suggestion is not to try convert old scripts, but to write interpreter for original .scr files - this should be pretty easy. If someone would like to edit or replace old .scr script, then he either can edit .scr file or manually translate it to lua script and make changes in it (if there are two scripts: old style and lua, the lua one should have priority).
Well, I don't know if you fully understood to what I meant, so I'll try to describe that goto decompilation more:

-Scan script for all goto statements, and collect from them a line numbers of all referenced lines.
-From that collected number, determine what lines needs to be converted to functions.
-Replace all goto statements with function calls.

Example:
if ({Global Var[1004]} <= {Number[1]}) then
goto line {Number[5]}

if (script.getGlobalVar(1004) <= 1)
function1()
return
end

Maybe I did not get your point, maybe I'll find out when I actually try to convert it. However, goto statement seems to be the most complicated to decompile, so if it wont be possible to decompile, I'll write it to output without decompilation.

I really want to avoid any goto, switch, whatever solution, I think that its possible to do that without it.

I also don't want to support scr scripts, since aim of OpenArcanum is to bind engine to lua as much as possible, so using some kind of binary scripts which are hard to code/edit will be foolish when lua is already available. Also with lua scripts, it will be much easier to extend and debug that scripts.

Anyway, I'll probably make that scr decompiler/converter tool public, so anybody will be able to contribute with their ideas and improvements.

;)

Post Reply