Twilight Path RPG's Battle System!
Documentation:
Code:
Screenshot:
Enjoy.
Documentation:
JASS:
//************************************************************************************************
// Battle System by Vestras. *
// *
// This system is my best system ever. It's my darling. In my eyes, it's a masterpiece. *
// *
// How to use: *
// When you use it, you ALWAYS need to call InitBattle() and then call AttackBoard(...). If you *
// do not call InitBattle() or call AttackBoard(...), nothing will happen. *
// *
// Ingame using: *
// Use the arrow keys to go up and down between the options in the multiboard. Press the right *
// arrow key to select the current option. Press F1 to make spells available. *
// *
// Pros: *
// Exciting battling in single player RPGs instead of the boring, old Warcraft battle system. *
// Easy use. *
// Fleeing. *
// A correct Final Fantasy-feeling. *
// *
// Cons: *
// If you press the arrow keys too fast, the system will start to bug much. (Blizzard'a fault) *
// *
// Leaks: *
// None as far as I know, but if you spot some, please report. *
// *
// Credit Vestras when using. *
// Thanks for using. *
// *
// Visit <a href="http://www.mapcrafting.com" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.mapcrafting.com</a>, it's a great Warcraft III mapping site. *
//************************************************************************************************
Code:
JASS:
//************************************************************************************************
// Battle System by Vestras. *
// *
// This system is my best system ever. It's my darling. In my eyes, it's a masterpiece. *
// *
// How to use: *
// When you use it, you ALWAYS need to call InitBattle() and then call AttackBoard(...). If you *
// do not call InitBattle() or call AttackBoard(...), nothing will happen. *
// *
// Ingame using: *
// Use the arrow keys to go up and down between the options in the multiboard. Press the right *
// arrow key to select the current option. Press F1 to make spells available. *
// *
// Pros: *
// Exciting battling in single player RPGs instead of the boring, old Warcraft battle system. *
// Easy use. *
// Fleeing. *
// A correct Final Fantasy-feeling. *
// *
// Cons: *
// If you press the arrow keys too fast, the system will start to bug much. (Blizzard'a fault) *
// *
// Leaks: *
// None as far as I know, but if you spot some, please report. *
// *
// Credit Vestras when using. *
// Thanks for using. *
// *
// Visit <a href="http://www.mapcrafting.com" target="_blank" class="link link--external" rel="nofollow ugc noopener">http://www.mapcrafting.com</a>, it's a great Warcraft III mapping site. *
//************************************************************************************************
library BS
globals
private real ATBgaugemin = 100 // The minimum before you can attack again.
private constant integer LockID = 039;h001039; // The raw code of the "Lock" dummy unit.
private constant integer SpellUser = 039;H000039; // The raw code of the "Use A Spell" unit.
private constant real CHeight = 200 // Camera height.
private constant real CAngle = 345 // Camera angle.
private constant real CDistance = 800 // Camera distance to target.
private constant real Period = 0.15 // The period between camera shifts.
private constant boolean allowai = true // Allow the AI? If your map is a single player RPG, I suggest that.
private constant real maximumlife = 25. // The maximum life the cpu can have before the chance of fleeing is there.
private constant real fleechance = 25. // The fleeing chance.
private constant string defendpath = "ReplaceableTextures\\CommandButtons\\BTNDefend.blp" // Path of the defend icon. (For Flee)
private constant string attackpath = "ReplaceableTextures\\CommandButtons\\BTNAttack.blp" // Path of the attack icon. (For Attack)
private constant string teleportfx = "Abilities\\Spells\\Items\\TomeOfRetraining\\TomeOfRetrainingCaster.mdl" // Path of the model for teleporting.
endglobals
// Don't touch below
globals
private timer CamTimer
private timer SlctTimer
private timer ReTimer
private timer AITimer
private multiboard M
private integer N
private integer T
private integer D
private integer C
private group attackers
private unit atked
private unit atker
private unit Lock
private unit turnunit
private unit dummy
private real Rotate
private real Distance
private real Angle
private real R = 0
private real array ATBgauges[1000] = 0
private trigger PressUp
private trigger PressDown
private trigger PressRight
private trigger AttackB
private trigger AddG
private trigger WhenDies
private trigger Select
private trigger Spell
private real firstx
private real firsty
private location cfirst
private boolean CPUIsDone = false
private boolean EndBattleb = false
private boolean b = false
endglobals
private function CleanUp takes nothing returns nothing
call SetUnitInvulnerable(GetEnumUnit(), false)
call PauseUnit(GetEnumUnit(), false)
endfunction
private function EndBattle takes nothing returns nothing
debug call BJDebugMsg("Cleaning Up")
call RemoveUnit(dummy)
call RemoveUnit(Lock)
call ForGroup(attackers, function CleanUp)
call ResetToGameCamera(Period)
call DestroyTimer(CamTimer)
call DestroyTimer(SlctTimer)
call DestroyTimer(ReTimer)
call DestroyTimer(AITimer)
call ResetToGameCamera(Period)
call SetUnitInvulnerable(atked, false)
call SetUnitInvulnerable(atker, false)
call PauseUnit(atked, false)
call PauseUnit(atker, false)
call DestroyTrigger(PressUp)
call DestroyTrigger(PressDown)
call DestroyTrigger(PressRight)
call DestroyTrigger(AttackB)
call DestroyTrigger(AddG)
call DestroyTrigger(WhenDies)
call DestroyTrigger(Select)
call DestroyTrigger(Spell)
call DestroyGroup(attackers)
call MultiboardDisplay(M, false)
call DestroyMultiboard(M)
call RemoveLocation(cfirst)
set cfirst = null
set attackers = null
set CamTimer = null
set SlctTimer = null
set ReTimer = null
set AITimer = null
set PressUp = null
set PressDown = null
set PressRight = null
set AttackB = null
set AddG = null
set WhenDies = null
set Select = null
set Spell = null
set atked = null
set atker = null
set dummy = null
set M = null
set Lock = null
endfunction
private function Camera takes nothing returns nothing
local location tl = GetUnitLoc(atked)
local location atkl = GetUnitLoc(atker)
local real dx = GetLocationX(atkl) - GetLocationX(tl)
local real dy = GetLocationY(atkl) - GetLocationY(tl)
local real dist = SquareRoot(dx * dx + dy * dy) / 2
local location l = PolarProjectionBJ(tl, dist, GetUnitFacing(atked)) // Yes, I know it's slow, but I don't think I can use Z cordinates with the "real method".
set Lock = CreateUnit(GetOwningPlayer(atked), LockID, GetLocationX(l), GetLocationY(l), 0)
call PanCameraToTimed(GetLocationX(l), GetLocationY(l), Period)
call SetCameraTargetController(Lock, 0., 0., false)
call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(atked) - 90, Period)
call SetCameraField(CAMERA_FIELD_ZOFFSET, GetCameraField(CAMERA_FIELD_ZOFFSET) + GetLocationZ(l) + CHeight - GetCameraEyePositionZ(), Period)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, Angle, Period)
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, Distance, Period)
call SetUnitFacingToFaceUnitTimed(atker, atked, Period)
call RemoveLocation(l)
call RemoveLocation(atkl)
call RemoveLocation(tl)
set R = R + 0.15
if R >= 1. then
call DestroyTimer(GetExpiredTimer())
endif
set tl = null
set atkl = null
set l = null
endfunction
private function PressesUp takes nothing returns boolean
debug call BJDebugMsg("You have pressed the up arrow key")
if N == 1 then
call MultiboardSetItemValueBJ(M, 1, 1, "Attack")
call MultiboardSetItemValueBJ(M, 1, 2, ">> Flee")
set N = 2
elseif N == 2 then
call MultiboardSetItemValueBJ(M, 1, 1, ">> Attack")
call MultiboardSetItemValueBJ(M, 1, 2, "Flee")
set N = 1
endif
return false // Safety
endfunction
private function PressesDown takes nothing returns boolean
debug call BJDebugMsg("You have pressed the down arrow key")
if N == 2 then
call MultiboardSetItemValueBJ(M, 1, 1, ">> Attack")
call MultiboardSetItemValueBJ(M, 1, 2, "Flee")
set N = 1
elseif N == 1 then
call MultiboardSetItemValueBJ(M, 1, 1, "Attack")
call MultiboardSetItemValueBJ(M, 1, 2, ">> Flee")
set N = 2
endif
return false // Safety
endfunction
private function Enable takes nothing returns nothing
if ATBgauges[1] >= ATBgaugemin then
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, true)
endif
call EnableTrigger(PressUp)
call EnableTrigger(PressDown)
call EnableTrigger(PressRight)
call EnableTrigger(AttackB)
set atker = FirstOfGroup(attackers)
call SetPlayerAlliance(GetOwningPlayer(atked), GetOwningPlayer(atker), ALLIANCE_SHARED_VISION, false)
call SetPlayerAlliance(GetOwningPlayer(atker), GetOwningPlayer(atked), ALLIANCE_SHARED_VISION, false)
call DestroyTimer(GetExpiredTimer())
set ATBgauges[1] = 0
endif
endfunction
private function Disable takes nothing returns nothing
if ATBgauges[1] <= ATBgaugemin then
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
call DisableTrigger(PressUp)
call DisableTrigger(PressDown)
call DisableTrigger(PressRight)
call DisableTrigger(AttackB)
call DestroyTimer(GetExpiredTimer())
endif
endfunction
private function facing takes nothing returns nothing
local location locA = GetUnitLoc(atked)
local location locB = GetUnitLoc(atker)
local real angle = AngleBetweenPoints(locA, locB)
call SelectUnit(atked, true)
debug call BJDebugMsg("Facing")
if T == 1 then
call SetUnitFacing(atked, angle)
call PauseUnit(atked, true)
call DestroyTimer(GetExpiredTimer())
endif
call TimerStart(CreateTimer(), 0.01, true, function Enable)
call RemoveLocation(locA)
call RemoveLocation(locB)
set locA = null
set locB = null
call DisableTrigger(PressRight)
endfunction
private function AIfacing takes nothing returns nothing
local location locA = GetUnitLoc(atker)
local location locB = GetUnitLoc(atked)
local real angle = AngleBetweenPoints(locA, locB)
debug call BJDebugMsg("Facing")
if T == 1 then
call SetUnitFacing(atker, angle)
call PauseUnit(atker, true)
call DestroyTimer(GetExpiredTimer())
endif
call RemoveLocation(locA)
call RemoveLocation(locB)
set locA = null
set locB = null
set CPUIsDone = true
call PauseUnit(dummy, false)
endfunction
private function AITimer1 takes nothing returns nothing
call SetUnitInvulnerable(atker, true)
call SetUnitInvulnerable(atked, true)
call DestroyEffect(AddSpecialEffect(teleportfx, GetUnitX(atker), GetUnitY(atker)))
call SetUnitPositionLoc(atker, cfirst)
call DestroyEffect(AddSpecialEffect(teleportfx, GetUnitX(atker), GetUnitY(atker)))
call TimerStart(CreateTimer(), 3.5, false, function AIfacing)
call DestroyTimer(GetExpiredTimer())
endfunction
private function AI takes nothing returns nothing
local real i = GetRandomReal(0, 100)
debug call BJDebugMsg("AI")
if GetUnitState(atker, UNIT_STATE_LIFE) <= maximumlife then
if i <= fleechance then
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
debug call BJDebugMsg("Fleeing..")
call DisplayTextToPlayer(Player(0), 0., 0.5, "Your opponent has fled!")
set EndBattleb = true
call TimerStart(CreateTimer(), 0.01, false, function Enable)
call RemoveUnit(atker)
endif
else
debug call BJDebugMsg("Attacking..")
call PauseUnit(atker, false)
call SetUnitInvulnerable(atked, false)
call IssueTargetOrder(atker, "attack", atked)
call TimerStart(CreateTimer(), 2.1, false, function AITimer1)
set ATBgauges[2] = 0
call DestroyTimer(GetExpiredTimer())
endif
endfunction
private function AISetATBHigher takes nothing returns nothing
set ATBgauges[2] = ATBgauges[2] + GetUnitState(atker, UNIT_STATE_LIFE) / 100
if ATBgauges[2] >= ATBgaugemin then
call TimerStart(CreateTimer(), .01, true, function AI)
endif
endfunction
private function RemoveBuffGroup takes nothing returns nothing
call UnitRemoveBuffBJ(039;BPSE039;, GetEnumUnit())
endfunction
private function SetATBHigher takes nothing returns nothing
set ATBgauges[1] = ATBgauges[1] + GetUnitState(atked, UNIT_STATE_LIFE) / 100
if ATBgauges[1] >= ATBgaugemin then
call DestroyTimer(GetExpiredTimer())
endif
call ClearTextMessages()
call DisplayTextToPlayer(Player(0), 0., 0., "|cff7777aaATB Gauge:|r " + R2S(ATBgauges[1]) + " percent filled.")
endfunction
private function WhenAttacked takes nothing returns boolean
if UnitHasBuffBJ(atker, 039;BPSE039;) then
set CPUIsDone = true
call Enable()
call ForGroup(attackers, function RemoveBuffGroup)
return false
endif
if T == 1 then
call DestroyEffect(AddSpecialEffect(teleportfx, GetUnitX(atked), GetUnitY(atked)))
call SetUnitPosition(atked, firstx, firsty)
call DestroyEffect(AddSpecialEffect(teleportfx, GetUnitX(atked), GetUnitY(atked)))
call SetUnitInvulnerable(atker, true)
call SetUnitInvulnerable(atked, true)
call TimerStart(CreateTimer(), 1.5, false, function facing)
call TimerStart(AITimer, 0.15, true, function AISetATBHigher)
call DestroyTimer(GetExpiredTimer())
endif
call TimerStart(CreateTimer(), 0.15, true, function SetATBHigher)
call TimerStart(CreateTimer(), 0.01, false, function Disable)
return false // Safety
endfunction
private function Selection takes nothing returns nothing
if b == false then
set Select = GetTriggeringTrigger()
set b = true
endif
call ClearSelection()
if EndBattleb == true then
call DestroyTimer(GetExpiredTimer())
call EndBattle()
endif
if CPUIsDone == true then
call DestroyTimer(GetExpiredTimer())
endif
endfunction
private function UnInvul takes nothing returns nothing
call SetUnitInvulnerable(GetEnumUnit(), false)
endfunction
private function Invul takes nothing returns nothing
call SetUnitInvulnerable(GetEnumUnit(), true)
endfunction
private function OnSpellRest takes nothing returns nothing
call ForGroup(attackers, function Invul)
call PauseUnit(dummy, true)
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
call TimerStart(CreateTimer(), .0, true, function Selection)
call TimerStart(CreateTimer(), 1.9, false, function WhenAttacked)
call DestroyTimer(GetExpiredTimer())
endfunction
private function OnSpell takes nothing returns boolean
call ForGroup(attackers, function UnInvul)
call TimerStart(CreateTimer(), 0.50, false, function OnSpellRest)
return false
endfunction
private function PressesRight takes nothing returns boolean
local real fx
local real fy
call PauseUnit(dummy, false)
call SetUnitState(dummy, UNIT_STATE_MANA, GetUnitState(atked, UNIT_STATE_MANA))
call DisableTrigger(AttackB)
debug call BJDebugMsg(I2S(N))
if N == 2 then
debug call BJDebugMsg("You have pressed the right arrow key")
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
call PauseUnit(dummy, true)
set EndBattleb = true
call EndBattle()
endif
if N == 1 then
if T == 1 then
set turnunit = atked
elseif T == 2 then
set turnunit = atker
endif
set fx = GetUnitX(turnunit)
set fy = GetUnitY(turnunit)
set firstx = fx
set firsty = fy
debug call BJDebugMsg("You have pressed the right arrow key")
if T == 1 then
call PauseUnit(atked, false)
call SetUnitInvulnerable(atker, false)
call IssueTargetOrder(turnunit, "attack", atker)
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
call PauseUnit(dummy, true)
debug call BJDebugMsg("Is it here?")
call TimerStart(CreateTimer(), .0, true, function Selection)
call TimerStart(CreateTimer(), 1.9, false, function WhenAttacked)
endif
debug call BJDebugMsg("Is it here?")
endif
return false // Safety
endfunction
private function Filtr takes nothing returns boolean
return IsUnitAlly(GetFilterUnit(), GetOwningPlayer(atked)) != true
endfunction
private function SetUnitXY takes unit whichUnit, real X, real Y returns nothing
call SetUnitX(whichUnit, X)
call SetUnitY(whichUnit, Y)
endfunction
private function MoveSpellUserTo takes nothing returns nothing
local real x = GetUnitX(atked)
local real y = GetUnitY(atked)
call SetUnitXY(dummy, x, y)
endfunction
private function RemoveGroup takes nothing returns boolean
local unit u = GetDyingUnit()
local unit s = FirstOfGroup(attackers)
call GroupRemoveUnit(attackers, u)
set u = null
return false
endfunction
private function Register takes nothing returns nothing
local unit u = FirstOfGroup(attackers)
call TriggerRegisterUnitEvent(WhenDies, u, EVENT_UNIT_DEATH)
call TriggerAddCondition(WhenDies, Condition(function RemoveGroup))
set u = null
endfunction
private function SetTimer takes nothing returns nothing
local unit s = FirstOfGroup(attackers)
if GetWidgetLife(s) < .405 then
call GroupRemoveUnit(attackers, s)
set s = FirstOfGroup(attackers)
set atker = s
set cfirst = GetUnitLoc(atker)
call TimerStart(CreateTimer(), Period, true, function Camera)
endif
if s == null then
if GetLocalPlayer() == Player(0) then
call MultiboardDisplay(M, false)
endif
set EndBattleb = true
call EndBattle()
set s = null
call DestroyTimer(GetExpiredTimer())
return
endif
set s = null
endfunction
private function AddGroup takes nothing returns boolean
call GroupAddUnit(attackers, GetTriggerUnit())
debug call BJDebugMsg(I2S(CountUnitsInGroup(attackers)))
call ForGroup(attackers, function Register)
call PauseUnit(GetTriggerUnit(), true)
call SetUnitInvulnerable(GetTriggerUnit(), true)
call TimerStart(CreateTimer(), 0.01, true, function SetTimer)
return false
endfunction
function AttackBoard takes unit attacked, unit attacker returns nothing
local unit d
set CamTimer = CreateTimer()
set SlctTimer = CreateTimer()
set ReTimer = CreateTimer()
set AITimer = CreateTimer()
set attackers = CreateGroup()
set AttackB = GetTriggeringTrigger()
set AddG = CreateTrigger()
set Spell = CreateTrigger()
set cfirst = GetUnitLoc(attacker)
set Rotate = 0
set Angle = CAngle
set Distance = CDistance
set atked = attacked
set atker = attacker
call TimerStart(CamTimer, Period, true, function Camera)
call TimerStart(ReTimer, 1., true, function Register)
set d = CreateUnit(GetOwningPlayer(attacked), SpellUser, GetUnitX(attacked), GetUnitY(attacked), GetUnitFacing(attacked))
set dummy = CreateUnit(GetOwningPlayer(attacked), SpellUser, GetUnitX(attacked), GetUnitY(attacked), GetUnitFacing(attacked))
call RemoveUnit(d)
call TimerStart(CreateTimer(), 0.01, true, function MoveSpellUserTo)
call SetUnitState(dummy, UNIT_STATE_MANA, GetUnitState(atked, UNIT_STATE_MANA))
call SetUnitInvulnerable(attacked, true)
call SetUnitInvulnerable(attacker, true)
call PauseUnit(attacked, true)
call PauseUnit(attacker, true)
call GroupAddUnit(attackers, attacker)
call SetUnitFacingToFaceUnitTimed(attacked, attacker, 0.10)
call SetUnitFacingToFaceUnitTimed(attacker, attacked, 0.10)
call TriggerRegisterUnitInRange(AddG, attacked, 325., Filter(function Filtr))
call TriggerRegisterUnitEvent(Spell, dummy, EVENT_UNIT_SPELL_EFFECT)
call TriggerAddCondition(AddG, Condition(function AddGroup))
call TriggerAddCondition(Spell, Condition(function OnSpell))
set d = null
endfunction
function InitBattle takes nothing returns nothing
local multiboarditem mbitem = null
set M = CreateMultiboard()
set PressUp = CreateTrigger()
set PressDown = CreateTrigger()
set PressRight = CreateTrigger()
set T = 1
set N = 1
set EndBattleb = false
call MultiboardSetTitleText(M, "Choose Your Action")
call MultiboardSetItemsWidth(M, 5.)
call MultiboardSetRowCount(M, 2)
call MultiboardSetColumnCount(M, 1)
call MultiboardSetItemValueBJ(M, 1, 1, ">> Attack")
call MultiboardSetItemValueBJ(M, 1, 2, "Flee")
call MultiboardSetItemIconBJ(M, 1, 1, attackpath)
call MultiboardSetItemIconBJ(M, 1, 2, defendpath)
set N = 1
set D = 2
set C = 1
set attackers = CreateGroup()
set mbitem = null
call MultiboardDisplay(M, true)
call MultiboardMinimize(M, false)
call TriggerRegisterPlayerKeyEventBJ(PressUp, Player(0), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_UP)
call TriggerRegisterPlayerKeyEventBJ(PressDown, Player(0), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_DOWN)
call TriggerRegisterPlayerKeyEventBJ(PressRight, Player(0), bj_KEYEVENTTYPE_DEPRESS, bj_KEYEVENTKEY_RIGHT)
call TriggerAddCondition(PressUp, Condition(function PressesUp))
call TriggerAddCondition(PressDown, Condition(function PressesDown))
call TriggerAddCondition(PressRight, Condition(function PressesRight))
endfunction
endlibrary
Screenshot:
Enjoy.