Custom DM Genie Scripts

Links to gaming-related tools and external resources. Feel free to promote your (RPG-related) sites here.

Moderators: dorpond, trevor, Azhrei

Post Reply
User avatar
thelevitator
Dragon
Posts: 963
Joined: Wed May 17, 2006 2:10 pm
Location: "The Biggest Little City In The World!"
Contact:

Custom DM Genie Scripts

Post by thelevitator »

As everyone here probably knows by now, we run a highly modified 3.5 campaign. Thanks to several folks over at the DM Genie boards, I've been able to modify my DM Genie to handle all of these modifications. My latest addition prompted me to share what I've compiled with everyone here. Thanks to Trevor and crew adding the halos, we've been able to starting using our relative health system of describing damage in combat. In addition to the color coding system, I also created something called "Battle Fatigue". I originally wanted to go to a Vitality/Wounds system, but found that kind of system a little tricky to incorporate into DM Genie. The Battle Fatigue system retains the standard D&D HP system, but makes combat a bit more realistic by allowing damage to HP to have a deteriorating effect on a creatures STR and DEX. It keeps the system 3.5 and abstract, while still allowing for some consequences of continuing the fight when injured to the point of being a blow or two away from death. I thought I would also share some other scripts that I'm using for more gritty and realistic combat.

First, the Battle Fatigue system. Basically, we use a color-coding system to represent damage in the game based on current HP. This allows me to describe combat without using metagame concepts like HP. It goes like this:

