Ironworks Gaming Forum

Ironworks Gaming Forum (http://www.ironworksforum.com/forum/index.php)
-   Baldurs Gate II: Shadows of Amn & Throne of Bhaal (http://www.ironworksforum.com/forum/forumdisplay.php?f=12)
-   -   Q about smarter Liches&Mages-tactics mod (http://www.ironworksforum.com/forum/showthread.php?t=12988)

Xen 06-04-2003 11:09 AM

Ok.Weimer has good mods but I have this Q about smarter liches&mages.If they are so smarter why are they using ADHW(s)?Would a real player cast such a powerful spell on creatures that are summoned by Wand Of monster Summoning?


EDIT:level up!Weheee [img]smile.gif[/img]

[ 06-04-2003, 11:10 AM: Message edited by: Xen ]

Dundee Slaytern 06-04-2003 11:15 AM

It's called AI Script limitations. True... a check for target's XPVALUE can be done... but as Alson and I found out not too long ago... a really smart AI Script for a Mage will be more than 1MB in size.

This includes memory, limited selective targeting and selective casting among other minor details.

Note the limited selective targeting. If we made it as best as possible... the filesize would be a whopping 9MB in size. Running a few of these babies will slow your machine to a crawl unless you have a hyperfast processor.

Xen 06-04-2003 11:20 AM

I think i have it...=> 1.2 GhZ [img]smile.gif[/img]

[ 06-04-2003, 11:20 AM: Message edited by: Xen ]

White Lancer 06-04-2003 11:31 AM

Quote:

Originally posted by Dundee Slaytern:
a really smart AI Script for a Mage will be more than 1MB in size.

This includes memory, limited selective targeting and selective casting among other minor details.

Note the limited selective targeting. If we made it as best as possible... the filesize would be a whopping 9MB in size. Running a few of these babies will slow your machine to a crawl unless you have a hyperfast processor.

9MB is pretty big, IIRC, each characters is 1 byte in size, so that would be approximately 9,437,184 characters(9 MB = 9*1024 KB = 9*1024*1024 B)... that's a lot of typing. Even the 1MB version would still be huge, coming in at roughly 1,048,576. Have fun typing all that out.

Still, that would be a VERY comprehensive script, i dont suppose you kept it did you? I wouldn't mind having a look.

Dundee Slaytern 06-04-2003 11:53 AM

Let's just say that... after making a basic template for a spell, I copied, pasted and modified over and over again, paragraphs after paragraphs. The 9MB is an estimate, because halfway through the project, I realised that to cater to 10 targets would be madness after calculating the current filesize and mulitplying it. We reduced it to 4 targets, making it much more manageable. I only completed up to level 3 spells/potions/wands/melee combat... and the script was already 30,000 lines over.

Still... it was a pretty good script, if a tad big.

I do however... have some complete AI Scripts for BG1 characters. Not Mage or Cleric though. I still get brain-freeze thinking of all those lines of text.

Alivad 06-04-2003 12:06 PM

You can, generally, play around with targetting blocks a bit to get the size of things down slightly. On the other hand, decent targetting generally has to be pretty big (I've got a 30KB block around somewhere to target Domination, for example).
I've looked at Weimer's AI scripts, and while I think they do leave a bit to be desired in terms of intelligence in some respects, they're pretty decent for "generic" enemy scripts, and aren't going to cause horrific performance problems.

Dundee Slaytern 06-04-2003 12:15 PM

Introducing... Melf's Acid Arrow.

This one caters to six targets, and takes the scroll into account too. Note that some spells, like Magic Missile has twice the coding due to its' ability to get rid of Mirror Image( selective casting so to speak).

WARNING - Excessive Text,

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">// Melfs Acid Arrow
IF
ActionListEmpty()
See([ENEMY])
CheckStat(NearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(NearestEnemyOf(Myself),0,MINORGLOBE)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(NearestEnemyOf(Myself),75,RESISTACID)
!CheckStatGT(NearestEnemyOf(Myself),40,RESISTMAGIC )
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,NearestEnemyOf(Myself))
!StateCheck(NearestEnemyOf(Myself),STATE_CHARMED)
!StateCheck(NearestEnemyOf(Myself),STATE_HELPLESS)
!StateCheck(NearestEnemyOf(Myself),STATE_INVISIBLE )
!StateCheck(NearestEnemyOf(Myself),STATE_IMPROVEDI NVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(NearestEnemyOf(Myself),2211)
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(SecondNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(SecondNearestEnemyOf(Myself),0,MINORGLOB E)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(SecondNearestEnemyOf(Myself),75,RESIS TACID)
!CheckStatGT(SecondNearestEnemyOf(Myself),40,RESIS TMAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,SecondNearestEnemyOf(Myself))
!StateCheck(SecondNearestEnemyOf(Myself),STATE_CHA RMED)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_HEL PLESS)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_INV ISIBLE)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_IMP ROVEDINVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(SecondNearestEnemyOf(Myself),2211)
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(ThirdNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(ThirdNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(ThirdNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(ThirdNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,ThirdNearestEnemyOf(Myself))
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(ThirdNearestEnemyOf(Myself),2211)
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(FourthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(FourthNearestEnemyOf(Myself),0,MINORGLOB E)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(FourthNearestEnemyOf(Myself),75,RESIS TACID)
!CheckStatGT(FourthNearestEnemyOf(Myself),40,RESIS TMAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,FourthNearestEnemyOf(Myself))
!StateCheck(FourthNearestEnemyOf(Myself),STATE_CHA RMED)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_HEL PLESS)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_INV ISIBLE)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_IMP ROVEDINVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(FourthNearestEnemyOf(Myself),2211)
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(FifthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(FifthNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(FifthNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(FifthNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,FifthNearestEnemyOf(Myself))
!StateCheck(FifthNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(FifthNearestEnemyOf(Myself),2211)
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(SixthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(SixthNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(SixthNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(SixthNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,SixthNearestEnemyOf(Myself))
!StateCheck(SixthNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HaveSpell(2211)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
Spell(SixthNearestEnemyOf(Myself),2211)
END
// Melfs Acid Arrow Scroll
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(NearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(NearestEnemyOf(Myself),0,MINORGLOBE)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(NearestEnemyOf(Myself),75,RESISTACID)
!CheckStatGT(NearestEnemyOf(Myself),40,RESISTMAGIC )
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,NearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,NearestEnemyOf(Myself))
!StateCheck(NearestEnemyOf(Myself),STATE_CHARMED)
!StateCheck(NearestEnemyOf(Myself),STATE_HELPLESS)
!StateCheck(NearestEnemyOf(Myself),STATE_INVISIBLE )
!StateCheck(NearestEnemyOf(Myself),STATE_IMPROVEDI NVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,NearestEnemyOf(Myself))
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(SecondNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(SecondNearestEnemyOf(Myself),0,MINORGLOB E)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(SecondNearestEnemyOf(Myself),75,RESIS TACID)
!CheckStatGT(SecondNearestEnemyOf(Myself),40,RESIS TMAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,SecondNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,SecondNearestEnemyOf(Myself))
!StateCheck(SecondNearestEnemyOf(Myself),STATE_CHA RMED)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_HEL PLESS)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_INV ISIBLE)
!StateCheck(SecondNearestEnemyOf(Myself),STATE_IMP ROVEDINVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,SecondNearestEnemyOf(My self))
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(ThirdNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(ThirdNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(ThirdNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(ThirdNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,ThirdNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,ThirdNearestEnemyOf(Myself))
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(ThirdNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,ThirdNearestEnemyOf(Mys elf))
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(FourthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(FourthNearestEnemyOf(Myself),0,MINORGLOB E)
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(FourthNearestEnemyOf(Myself),75,RESIS TACID)
!CheckStatGT(FourthNearestEnemyOf(Myself),40,RESIS TMAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,FourthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,FourthNearestEnemyOf(Myself))
!StateCheck(FourthNearestEnemyOf(Myself),STATE_CHA RMED)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_HEL PLESS)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_INV ISIBLE)
!StateCheck(FourthNearestEnemyOf(Myself),STATE_IMP ROVEDINVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,FourthNearestEnemyOf(My self))
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(FifthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(FifthNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(FifthNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(FifthNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,FifthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,FifthNearestEnemyOf(Myself))
!StateCheck(FifthNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(FifthNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,FifthNearestEnemyOf(Mys elf))
END
IF
ActionListEmpty()
See([ENEMY])
CheckStat(Myself,0,165) // Not in a state of Improved Alacrity
CheckStat(SixthNearestEnemyOf(Myself),0,162) // Target has no Spell Turning
CheckStat(SixthNearestEnemyOf(Myself),0,MINORGLOBE )
!CheckStatGT(Myself,40,SPELLFAILUREMAGE)
!CheckStatGT(SixthNearestEnemyOf(Myself),75,RESIST ACID)
!CheckStatGT(SixthNearestEnemyOf(Myself),40,RESIST MAGIC)
!GlobalTimerNotExpired(&quot;RoundTimer&quot;,&quo t;LOCALS&quot;)
!HasItem(&quot;DEMILICH&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;LICH&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;MAGEAMUL&quot; ,SixthNearestEnemyOf(Myself))
!HasItem(&quot;RAKRING&quot; ,SixthNearestEnemyOf(Myself))
!StateCheck(SixthNearestEnemyOf(Myself),STATE_CHAR MED)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_HELP LESS)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_INVI SIBLE)
!StateCheck(SixthNearestEnemyOf(Myself),STATE_IMPR OVEDINVISIBILITY)
HasItemEquiped(&quot;SCRL95&quot;,Myself)
THEN
RESPONSE #100

SetGlobalTimer(&quot;RoundTimer&quot;,&quot;LOCALS &quot;,6)
UseItem(&quot;SCRL95&quot;,SixthNearestEnemyOf(Mys elf))
END</pre>[/QUOTE]

[ 06-04-2003, 12:20 PM: Message edited by: Dundee Slaytern ]

Raistlin Majere 06-04-2003 01:28 PM

[img]graemlins/wow.gif[/img] wow, starting to feel a bit dizzy [img]graemlins/1dizzy.gif[/img]

andrewas 06-04-2003 01:52 PM

Bloody hell, but thats one inefficient scripting language. One thing that springs to mind should this project ever get going again, if you can nest if statements you can do something like

</font><blockquote>code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">if (nearest enemy is a valid target)
then
if (have spell) cast spell else
if (have scroll) cast spell
end</pre>[/QUOTE]which cuts the melfs acid arrow script in half, give or take.

Shame there isnt a function to take the nth nearest enemy, that would really cut down on the lines needed.

SixOfSpades 06-04-2003 05:51 PM

The biggest flaw of the Infinity Engine is that it has no capacity for functions like (determine if creature X is a valid target for spell Y). It doesn't even have the most basic things that most programmers take for granted, such as arrays, subroutines, 'until' statements--hell, the damn language doesn't even have 'FOR' loops. Take another look at Dundee's code: It's all IF, THEN, END. Not even a single ELSE in the whole damn thing.

And I thought C++ was ugly.


All times are GMT -4. The time now is 11:39 AM.

Powered by vBulletin® Version 3.8.3
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
©2024 Ironworks Gaming & ©2024 The Great Escape Studios TM - All Rights Reserved