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
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
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
+ 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! [/list]