Green = 100% (actually speaking it's >76% of current HP)
Yellow = 75% of current HP
Orange = 50% of current HP
Red = 25% of current HP
Black = dead, disabled, unconscious or otherwise lying on the ground motionless

Using this as a guide, I created 3 new conditions in the condition editor, called Battle Fatigue Yellow, Battle Fatigue Orange and Battle Fatigue Red. The conditions llok like this:

Battle Fatigue Yellow: -1 STR, -1 DEX
Battle Fatigue Orange: -2 STR, -2 DEX
Battle Fatigue Red: -4 STR, -4 Dex

After creating the conditions, I created the following script. This script is add to the end of the CalcConditionsPre script.

Code: Select all

'Declaring your Variables to use
BatFatY = func.GetConditionNum("Battle Fatigue Yellow")
BatFatO = func.GetConditionNum("Battle Fatigue Orange")
BatFatR = func.GetConditionNum("Battle Fatigue Red")
MaxHP = cr.HPBase

If HP <= (MaxHP * .75) then
  cr.Condit(BatFatY)=True
  cr.Condit(BatFatO)=False
  cr.Condit(BatFatR)=False
End If
If HP <= (MaxHP * .5) then
  cr.Condit(BatFatY)=False
  cr.Condit(BatFatO)=True
  cr.Condit(BatFatR)=False 
End If
If HP <= (MaxHP * .25) then
  cr.Condit(BatFatY)=False
  cr.Condit(BatFatO)=False
  cr.Condit (BatFatR)=True
End If
If HP => (MaxHP * .75) then
  cr.Condit(BatFatY)=False
  cr.Condit(BatFatO)=False
  cr.Condit(BatFatR)=False
End If 
End Sub
The nice thing about this code is that it adjusts automatically as damage is dealt. It also automatically adjusts the creature's condition as it heals as well.

In addition to the Battle Fatigue system, we are using other variants. 3 of them are integrated into the Attack Button Script. I thought it would be easier to simply explain what they are and then just provide the entire Attack Button script for ease of implementation.

I've added Auto-ammo, Defensive Opposed Roll, and armor and shield damage. The auto-ammo script automatically deducts ranges weapon ammunition like throwing knives, arrows, bolts, etc. from inventory. The Defensive Opposed Roll is based on the variant in the DMG. Rather than "take 10" on the AC, the player defending the attack rolls d20 and adds it to all AC bonuses. This mixes things up a bit better and makes the "super powerful guy always hitting super wimpy guy" less than a foregone conclusion. Finally, we use an Armor as DR system, which utilizes a different script. To make the Armor as Dr even a little better, I've added the Armor and Shield damage so that armor and shields can eventually be damaged and even destroyed during combat. You will need a few extra things for this to work, more importantly having the DR condtions DR1-DR8 created and having all of your armor and shields' hardness and HP information filled out. I have them all finished (including magical and small armor) and zipped for your convenience. You will also need to create the ArmorDR conditions that apply too. I have also zipped those as well.

Here is the entire Attack Button script:

Code: Select all

Public function AttackButton(cAtt, AttackNumber, CombatLogStr)

'This function is called when a user clicks one of the attack buttons 
' - after the default attack rolls are done, but before any target auto-attacking is applied, and before any output is done to the combat log.
' - if a critical threat is rolled, this function is still called only once.

' - Parameters -
'Cr (implicit): The current creature
'cAtt: The current attack.
'AttackNumber: Which button was pressed
'CombatLogStr: default output to the combat log.

'Return: Must return the CombatLogStr (modified or not)

'Init Variables used later
shot = false
ammoType = ""
attackType = ""
canelAttack = false

'Get the last damage object
dim LastDamage
set LastDamage = func.GetLastDamage

' Begin: Auto Ammo Script
if (LastDamage.Kind = 1 or LastDamage.Kind = 2) then
'Read attack string of current weapon
'This is a static variable for the moment
AttackName = cAtt.Name

'Determine ammunition name from Attack Name.
'If it's a thrown attack then the attack name matches the ammunition name.
if LastDamage.Kind = 2 then
ammo = AttackName
'otherwise we need to derive the ammunition from the attack name
elseif inStr(1, AttackName, "Longbow", 1) > 0 then
ammo = "Arrows"
elseif inStr(1, AttackName, "Shortbow", 1) > 0 then
ammo = "Arrows"
elseif inStr(1, AttackName, "Crossbow", 1) > 0 then
ammo = "Bolts"
elseif inStr(1, AttackName, "Sling", 1) then
ammo = "Bullets"
end if

'Determine correct Ammo Type for this attack from the Attack Name
foo = inStrRev(AttackName, "&") 'is an ampersand in the name?
if foo > 0 then
bar = Len(AttackName) - foo - 1
attackType = Right(AttackName, bar)
attackMagic = True
elseif ammo = AttackName then
foo = inStrRev(AttackName, "+")
if foo > 0 then
bar = Len(AttackName) - foo + 1
attackType = Right(AttackName, bar)
attackMagic = True
end if
else
attackMagic = False
end if

'Search User's Equipment for the Ammo type used with this attack
For x = 0 to cr.NumItems
item = cr.ItemName(x)
'Check to see if it's the correct ammo type
if inStr(1, item, ammo, VBTEXTCOMPARE) then
foo = inStrRev(item, "+")
if foo > 0 then
bar = Len(item) - foo + 1
if LastDamage.Kind = 2 then
ammoType = Right(Item, bar)
else 
ammoType = ammo & " " & Right(item, bar)
end if
itemMagic = true
else
ammoType = ""
itemMagic = false
end if
if (itemMagic = false And attackMagic = false) then
'If non-magical attack then only use non-magical ammunition
'If it ends in (20) or (50) and weighs more than 2lbs it's a newly added standard item.
'Set the quantity and convert it to a multiple-quantity item so we can decriment it with attack.
itemQty = 0
if inStr(1, item, "(20)") then itemQty = 20
if inStr(1, item, "(50)") then itemQty = 50
if (cr.ItemWt(x) > 2 and itemQty <> 0) then
call cr.SetItemName( x, ammo & " " & ammoType)
cr.ItemWt(x) = cr.ItemWt(x) / itemQty
cr.ItemCount(x) = itemQty
cr.ItemGP(x) = cr.ItemGP(x) / itemQty
end if

if (cr.itemCount(x) > 0 and cr.ItemEquipped(x) = true) then
cr.ItemCount(x) = cr.ItemCount(x) -1
shot = true
exit For
end if
elseif (itemMagic = true And attackMagic = true) then
'If Magic item and attack, find out if they match
if StrComp(ammoType, attackType, VBTEXTCOMPARE) = 0 then
'If it ends in (20) or (50) and weighs more than 2lbs it's a newly added standard item.
'Set the quantity and convert it to a multiple-quantity item so we can decriment it with attack.
itemQty = 0
if inStr(1, item, "(20)") then itemQty = 20
if inStr(1, item, "(50)") then itemQty = 50
if (cr.ItemWt(x) > 2 and itemQty <> 0) then
call cr.SetItemName( x, ammo & " " & ammoType)
cr.ItemWt(x) = cr.ItemWt(x) / itemQty
cr.ItemCount(x) = itemQty
cr.ItemGP(x) = cr.ItemGP(x) / itemQty
end if
if (cr.itemCount(x) > 0 and cr.ItemEquipped(x) = true) then
cr.ItemCount(x) = cr.ItemCount(x) -1
shot = true
exit For
end if
end if
end if
end if
Next
If shot = false then
res = msgbox("There is no available ammunition for that attack, do it anyway?", 4)
if res = 7 then
'undo the last attack's damage
LastDamage.Damage1 = 0
LastDamage.CritDamage1 = 0
LastDamage.Damage2 = 0
LastDamage.CritDamage2 = 0
CombatLogStr = " "
' Set a flag so we know not to try and perform auto trip and the defense roll
canelAttack = true
end if
end if
'End of global Skip
end if
' End: Auto Ammo Script

' Begin: Opposed to hit roll Script
' Get the Creature being attacked
' Note: You must use the attack buttons and set the current
' target for this script to work.
if canelAttack = false And Len(Cr.LastAttackedCreature) > 0 Then
dim attackedCr
set attackedCr = func.GetCreatureName(Cr.LastAttackedCreature)

' Make the defense roll 1d20 + (AC - 10)
dim defenseRoll
defenseRoll = func.RollDice("1d20")+attackedCr.AC-10

' Update the Combat Log with the defense Roll 
CombatLogStr = CombatLogStr + "Defense Roll: " + CStr(defenseRoll) + "\par" 

' Do nothing for the auto hit and auto miss cases
' If auto hit is true then the attacker rolled a natural 20.
' If auto miss is true then the attacker rolled a natrual 1.
if LastDamage.AutoMiss = false And LastDamage.AutoHit = false Then
' If the creatures defense roll is greater than the attack roll
' then the attack misses, unless the Auto Hit property is true.
if defenseRoll > LastDamage.AC then
' Update the log string stating that the attack missed because of the defense roll
' Comment out the following line if you do not want the information in the log.
CombatLogStr = CombatLogStr + " Attack Missed!\par"

' Update the Last Damage object to reflect the miss by setting the
' AutoMiss property to true
LastDamage.AutoMiss = true
else
' The attack hits. 
' Update the log string stating that the attack hit because of the defense roll
' Comment out the following line if you do not want the information in the log.
CombatLogStr = CombatLogStr + " Attack Hit!\par"

' Update the attacks hit AC to be equal to the creatures AC
' if it is currently less than that AC
if LastDamage.AC <= attackedCR.AC then 
LastDamage.AC = attackedCR.AC
end if
end if
end if
end if 
' End: Opposed to hit roll Script
' Begin Armor/Shield Damage
if canelAttack = false And LastDamage.AutoMiss = false And (LastDamage.AutoHit = true Or LastDamage.AC >= attackedCR.AC) then
'dim attackedCr
'set attackedCr = func.GetCreatureName(Cr.LastAttackedCreature)

' See if the attacked creature has a shield
if attackedCR.HasShield() = true then
' Search for the shield
For x = 0 to attackedCR.NumItems
if attackedCR.GetItemStat(x, "ArmorData.IsShield") > 0 then
' Calculate the armor damage
shieldDamage = _
(LastDamage.Damage1 + LastDamage.CritDamage1 + _
LastDamage.Damage2 + LastDamage.CritDamage2 - _
attackedCR.GetItemStat(x, "Hardness"))

' Apply the damage to the shield
if shieldDamage > 0 then
hp = attackedCR.GetItemStat(x, "HitPoints")
hp = hp - shieldDamage
attackedCR.SetItemStat x, "HitPoints", hp

' If the armor is destroyed unequip
if hp < 1 then
CombatLogStr = CombatLogStr + " Shield Destroyed!\par"
attackedCR.SetItemStat x, "Equipped", 0
elseif shieldDamage > 0 then
CombatLogStr = CombatLogStr + " Shield Damaged! (" + CStr(hp) + ")\par"
end if
end if
exit for
end if
Next
elseif attackedCR.HasArmor() = true then
' Search for the armor
For x = 0 to attackedCR.NumItems
if attackedCR.GetItemStat(x, "ArmorData.IsArmor") > 0 then
' Calculate the armor damage
armorDamage = _
(LastDamage.Damage1 + LastDamage.CritDamage1 + _
LastDamage.Damage2 + LastDamage.CritDamage2 - _
attackedCR.GetItemStat(x, "Hardness"))

' Apply the damage to the armor
if armorDamage > 0 then
hp = attackedCR.GetItemStat(x, "HitPoints")
hp = hp - armorDamage
attackedCR.SetItemStat x, "HitPoints", hp

' If the armor is destroyed unequip
if hp < 1 then
CombatLogStr = CombatLogStr + " Armor Destroyed!\par"
attackedCR.SetItemStat x, "Equipped", 0
elseif armorDamage > 0 then
CombatLogStr = CombatLogStr + " Armor Damaged! (" + CStr(hp) + ")\par"
end if
end if
exit for
end if
Next
end if
end if
' End Armor/Shield Damage


'Finally, you must return the combat log string
AttackButton = CombatLogStr 

End function
You can get the armor and weapons with completed hardness, DR, and HP here:

http://www.spelz.biz/Armor_and_Weapons.rar

The ArmorDR conditions are here:

http://www.spelz.biz/ArmorDR_Conditions.rar

To make the Armor as DR work properly, you will also need to add the following code to your Autodamage script. I set up the Armor as DR like the Iron Heroes variant. In this system, armor gives no AC bonus, instead giving a variable DR bonus up to its original AC bonus. For example, leather armor normally provides +2 to AC, but in this system it provides +1d2 DR. Full plate normally provides +8 to AC, but in this system it provides +1d8 DR.

This is the script that you need to place at the end of the normal Autodamage script.

Code: Select all

'Here is the code that links you armor, armor conditions, and attack/damage/damage reduction together. Following is the code that does it. After that is a replica of where the code is situated in my system. It goes in (under the General Scripting Editor) Global Functions -> AutoDamage.

'NOTE: The armor files should overwrite your current ones. This will make things easier. As an added bonus, they have full hardness and hp stats so you can take damage off them when the character is struck. Pretty nifty.

'If the victim has armor, applies appropriate damage reduction.
if cr.GetCondition("ArmorDR2") then
    roll = func.RollDice("1d2")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR3") then
    roll = func.RollDice("1d3")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR4") then
    roll = func.RollDice("1d4")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR5") then
    roll = func.RollDice("1d5")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR6") then
    roll = func.RollDice("1d6")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR7") then
    roll = func.RollDice("1d7")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
elseif cr.GetCondition("ArmorDR8") then
    roll = func.RollDice("1d8")
    LastDamage.Damage1 = LastDamage.Damage1 - roll
    LastDamage.CritDamage1 = LastDamage.CritDamage1 - roll
    AutoDamage = ". \b1" & cr.Name & "\b0's armor reduced the damage taken by " & roll
end if
'End of my ArmorDR code
End Function 
OK, so this thread basically gives you the ability to add the following to your DM Genie and your 3.5 game:

+ an automated Battle Fatigue system.
+ Opposed Defense Roll variant
+ Armor as Dr system, including automated physical damage to armor and shields
+ Auto-ammo system that automatically removes ranged ammunition from inventory. I do quite a few other additions to my DM Genie and would be happy to share any files I have with everyone here! :D [/list]
"Neither hexes nor squares can confine me!"

James Anthony
"It's all in your head....."
http://www.spelz.net

User avatar
giliath
RPTools Founder
Posts: 275
Joined: Tue Jan 31, 2006 11:10 am
Location: Austin, TX

Post by giliath »

I am not at all familiar with DMGenie's scripting. Is it possible to use the scripting to call out to another program? Possible hitting a URL or some other possibility.

We have been talking for a long time about exposing a remote access to MapTool so that it could be manipulated by external programs like InitTool or DMGenie.

Wouldn't it be cool if the script was able to change the halos for you?
~Giliath

User avatar
thelevitator
Dragon
Posts: 963
Joined: Wed May 17, 2006 2:10 pm
Location: "The Biggest Little City In The World!"
Contact:

Post by thelevitator »

That would be a dream! However, fellas like Dorpond and Ahzrei have MUCH more expertise in that area than me. I know it has been discussed on the DM Genie boards. I'll snoop around and see if I can dig up anything over there.
"Neither hexes nor squares can confine me!"

James Anthony
"It's all in your head....."
http://www.spelz.net

User avatar
snikle
Great Wyrm
Posts: 1143
Joined: Tue Oct 24, 2006 11:45 pm
Location: Clarksville, TN
Contact:

Post by snikle »

Holy moly! That is one long arse script!
• snikle •
snikle.wordpress.com

User avatar
trevor
Codeum Arcanum (RPTools Founder)
Posts: 11311
Joined: Mon Jan 09, 2006 4:16 pm
Location: Austin, Tx
Contact:

Post by trevor »

If it's just interpreted VB, I wonder if it would allow raw socket connections.

Anyone know about VB sockets ? (I'm sure I could look it up, but, VB makes be yack)
Dreaming of a 1.3 release

User avatar
Azhrei
Site Admin
Posts: 12086
Joined: Mon Jun 12, 2006 1:20 pm
Location: Tampa, FL

Post by Azhrei »

First, I need to apologize to thelevitator, since he probably abandoned the Vitality/Wounds system because I never worked on his DM Genie script to tweak it and get it right. :(

Second, let me say something about his scripts: I'm impressed!! Good job, TL! It seems like you've come a long way in your scripting ability and you've got every right to be proud about your creations!

Third, AFAIK, there is not a network-based VB control that is accessible to the DM Genie VBscript engine. I've mentioned this on the DM Genie forums a few times, thinking that the author might prepare such an object and export it to VBscript. (I'm no expert on VB -- and VB6 at that! -- but I think a LoadLibrary() call and some additional parameters to the scripting engine would suffice.)

I also started looking at some way to get from VBscript to WSH (Windows SHell) because WSH provides its own hooks for loading ActiveX and COM objects, but I didn't get any where with that idea. It could be that I just overlooked something while reading documentation...

I also proposed replacing the RichEdit32.DLL used by the CombatLog with a "front-end" DLL. This front-end would receive everything that should be printed in the CombatLog, but in addition to displaying it, it would also multicast the information to other systems (multicast instead of broadcast so that it would flow through routers). Players would "register" with the GM's "server" and that would dictate which text was displayed on which computers.

Just pie-in-the-sky right now...

User avatar
thelevitator
Dragon
Posts: 963
Joined: Wed May 17, 2006 2:10 pm
Location: "The Biggest Little City In The World!"
Contact:

Post by thelevitator »

No worries Azhrei!! :D In fact, we game tested the VWS to the extent that we could and truthfully, we found too many clunky aspects of it, undead being one of the clunkiest. We have a lot of undead in our campaigns so that was a factor. The other factor was that nobody in our group really found anything wrong with the standard HP system, except for the part where a 100HP fighter fights just as well at 10 HP as he does at full strength. By simply adding the Battle Fatigue idea, it allows some consequence of taking sustained damage without completely unbalancing the HP system. My biggest reason for desiring the VWS was to give me as a DM more information to help in making combat more descriptive. But look at what I have now. The Defense Opposed Roll tells me iif it's a great swing or a poor swing, a great parry, shield block or if the guy moved right into the blade. The Armor as DR allows me more description because if the armor absorbs a great part of the damage, it's a shot to the chest. If it only absorbs a point or two, I can describe it as a shot to the arm or leg or weak spot in the armor. And the Battle Fatigue gives a great way to show the attrition of continued injuries during combat.


All in all, I'm very proud of our modified combat system. It stays pretty true to much of the feel of 3.5 but has enough added touches to increase the grittiness and danger of combat without unbalancing it.

Maybe I'll take advantage of Azhrei's guilt and ask for a little favor? :twisted: We are using the defense bonus to AC (1/2 BAB) and right now I'm adding it to the misc. field manually. Is there any way to automate that? I'm not even sure where to start in how to implement that to be an automated function in DM Genie.

For the record, Azhrei has been instrumental in my ever increased understanding of DM Genie. Not only have his personal answers to my questions been of great help, but his many posts on DM Genie have been invaluable to my learning curve. I'm grateful for the help Azhrei's been able to give me! :D
"Neither hexes nor squares can confine me!"

James Anthony
"It's all in your head....."
http://www.spelz.net

User avatar
trevor
Codeum Arcanum (RPTools Founder)
Posts: 11311
Joined: Mon Jan 09, 2006 4:16 pm
Location: Austin, Tx
Contact:

Post by trevor »

Azhrei wrote: Third, AFAIK, there is not a network-based VB control that is accessible to the DM Genie VBscript engine. I've mentioned this on the DM Genie forums a few times
Bummer. Well, we can always fall back on the poll-the-file approach
Dreaming of a 1.3 release

Post Reply

Return to “Links & External Resources”