Name | Type | is_array | initial_value |
//TESH.scrollpos=46
//TESH.alwaysfold=0
library TimerUtils initializer init
//*********************************************************************
//* TimerUtils (red+blue+orange flavors for 1.24b+) 2.0 + FIX
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3c.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* set t=NewTimerEx(x) : Get a timer (alternative to CreateTimer), call
//* Initialize timer data as x, instead of 0.
//*
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Multi-flavor:
//* Set USE_HASH_TABLE to true if you don't want to complicate your life.
//*
//* If you like speed and giberish try learning about the other flavors.
//*
//********************************************************************
//================================================================
globals
//How to tweak timer utils:
// USE_HASH_TABLE = true (new blue)
// * SAFEST
// * SLOWEST (though hash tables are kind of fast)
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = true (orange)
// * kinda safe (except there is a limit in the number of timers)
// * ALMOST FAST
//
// USE_HASH_TABLE = false, USE_FLEXIBLE_OFFSET = false (red)
// * THE FASTEST (though is only faster than the previous method
// after using the optimizer on the map)
// * THE LEAST SAFE ( you may have to tweak OFSSET manually for it to
// work)
//
private constant boolean USE_HASH_TABLE = true
private constant boolean USE_FLEXIBLE_OFFSET = false
private constant integer OFFSET = 0x100000
private integer VOFFSET = OFFSET
//Timers to preload at map init:
private constant integer QUANTITY = 512
//Changing this to something big will allow you to keep recycling
// timers even when there are already AN INCREDIBLE AMOUNT of timers in
// the stack. But it will make things far slower so that's probably a bad idea...
private constant integer ARRAY_SIZE = 8190
endglobals
//==================================================================================================
globals
private integer array data[ARRAY_SIZE]
private hashtable ht
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
static if(USE_HASH_TABLE) then
// new blue
call SaveInteger(ht,0,GetHandleId(t), value)
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-VOFFSET]=value
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
set data[GetHandleId(t)-OFFSET]=value
endif
endfunction
function GetTimerData takes timer t returns integer
static if(USE_HASH_TABLE) then
// new blue
return LoadInteger(ht,0,GetHandleId(t) )
elseif (USE_FLEXIBLE_OFFSET) then
// orange
static if (DEBUG_MODE) then
if(GetHandleId(t)-VOFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-VOFFSET]
else
// new red
static if (DEBUG_MODE) then
if(GetHandleId(t)-OFFSET<0) then
call BJDebugMsg("SetTimerData: Wrong handle id, only use SetTimerData on timers created by NewTimer")
endif
endif
return data[GetHandleId(t)-OFFSET]
endif
endfunction
//==========================================================================================
globals
private timer array tT[ARRAY_SIZE]
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
private boolean didinit = false
endglobals
private keyword init
//==========================================================================================
// I needed to decide between duplicating code ignoring the "Once and only once" rule
// and using the ugly textmacros. I guess textmacros won.
//
//! textmacro TIMERUTIS_PRIVATE_NewTimerCommon takes VALUE
// On second thought, no.
//! endtextmacro
function NewTimerEx takes integer value returns timer
if (tN==0) then
if (not didinit) then
//This extra if shouldn't represent a major performance drawback
//because QUANTITY rule is not supposed to be broken every day.
call init.evaluate()
set tN = tN - 1
else
//If this happens then the QUANTITY rule has already been broken, try to fix the
// issue, else fail.
debug call BJDebugMsg("NewTimer: Warning, Exceeding TimerUtils_QUANTITY, make sure all timers are getting recycled correctly")
set tT[0]=CreateTimer()
static if( not USE_HASH_TABLE) then
debug call BJDebugMsg("In case of errors, please increase it accordingly, or set TimerUtils_USE_HASH_TABLE to true")
static if( USE_FLEXIBLE_OFFSET) then
if (GetHandleId(tT[0])-VOFFSET<0) or (GetHandleId(tT[0])-VOFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
else
if (GetHandleId(tT[0])-OFFSET<0) or (GetHandleId(tT[0])-OFFSET>=ARRAY_SIZE) then
//all right, couldn't fix it
call BJDebugMsg("NewTimer: Unable to allocate a timer, you should probably set TimerUtils_USE_HASH_TABLE to true or fix timer leaks.")
return null
endif
endif
endif
endif
else
set tN=tN-1
endif
call SetTimerData(tT[tN],value)
// debug call BJDebugMsg( "|cff76CAFF"+I2S(tN)+"|r") // MoCo
return tT[tN]
endfunction
function NewTimer takes nothing returns timer
return NewTimerEx(0)
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==ARRAY_SIZE) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
// debug call BJDebugMsg( "|cff76CAFF"+I2S(tN)+"|r") // MoCo
endfunction
// MoCo
private function ShowTimerActions takes nothing returns nothing
debug call BJDebugMsg( "|cff76CAFFTimer N:|r "+I2S(tN)) // MoCo
endfunction
private function init takes nothing returns nothing
local integer i=0
local integer o=-1
local boolean oops = false
local trigger trg = CreateTrigger( )
// MoCo
call TriggerRegisterPlayerChatEvent( trg, Player(0), "res", true )
call TriggerAddAction( trg, function ShowTimerActions )
set trg = null
if ( didinit ) then
return
else
set didinit = true
endif
static if( USE_HASH_TABLE ) then
set ht = InitHashtable()
loop
exitwhen(i==QUANTITY)
set tT[i]=CreateTimer()
call SetTimerData(tT[i], HELD)
set i=i+1
endloop
set tN = QUANTITY
else
loop
set i=0
loop
exitwhen (i==QUANTITY)
set tT[i] = CreateTimer()
if(i==0) then
set VOFFSET = GetHandleId(tT[i])
static if(USE_FLEXIBLE_OFFSET) then
set o=VOFFSET
else
set o=OFFSET
endif
endif
if (GetHandleId(tT[i])-o>=ARRAY_SIZE) then
exitwhen true
endif
if (GetHandleId(tT[i])-o>=0) then
set i=i+1
endif
endloop
set tN = i
exitwhen(tN == QUANTITY)
set oops = true
exitwhen not USE_FLEXIBLE_OFFSET
debug call BJDebugMsg("TimerUtils_init: Failed a initialization attempt, will try again")
endloop
if(oops) then
static if ( USE_FLEXIBLE_OFFSET) then
debug call BJDebugMsg("The problem has been fixed.")
//If this message doesn't appear then there is so much
//handle id fragmentation that it was impossible to preload
//so many timers and the thread crashed! Therefore this
//debug message is useful.
elseif(DEBUG_MODE) then
call BJDebugMsg("There were problems and the new timer limit is "+I2S(i))
call BJDebugMsg("This is a rare ocurrence, if the timer limit is too low:")
call BJDebugMsg("a) Change USE_FLEXIBLE_OFFSET to true (reduces performance a little)")
call BJDebugMsg("b) or try changing OFFSET to "+I2S(VOFFSET) )
endif
endif
endif
endfunction
endlibrary
//TESH.scrollpos=99
//TESH.alwaysfold=0
library GroupUtils initializer Init requires optional xebasic
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a combination of several features relevant to groups. First
//* and foremost, it contains a group stack that you can access dynamic groups
//* from. It also provides means to refresh groups and clear any shadow
//* references within them. The included boolexprs are there for backwards
//* compatibility with maps that happen to use them. Since the 1.24c patch,
//* null boolexprs used in GroupEnumUnits* calls no longer leak, so there is no
//* performance gain to using the BOOLEXPR_TRUE constant.
//*
//* Instead of creating/destroying groups, we have moved on to recycling them.
//* NewGroup pulls a group from the stack and ReleaseGroup adds it back. Always
//* remember to call ReleaseGroup on a group when you are done using it. If you
//* fail to do so enough times, the stack will overflow and no longer work.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hashtable. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it. It is only worth doing this on
//* groups that you plan to have around for awhile.
//*
//* Constants that can be used from the library:
//* [group] ENUM_GROUP As you might expect, this group is good for
//* when you need a group just for enumeration.
//* [boolexpr] BOOLEXPR_TRUE This is a true boolexpr, which is important
//* because a 'null' boolexpr in enumeration
//* calls results in a leak. Use this instead.
//* [boolexpr] BOOLEXPR_FALSE This exists mostly for completeness.
//*
//* This library also includes a simple implementation of a group enumeration
//* call that factors collision of units in a given area of effect. This is
//* particularly useful because GroupEnumUnitsInRange doesn't factor collision.
//*
//* In your map, you can just replace all instances of GroupEnumUnitsInRange
//* with GroupEnumUnitsInArea with identical arguments and your spells will
//* consider all units colliding with the area of effect. After calling this
//* function as you would normally call GroupEnumUnitsInRange, you are free to
//* do anything with the group that you would normally do.
//*
//* If you don't use xebasic in your map, you may edit the MAX_COLLISION_SIZE
//* variable below and the library will use that as the added radius to check.
//* If you use xebasic, however, the script will automatically use xe's
//* collision size variable.
//*
//* You are also able to use GroupUnitsInArea. This function returns all units
//* within the area, no matter what they are, which can be convenient for those
//* instances where you actually want that.
//*
//* Example usage:
//* local group MyGroup = NewGroup()
//* call GroupRefresh(MyGroup)
//* call ReleaseGroup(MyGroup)
//* call GroupEnumUnitsInArea(ENUM_GROUP, x, y, 350., BOOLEXPR_TRUE)
//* call GroupUnitsInArea(ENUM_GROUP, x, y, 350.)
//*
globals
//If you don't have xebasic in your map, this value will be used instead.
//This value corresponds to the max collision size of a unit in your map.
private constant real MAX_COLLISION_SIZE = 197.
//If you are insane and don't care about any of the protection involved in
//this library, but want this script to be really fast, set this to true.
private constant boolean LESS_SAFETY = false
endglobals
globals
//* Constants that are available to the user
group ENUM_GROUP = CreateGroup()
boolexpr BOOLEXPR_TRUE = null
boolexpr BOOLEXPR_FALSE = null
endglobals
globals
//* Hashtable for debug purposes
private hashtable ht = InitHashtable()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Arrays and counter for the group stack
private group array Groups
private integer Count = 0
//* Variables for use with the GroupUnitsInArea function
private real X = 0.
private real Y = 0.
private real R = 0.
private hashtable H = InitHashtable()
endglobals
private function HookDestroyGroup takes group g returns nothing
if g == ENUM_GROUP then
call BJDebugMsg(SCOPE_PREFIX+"Warning: ENUM_GROUP destroyed")
endif
endfunction
debug hook DestroyGroup HookDestroyGroup
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
static if not LESS_SAFETY then
call SaveInteger(ht, 0, GetHandleId(Groups[Count]), 1)
endif
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer id = GetHandleId(g)
static if LESS_SAFETY then
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
else
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Null groups cannot be released")
return false
elseif not HaveSavedInteger(ht, 0, id) then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Group not part of stack")
return false
elseif LoadInteger(ht, 0, id) == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Groups cannot be multiply released")
return false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: Max groups achieved, destroying group")
call DestroyGroup(g)
return false
endif
call SaveInteger(ht, 0, id, 2)
endif
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
return true
endfunction
private function Filter takes nothing returns boolean
return IsUnitInRangeXY(GetFilterUnit(), X, Y, R)
endfunction
private function HookDestroyBoolExpr takes boolexpr b returns nothing
local integer bid = GetHandleId(b)
if HaveSavedHandle(H, 0, bid) then
//Clear the saved boolexpr
call DestroyBoolExpr(LoadBooleanExprHandle(H, 0, bid))
call RemoveSavedHandle(H, 0, bid)
endif
endfunction
hook DestroyBoolExpr HookDestroyBoolExpr
private constant function GetRadius takes real radius returns real
static if LIBRARY_xebasic then
return radius+XE_MAX_COLLISION_SIZE
else
return radius+MAX_COLLISION_SIZE
endif
endfunction
function GroupEnumUnitsInArea takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
local integer bid = 0
//Set variables to new values
set X = x
set Y = y
set R = radius
if filter == null then
//Adjusts for null boolexprs passed to the function
set filter = Condition(function Filter)
else
//Check for a saved boolexpr
set bid = GetHandleId(filter)
if HaveSavedHandle(H, 0, bid) then
//Set the filter to use to the saved one
set filter = LoadBooleanExprHandle(H, 0, bid)
else
//Create a new And() boolexpr for this filter
set filter = And(Condition(function Filter), filter)
call SaveBooleanExprHandle(H, 0, bid, filter)
endif
endif
//Enumerate, if they want to use the boolexpr, this lets them
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), filter)
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
function GroupUnitsInArea takes group whichGroup, real x, real y, real radius returns nothing
local real prevX = X
local real prevY = Y
local real prevR = R
//Set variables to new values
set X = x
set Y = y
set R = radius
//Enumerate
call GroupEnumUnitsInRange(whichGroup, x, y, GetRadius(radius), Condition(function Filter))
//Give back original settings so nested enumerations work
set X = prevX
set Y = prevY
set R = prevR
endfunction
private function True takes nothing returns boolean
return true
endfunction
private function False takes nothing returns boolean
return false
endfunction
private function Init takes nothing returns nothing
set BOOLEXPR_TRUE = Condition(function True)
set BOOLEXPR_FALSE = Condition(function False)
endfunction
endlibrary
//TESH.scrollpos=15
//TESH.alwaysfold=0
// **************************************************************************
// ** **
// ** Mathematical Functions **
// ** ————————————— **
// ** **
// ** Functions used instead of BJs to calculate some values **
// ** **
// ** By: Majin **
// **
// ** **
// **************************************************************************
library Math
function GetDistance takes real ax, real ay, real bx, real by returns real
return SquareRoot((bx-ax)*(bx-ax)+(by-ay)*(by-ay))
endfunction
function PolarProjectionx takes real ax, real dist, real angle returns real
return ax + dist * Cos(angle)
endfunction
function PolarProjectiony takes real ay, real dist, real angle returns real
return ay + dist * Sin(angle)
endfunction
function GetAngle takes real ax, real ay, real bx, real by returns real
return Atan2(by-ay, bx-ax)
endfunction
function IAbs takes integer a returns integer
if (a >= 0) then
return a
else
return -a
endif
endfunction
function RAbs takes real a returns real
if (a >= 0) then
return a
else
return -a
endif
endfunction
function IMin takes integer a, integer b returns integer
if (a < b) then
return a
else
return b
endif
endfunction
function AntiLeak takes nothing returns boolean
return true
endfunction
endlibrary
//TESH.scrollpos=7
//TESH.alwaysfold=0
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 3.1.0.1
One map, one hashtable. Welcome to NewTable 3.1
This library was originally called NewTable so it didn't conflict with
the API of Table by Vexorian. However, the damage is done and it's too
late to change the library name now. To help with damage control, I
have provided an extension library called TableBC, which bridges all
the functionality of Vexorian's Table except for 2-D string arrays &
the ".flush(integer)" method. I use ".flush()" to flush a child hash-
table, because I wanted the API in NewTable to reflect the API of real
hashtables (I thought this would be more intuitive).
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private integer less = 0 //Index generation for TableArrays (below 0).
private integer more = 8190 //Index generation for Tables.
//Configure it if you use more than 8190 "key" variables in your map (this will never happen though).
private hashtable ht = InitHashtable()
private key sizeK
private key listK
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return sizeK
endmethod
static method operator list takes nothing returns Table
return listK
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//Run these textmacros to include the entire hashtable API as wrappers.
//Don't be intimidated by the number of macros - Vexorian's map optimizer is
//supposed to kill functions which inline (all of these functions inline).
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive syntax (tb.handle; tb.unit; etc.)
implement realm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
//set this = tb[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key)
endmethod
//set tb[389034] = 8192
method operator []= takes integer key, Table tb returns nothing
call SaveInteger(ht, this, key, tb)
endmethod
//set b = tb.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key)
endmethod
//call tb.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key)
endmethod
//Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
//local Table tb = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set this = more + 1
set more = this
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this) //Clear hashed memory
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call tb.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
//! runtextmacro optional TABLE_BC_METHODS()
endstruct
//! runtextmacro optional TABLE_BC_STRUCTS()
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table tb = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = tb[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set this = less - array_size
set less = this
else
set tb[0] = tb[this] //Set the last destroyed to the last-last destroyed
call tb.remove(this) //Clear hashed memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//This magic method enables two-dimensional[array][syntax] for Tables,
//similar to the two-dimensional utility provided by hashtables them-
//selves.
//
//ta[integer a].unit[integer b] = unit u
//ta[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; I assume you call .flush()
//if you want it flushed too. This is a public method so that you don't
//have to loop through all TableArray indices to flush them if you don't
//need to (ie. if you were flushing all child-keys as you used them).
//
method destroy takes nothing returns nothing
local Table tb = dex.size[this.size]
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if tb == 0 then
//Create a Table to index recycled instances with their array size
set tb = Table.create()
set dex.size[this.size] = tb
endif
call dex.size.remove(this) //Clear the array size from hash memory
set tb[this] = tb[0]
set tb[0] = this
endmethod
private static Table tempTable
private static integer tempEnd
//Avoids hitting the op limit
private static method clean takes nothing returns nothing
local Table tb = .tempTable
local integer end = tb + 0x1000
if end < .tempEnd then
set .tempTable = end
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
else
set end = .tempEnd
endif
loop
call tb.flush()
set tb = tb + 1
exitwhen tb == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
debug if this.size == 0 then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
set .tempTable = this
set .tempEnd = this + this.size
call ForForce(bj_FORCE_PLAYER[0], function thistype.clean)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=21
//TESH.alwaysfold=0
library ErrorMessage /* v1.0.1.4
*************************************************************************************
*
* Issue Compliant Error Messages
*
************************************************************************************
*
* debug function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
* - In the event of an error the game will be permanently paused
*
* debug function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
*
************************************************************************************/
static if DEBUG_MODE then
private struct Fields extends array
static constant string COLOR_RED = "|cffff0000"
static constant string COLOR_YELLOW = "|cffffff00"
static string lastError = null
endstruct
private function Pause takes nothing returns nothing
call PauseGame(true)
endfunction
private function ThrowMessage takes string libraryName, string functionName, string objectName, integer objectInstance, string description, string errorType, string color returns nothing
local string str
local string color_braces = "|cff66FF99"
local string orange = "|cffff6600"
set str = "->\n-> " + color_braces + "{|r " + "Library" + color_braces + "(" + orange + libraryName + color_braces + ")"
if (objectName != null) then
if (objectInstance > 0) then
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + " (|rinstance = " + orange + I2S(objectInstance) + color_braces + ") )" + "|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
else
set str = str + "|r.Object" + color_braces + "(" + orange + objectName + color_braces + ")|r." + "Method" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
else
set str = str + "|r." + "Function" + color_braces + "(" + orange + functionName + color_braces + ")"
endif
set str = str + color_braces + " }|r " + "has thrown an exception of type " + color_braces + "(" + color + errorType + color_braces + ")|r."
set Fields.lastError = str + "\n->\n" + "-> " + color + description + "|r\n->"
endfunction
function ThrowError takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Error", Fields.COLOR_RED)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
call TimerStart(CreateTimer(), 0, true, function Pause)
set objectInstance = 1/0
endif
endfunction
function ThrowWarning takes boolean expression, string libraryName, string functionName, string objectName, integer objectInstance, string description returns nothing
if (Fields.lastError != null) then
set objectInstance = 1/0
endif
if (expression) then
call ThrowMessage(libraryName, functionName, objectName, objectInstance, description, "Warning", Fields.COLOR_YELLOW)
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60000,Fields.lastError)
set Fields.lastError = null
endif
endfunction
endif
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Alloc /* v1.1.2.0
*************************************************************************************
*
* */uses/*
*
* */ ErrorMessage /* https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage
*
*************************************************************************************
*
* Minimizes code generation and global variables while maintaining
* excellent performance.
*
* local thistype this = recycler[0]
*
* if (recycler[this] == 0) then
* set recycler[0] = this + 1
* else
* set recycler[0] = recycler[this]
* endif
*
************************************************************************************
*
* module Alloc
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* readonly boolean isAllocated
*
* debug static method calculateMemoryUsage takes nothing returns integer
* debug static method getAllocatedMemoryAsString takes nothing returns string
*
************************************************************************************/
module Alloc
/*
* stack
*/
private static integer array recycler
/*
* list of allocated memory
*/
debug private static integer array allocatedNext
debug private static integer array allocatedPrev
/*
* free memory counter
*/
debug private static integer usedMemory = 0
/*
* allocation
*/
static method allocate takes nothing returns thistype
local thistype this = recycler[0]
debug call ThrowError(this == 8192, "Alloc", "allocate", "thistype", 0, "Overflow.")
if (recycler[this] == 0) then
set recycler[0] = this + 1
else
set recycler[0] = recycler[this]
endif
set recycler[this] = -1
debug set usedMemory = usedMemory + 1
debug set allocatedNext[this] = 0
debug set allocatedPrev[this] = allocatedPrev[0]
debug set allocatedNext[allocatedPrev[0]] = this
debug set allocatedPrev[0] = this
return this
endmethod
method deallocate takes nothing returns nothing
debug call ThrowError(recycler[this] != -1, "Alloc", "deallocate", "thistype", this, "Attempted To Deallocate Null Instance.")
set recycler[this] = recycler[0]
set recycler[0] = this
debug set usedMemory = usedMemory - 1
debug set allocatedNext[allocatedPrev[this]] = allocatedNext[this]
debug set allocatedPrev[allocatedNext[this]] = allocatedPrev[this]
endmethod
/*
* analysis
*/
method operator isAllocated takes nothing returns boolean
return recycler[this] == -1
endmethod
static if DEBUG_MODE then
static method calculateMemoryUsage takes nothing returns integer
return usedMemory
endmethod
static method getAllocatedMemoryAsString takes nothing returns string
local integer memoryCell = allocatedNext[0]
local string memoryRepresentation = null
loop
exitwhen memoryCell == 0
if (memoryRepresentation == null) then
set memoryRepresentation = I2S(memoryCell)
else
set memoryRepresentation = memoryRepresentation + ", " + I2S(memoryCell)
endif
set memoryCell = allocatedNext[memoryCell]
endloop
return memoryRepresentation
endmethod
endif
/*
* initialization
*/
private static method onInit takes nothing returns nothing
set recycler[0] = 1
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Pool
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script gives the user access to general integer pools. A pool is a data
//* structure that allows you to give entries to it a weight. This weight
//* essentially scales how likely certain random accesses to the pool will be
//* returned by the internal .getRandomInt method. Pools can be useful in any
//* number of ways, such as item drops, randomizing enemy encounters, randomly
//* selecting rects weighted by area, and so forth.
//*
//* Modified by Moco [2013-04-12]:
//* - Fixed a critical issue with the RemoveInt function not properly updating the hashtable
//* - Added a flush method to clear the whole pool
//*
//******************************************************************************
//*
//* Example usage:
//* local intpool ip = intpool.create()
//* call ip.addInt(1, 1.0)
//* call ip.addInt(2, 0.5)
//* call ip.getRandomInt()
//* call ip.getChance(2)
//* call ip.getWeight(2)
//* call ip.removeInt(1)
//*
//* You will first need to create an intpool as shown above. Once you've done
//* that, you may use the .addInt method to add an entry to the pool with a
//* specific weight. The example above adds 2 integers, one twice as likely to
//* be randomly selected as the other. That means for the above example, the
//* .getRandomInt method will 66% of the time return 1 and 33% of the time
//* return 2. If you want to remove an entry from an intpool, the .removeInt
//* method is what you will want to use. If you would like to update an entry's
//* weight after already adding it, simply use .addInt again with the new
//* weight.
//*
//* The .getChance and .getWeight methods are there for convenience. If you are
//* interested in the exact chance of the intpool returning a specific entry,
//* then you should use .getChance to obtain the decimal chance out of 1. If you
//* want to know the weight input for a specific entry, .getWeight will return
//* that for you.
//*
//* When adding an entry to the intpool with .addInt, the actual magnitude of
//* the weight doesn't matter. What matters is its magnitude relative to the
//* magnitudes of all other entries in the intpool. This means that it is ok to
//* use very large or very small weights and is done at the user's discretion.
//*
//* It is worth noting that if you use .getRandomInt on an intpool with no
//* entries, the function will return INTPOOL_NO_ENTRIES, which is about as
//* random an integer as possible so as to avoid people accidentally using it.
//*
globals
//These constants can be changed
private constant integer MAX_INSTANCES = 8191
private constant integer MAX_ENTRIES = 256
constant integer INTPOOL_NO_ENTRIES = 0x672819
//Don't change the following global declaration
private hashtable ht = InitHashtable()
endglobals
struct intpool[MAX_INSTANCES]
private integer Cnt = 0
private real WeightTotal = 0.
private integer array Entries[MAX_ENTRIES]
private real array Weights[MAX_ENTRIES]
private string name = " " // pool name for debug
method getWeight takes integer entry returns real
return Weights[LoadInteger(ht, integer(this), entry)]
endmethod
method getChance takes integer entry returns real
if WeightTotal > 0. then
return Weights[LoadInteger(ht, integer(this), entry)]/WeightTotal
endif
return 0.
endmethod
method addInt takes integer entry, real weight returns nothing
local integer in = 0
if .Cnt == MAX_ENTRIES then
//Can't hold any more entries
debug call BJDebugMsg(SCOPE_PREFIX+"Error: .addEntry has reached MAX_ENTRIES")
return
elseif weight <= 0. then
//Zero or negative weights make no sense
debug call BJDebugMsg(SCOPE_PREFIX+"Error: .addEntry can't take zero or negative weights (" +.name+")")
return
endif
set in = LoadInteger(ht, integer(this), entry)
if in > 0 then
//Update old entry
set .WeightTotal = .WeightTotal - .Weights[in] + weight
set .Weights[in] = weight
// debug call BJDebugMsg(SCOPE_PREFIX+"Pool updated existing entry: "+I2S(entry))
else
//Make a new entry
set .Cnt = .Cnt + 1
call SaveInteger(ht, integer(this), entry, .Cnt)
set .Entries[.Cnt] = entry
set .Weights[.Cnt] = weight
set .WeightTotal = .WeightTotal + weight
// debug call BJDebugMsg(SCOPE_PREFIX+"Pool New Entry: "+I2S(entry))
endif
// debug call BJDebugMsg("Pool added value: "+I2S(entry)+" with weight: "+R2S(weight))
endmethod
method flush takes nothing returns nothing
local integer c = 0
call FlushChildHashtable(ht, integer(this))
loop
exitwhen c > Cnt
set .Entries[.Cnt] = 0
set .Weights[.Cnt] = 0
set c = c + 1
endloop
set .WeightTotal = 0
set .Cnt = 0
endmethod
method showEntries takes nothing returns nothing
local integer c = 1
call BJDebugMsg(" Pool count: "+I2S(Cnt))
loop
exitwhen c > Cnt
call BJDebugMsg("Pool entry #"+I2S(c)+ ": "+I2S(.Entries[c]))
set c = c + 1
endloop
endmethod
method removeInt takes integer entry returns nothing
local integer in = LoadInteger(ht, integer(this), entry)
if in > 0 then
call RemoveSavedInteger(ht, integer(this), entry)
//Remove its entry in the arrays
set .WeightTotal = .WeightTotal - .Weights[in]
if in != .Cnt then
set .Entries[in] = .Entries[.Cnt]
set .Weights[in] = .Weights[.Cnt]
call SaveInteger(ht, integer(this), .Entries[in], in)
endif
set .Entries[.Cnt] = 0
set .Weights[.Cnt] = 0
set .Cnt = .Cnt - 1
if .Cnt == 0 then
call this.flush()
endif
debug else
debug call BJDebugMsg(SCOPE_PREFIX+"Error: .removeEntry entry doesn't exist")
endif
endmethod
method getRandomInt takes nothing returns integer
local real r = GetRandomReal(0, .WeightTotal)
local integer c = 0
if .WeightTotal <= 0. then
debug call BJDebugMsg(SCOPE_PREFIX+"Error: intpool has no entries (" +.name+")")
return INTPOOL_NO_ENTRIES
endif
set r = GetRandomReal(0, .WeightTotal) // Double Random
loop
set r = r - .Weights[c]
exitwhen r <= 0
set c = c + 1
endloop
return .Entries[c]
endmethod
method setName takes string name returns nothing
set this.name = name
endmethod
endstruct
endlibrary
//TESH.scrollpos=112
//TESH.alwaysfold=0
library PathingType initializer onInit
// Configuration
globals
private constant integer PATH_CHECKER = 'h00C'
private constant integer FLY_CHECKER = 'h00E'
private constant integer WALK_CHECKER = 'h00D'
private constant integer BUILD_CHECKER = 'h00F'
private constant player UNUSED_PLAYER = Player(15)
endglobals
/*
PathingType v1.3
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
by: Dalvengyr
Description
¯¯¯¯¯¯¯¯¯¯¯
This library allows you to detect all pathability types:
walkablility, flyability, and buildability. As well as allowing
you to determine the pathing color of given coordinates.
Here is the pathing color specifications:
Color Buildable Walkable Flyable Red Green Blue
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
White x x x 255 255 255
Magenta x x o 255 0 255
Cyan x o x 0 255 255
Blue x o o 0 0 255
Yellow o x x 255 255 0
Red o x o 255 0 0
Green o o x 0 255 0
Black o o o 0 0 0
(You can check your pathing map by pressing 'p' at terrain editor.)
API
¯¯¯
1. Used for checking certain point's flyability
| function IsTerrainFlyable takes real x, real y returns boolean
2. Used for checking certain point's walkability.
| function IsTerrainWalkable takes real x, real y returns boolean
3. Used for checking certain point's buildability.
| function IsTerrainBuildable takes real x, real y returns boolean
4. (Bonus) Used for checking certain point's pathability color.
| function GetTerrainPathingColor takes real x, real y returns integer
Returned values (pathing colors):
| PATHING_COLOR_WHITE
| PATHING_COLOR_MAGENTA
| PATHING_COLOR_CYAN
| PATHING_COLOR_BLUE
| PATHING_COLOR_YELLOW
| PATHING_COLOR_RED
| PATHING_COLOR_GREEN
| PATHING_COLOR_BLACK
How to import
¯¯¯¯¯¯¯¯¯¯¯¯¯
- Copy Fly, Walk, Build, and Path Checker (units) at object editor.
- Make sure Path Checker is able to build Fly, Walk, and Build Checker.
- Configure this system (available above).
Credits
¯¯¯¯¯¯¯
- PurgeandFire for pathability checking method.
- TheHelper.net for complete pathing types tutorial.
Link
¯¯¯¯
hiveworkshop.com/forums/spells-569/pathing-type-v1-2-a-263230/
*/
globals
private unit PathChecker
constant integer PATHING_COLOR_WHITE = 0
constant integer PATHING_COLOR_MAGENTA = 1
constant integer PATHING_COLOR_CYAN = 2
constant integer PATHING_COLOR_BLUE = 3
constant integer PATHING_COLOR_YELLOW = 4
constant integer PATHING_COLOR_RED = 5
constant integer PATHING_COLOR_GREEN = 6
constant integer PATHING_COLOR_BLACK = 7
endglobals
function IsTerrainFlyable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, FLY_CHECKER, x, y)
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, WALK_CHECKER, x, y)
endfunction
function IsTerrainBuildable takes real x, real y returns boolean
return IssueBuildOrderById(PathChecker, BUILD_CHECKER, x, y)
endfunction
function GetTerrainPathingColor takes real x, real y returns integer
local integer color = 0
if IsTerrainFlyable(x, y) then
set color = color + 1
endif
if IsTerrainWalkable(x, y) then
set color = color + 2
endif
if IsTerrainBuildable(x, y) then
set color = color + 4
endif
return color
endfunction
private function onInit takes nothing returns nothing
set PathChecker = CreateUnit(UNUSED_PLAYER, PATH_CHECKER, 0, 0, 0)
call UnitRemoveAbility(PathChecker, 'Amov')
call ShowUnit(PathChecker, false)
if GetLocalPlayer() == UNUSED_PLAYER then
call FogEnable(false)
call FogMaskEnable(false)
set bj_lastCreatedFogModifier = CreateFogModifierRect(UNUSED_PLAYER, FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
call FogModifierStart(bj_lastCreatedFogModifier)
endif
endfunction
endlibrary
//TESH.scrollpos=106
//TESH.alwaysfold=0
library ProgressBars requires TimerUtils optional BoundSentinel
/**************************************************************
*
* ProgressBars v2.0.1 by TriggerHappy
*
* This library allows you to easily create and modify progress bars.
* It works by creating a dummy unit with a special model and changing
* the animation speed to increase or reduce the bar speed. It is more than
* just a wrapper as it recycles each progress bar, meaning it will avoid
* costly CreateUnit calls whenever possible which also leak.
*
* Options:
* x - set X coordinate
* y - set Y coordinate
* xOffset - offset of the target unit, if any.
* yOffset - offset of the target unit, if any.
* zOffset - how high the bar is from the ground.
* color - allows you to tint the bar or add transparency
* targetUnit - pick which unit the bar should hover over
* size - set model scale
*
* Usage:
* local ProgressBar bar = ProgressBar.create()
* set bar.zOffset = 150
* set bar.color = PLAYER_COLOR_RED
* set bar.targetUnit = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
* call bar.setPercentage(30)
*
* Installation:
* 1. Copy the dummy unit over to your map
* 2. Change the DUMMY constant to fit the Raw code of the dummy.
* 3. Copy this and all required libraries over to your map.
*
* Thanks to JesusHipster for the Progress Bar models
* and to Vexorian for TimerUtils & BoundSentinel
*
**************************************************************/
globals
private constant integer PROGRESS_BAR_DUMMY = 'e001' // the default one
private constant player PROGRESS_BAR_OWNER = Player(PLAYER_NEUTRAL_PASSIVE) // owner of the dummy
private constant real UPDATE_POSITION_PERIOD = 0.03 // the timer period used with .targetUnit
private integer DUMMY_COUNT = 0
endglobals
struct ProgressBar
unit bar
unit target
real xOffset = 0
real yOffset = 0
timer timer
timer timer2
private boolean t_enabled = false
private real endVal
private real curVal=0
private real pspeed=0
private boolean reverse
private boolean done
private boolean recycle
readonly static unit array dummy
readonly static integer lastDummyIndex = -1
method operator x= takes real x returns nothing
call SetUnitX(this.bar, x)
endmethod
method operator x takes nothing returns real
return GetUnitX(this.bar)
endmethod
method operator y= takes real y returns nothing
call SetUnitY(this.bar, y)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.bar)
endmethod
method operator zOffset= takes real offset returns nothing
call SetUnitFlyHeight(this.bar, offset, 0)
endmethod
method operator zOffset takes nothing returns real
return GetUnitFlyHeight(this.bar)
endmethod
method operator size= takes real size returns nothing
call SetUnitScale(this.bar, size, size, size)
endmethod
method operator color= takes playercolor color returns nothing
call SetUnitColor(this.bar, color)
endmethod
method show takes boolean flag returns nothing
call UnitRemoveAbility(this.bar, 'Aloc')
call ShowUnit(this.bar, flag)
call UnitAddAbility(this.bar, 'Aloc')
endmethod
method reset takes nothing returns nothing
call SetUnitAnimationByIndex(this.bar, 1)
endmethod
method RGB takes integer red, integer green, integer blue, integer alpha returns nothing
call SetUnitVertexColor(this.bar, red, green, blue, alpha)
endmethod
method destroy takes nothing returns nothing
if (recycle) then
set lastDummyIndex = lastDummyIndex + 1
set dummy[lastDummyIndex] = this.bar
call SetUnitAnimationByIndex(this.bar, 0)
call SetUnitTimeScale(this.bar, 1)
endif
set this.bar = null
set this.target = null
set this.t_enabled = false
set this.endVal = 0
set this.curVal = 0
if (this.timer != null) then
call ReleaseTimer(this.timer)
set this.timer = null
endif
if (this.timer2 != null) then
call ReleaseTimer(this.timer2)
set this.timer2 = null
endif
endmethod
private static method updatePercentage takes nothing returns nothing
local timer expired = GetExpiredTimer()
local thistype this = GetTimerData(expired)
if (this.reverse) then
if (this.curVal > this.endVal) then
call SetUnitTimeScale(this.bar, -this.pspeed)
set this.curVal = (this.curVal - (this.pspeed))
elseif (this.curVal <= this.endVal) then
call PauseTimer(this.timer2)
call SetUnitTimeScale(this.bar, 0)
set this.curVal = this.endVal
set this.done = true
endif
else
if (this.curVal < this.endVal) then
call SetUnitTimeScale(this.bar, this.pspeed)
set this.curVal = (this.curVal + (this.pspeed))
elseif (this.curVal >= this.endVal) then
call PauseTimer(this.timer2)
call SetUnitTimeScale(this.bar, 0)
set this.curVal = this.endVal
set this.done = true
endif
endif
set expired = null
endmethod
private static method updatePosition takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
if (this.target != null) then
call SetUnitX(this.bar, GetUnitX(this.target) + xOffset)
call SetUnitY(this.bar, GetUnitY(this.target) + yOffset)
else
call ReleaseTimer(GetExpiredTimer())
endif
endmethod
private static method getDummy takes nothing returns unit
if (lastDummyIndex <= -1) then
set bj_lastCreatedUnit = CreateUnit(PROGRESS_BAR_OWNER, PROGRESS_BAR_DUMMY, 0, 0, 270)
call PauseUnit(bj_lastCreatedUnit, true)
return bj_lastCreatedUnit
endif
call SetUnitAnimationByIndex(dummy[lastDummyIndex], 1)
set lastDummyIndex = lastDummyIndex - 1
return dummy[lastDummyIndex + 1]
endmethod
static method release takes integer count returns nothing
if (count > thistype.lastDummyIndex) then
set count = thistype.lastDummyIndex
endif
debug call BJDebugMsg("release method of progress bar")
loop
exitwhen count <= 0
call RemoveUnit(dummy[count])
set DUMMY_COUNT = DUMMY_COUNT - 1
set dummy[count] = null
set count = count - 1
endloop
set thistype.lastDummyIndex = -1
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.bar = thistype.getDummy()
set this.done = true
set this.recycle = true
set DUMMY_COUNT = DUMMY_COUNT + 1
call SetUnitAnimationByIndex(this.bar, 1)
call SetUnitTimeScale(this.bar, 0)
debug call BJDebugMsg("progress bar dummy count: "+I2S(DUMMY_COUNT))
return this
endmethod
static method createEx takes integer unitId returns thistype
local thistype this = thistype.allocate()
set this.bar = CreateUnit(PROGRESS_BAR_OWNER, unitId, 0, 0, 0)
set this.done = true
set this.recycle = false
call SetUnitAnimationByIndex(this.bar, 1)
call SetUnitTimeScale(this.bar, 0)
return this
endmethod
method setPercentage takes real percent, real speed returns nothing
set this.endVal = R2I(percent)
set this.pspeed = speed
set this.reverse = (curVal > endVal)
if (this.done) then
if (this.timer2 == null) then
set this.timer2 = NewTimerEx(this)
endif
call TimerStart(this.timer2, 0.01, true, function thistype.updatePercentage)
set this.done=false
endif
endmethod
method operator targetUnit= takes unit u returns nothing
set this.target = u
if (u != null) then
if (this.timer == null) then
set this.timer = NewTimerEx(this)
endif
call TimerStart(this.timer, UPDATE_POSITION_PERIOD, true, function thistype.updatePosition)
call SetUnitX(this.bar, GetUnitX(this.target) - xOffset)
call SetUnitY(this.bar, GetUnitY(this.target) - yOffset)
set this.t_enabled = true
else
if (this.timer != null) then
call ReleaseTimer(this.timer)
endif
set this.t_enabled = false
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=78
//TESH.alwaysfold=0
library ReverseAnimation requires TimerUtils
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ReverseAnimation
//====================================================================================================================
// Firstly, this script requires TimerUtils (by Vexorian @ [url]www.wc3campaigns.net):[/url]
// [url]http://wc3campaigns.net/showthread.php?t=101322[/url]
//
// Background Info:
// [url]http://www.wc3campaigns.net/showpost.php?p=1017121&postcount=88[/url]
//
// function SetUnitAnimationReverse takes:
//
// unit u - animation of which reverse animation is played;
// integer index - animation index of the animation to be played;
// real animTime - the natural duration of the animation to be played. This can be referred to in the preview
// window in the bottom-left part of the World Editor interface (it is the real value enclosed
// in parenthesis);
// real runSpeed - the speed at which the animation to be played in reverse will be ran.
// boolean resetAnim - indicates to the system if it should set the unit's animation to "stand" after playing the
// reverse animation.
//
// function SetUnitAnimationReverseFollowed takes all of the above and:
// FollowUpFunc func - function to be ran after the animation is played. Expressed as a function interface
// (see below). Takes an data object arguement pertaining to relevant stuff that must be
// passed.
// integer data - a struct that is the above data object.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
// -- Configuration --
globals
private constant real PREP_INTERVAL_DURATION = 0.03
endglobals
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
// -- User Functions --
private keyword ReverseAnimation
function SetUnitAnimationReverse takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim returns boolean
return ReverseAnimation.Prepare(u, index, animTime, runSpeed, resetAnim, 0, 0)
endfunction
function SetUnitAnimationReverseFollowed takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim, FollowUpFunc func, integer data returns boolean
return ReverseAnimation.Prepare(u, index, animTime, runSpeed, resetAnim, func, data)
endfunction
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
//IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII//
// -- Script Operation Functions --
function interface FollowUpFunc takes integer data returns nothing
private struct ReverseAnimation
private unit u
private integer intAnimIndex
private real rAnimTime
private real rRunSpeed
private boolean boolResetAnim
private FollowUpFunc func
private integer data
public static method Prepare takes unit u, integer index, real animTime, real runSpeed, boolean resetAnim, FollowUpFunc func, integer data returns boolean
local ReverseAnimation new = 0
local timer TIM = null
if u != null and runSpeed > 0.00 then // MoCo
set new = .allocate()
set new.u = u
set new.intAnimIndex = index
set new.rAnimTime = animTime
set new.rRunSpeed = -runSpeed
set new.boolResetAnim = resetAnim
set new.func = func
set new.data = data
call SetUnitTimeScale(u, animTime/PREP_INTERVAL_DURATION)
call SetUnitAnimationByIndex(u, index)
set TIM = NewTimer()
call SetTimerData(TIM, integer(new))
call TimerStart(TIM, PREP_INTERVAL_DURATION, false, function ReverseAnimation.Play)
set TIM = null
return true
endif
return false
endmethod
public static method Play takes nothing returns nothing
local timer TIM = GetExpiredTimer()
local ReverseAnimation INST = GetTimerData(TIM)
call SetUnitTimeScale(INST.u, INST.rRunSpeed)
call TimerStart(TIM, INST.rAnimTime/-INST.rRunSpeed, false, function ReverseAnimation.End)
set TIM = null
endmethod
public static method End takes nothing returns nothing
local timer TIM = GetExpiredTimer()
local ReverseAnimation INST = GetTimerData(TIM)
call SetUnitTimeScale(INST.u, 1.00)
if INST.boolResetAnim then
call SetUnitAnimation(INST.u, "stand")
endif
if INST.func != 0 then
call INST.func.execute(INST.data)
endif
set INST.u = null
call INST.destroy()
call ReleaseTimer(TIM)
set TIM = null
endmethod
endstruct
endlibrary
//TESH.scrollpos=95
//TESH.alwaysfold=0
//* API:
//* boolean ADD_ALL_UNITS: If enabled, a trigger turns on which automatically
//* registers all units in the map.
//* integer BUCKET_SIZE: How many units to add to each 'bucket' - a larger
//* bucket will have their trigger refresh less frequently but will be
//* more computationally expensive. A good starting value is about 20.
//* real PER_CLEANUP_TIMEOUT: How many seconds to wait in between each
//* scan for empty buckets. This value should be lower if units die often
//* in your map. A good starting value is about 60.
//* static method addHandler: Registers a callback function to the generic
//* unit damage event. Example: call StructuredDD.addHandler(function h)
//* static method add: Adds a unit to a bucket. If ADD_ALL_UNITS is enabled,
//* this method need not be used.
library StructuredDD
globals
//<< BEGIN SETTINGS SECTION
//* Set this to true if you want all units in your map to be
//* automatically added to StructuredDD. Otherwise you will have to
//* manually add them with StructuredDD.add(u).
private constant boolean ADD_ALL_UNITS=false
//* This is the amount of units that exist in each trigger bucket.
//* This number should be something between 5 and 30. A good starting
//* value will be an estimate of your map's average count of units,
//* divided by 10. When in doubt, just use 20.
private constant integer BUCKET_SIZE=10
//* This is how often StructuredDD will search for empty buckets. If
//* your map has units being created and dying often, a lower value
//* is better. Anything between 10 and 180 is good. When in doubt,
//* just use 60.
private constant real PER_CLEANUP_TIMEOUT= 120.
//>> END SETTINGS SECTION
endglobals
//* Our bucket struct which contains a trigger and its associated contents.
private struct bucket
integer bucketIndex=0
trigger trig=CreateTrigger()
unit array members[BUCKET_SIZE]
endstruct
//* Our wrapper struct. We never intend to actually instanciate "a
//* StructuredDD", we just use this for a pretty, java-like API :3
struct StructuredDD extends array
private static boolexpr array conditions
private static bucket array bucketDB
private static integer conditionsIndex=-1
private static integer dbIndex=-1
private static integer maxDBIndex=-1
//* This method gets a readily available bucket for a unit to be added.
//* If the "current" bucket is full, it returns a new one, otherwise
//* it just returns the current bucket.
private static method getBucket takes nothing returns integer
local integer index=0
local integer returner=-1
local bucket tempDat
if thistype.dbIndex!=-1 and thistype.bucketDB[thistype.dbIndex].bucketIndex<BUCKET_SIZE then
return thistype.dbIndex
else
set thistype.maxDBIndex=thistype.maxDBIndex+1
set thistype.dbIndex=thistype.maxDBIndex
set tempDat=bucket.create()
set thistype.bucketDB[.maxDBIndex]=tempDat
loop
exitwhen index>thistype.conditionsIndex
call TriggerAddCondition(tempDat.trig,thistype.conditions[index])
set index=index+1
endloop
return thistype.dbIndex
endif
return -1
endmethod
//* This method is for adding a handler to the system. Whenever a
//* handler is added, damage detection will immediately trigger that
//* handler. There is no way to deallocate a handler, so don't try to
//* do this dynamically (!) Support for handler deallocation is
//* feasible (please contact me)
public static method addHandler takes code func returns nothing
local bucket tempDat
local integer index=0
set thistype.conditionsIndex=thistype.conditionsIndex+1
set thistype.conditions[thistype.conditionsIndex]=Condition(func)
loop
exitwhen index>thistype.maxDBIndex
set tempDat=thistype.bucketDB[index]
call TriggerAddCondition(tempDat.trig,thistype.conditions[thistype.conditionsIndex])
set index=index+1
endloop
endmethod
//* This method adds a unit to the damage detection system. If
//* ADD_ALL_UNITS is enabled, this method need not be used.
public static method add takes unit member returns nothing
local bucket tempDat
local integer whichBucket=thistype.getBucket()
set tempDat=thistype.bucketDB[whichBucket]
set tempDat.bucketIndex=tempDat.bucketIndex+1
set tempDat.members[tempDat.bucketIndex]=member
call TriggerRegisterUnitEvent(tempDat.trig,member,EVENT_UNIT_DAMAGED)
endmethod
//* This is just an auxillary function for ADD_ALL_UNITS' implementation
static if ADD_ALL_UNITS then
private static method autoAddC takes nothing returns boolean
call thistype.add(GetTriggerUnit())
return false
endmethod
endif
//* This method is used to check if a given bucket is empty (and thus
//* can be deallocated) - this is an auxillary reoutine for the
//* periodic cleanup system.
private static method bucketIsEmpty takes integer which returns boolean
local bucket tempDat=thistype.bucketDB[which]
local integer index=0
loop
exitwhen index==BUCKET_SIZE
//GetUnitTypeId(unit)==0 means that the unit has been removed.
if GetUnitTypeId(tempDat.members[index])!=0 then
return false
endif
set index=index+1
endloop
return true
endmethod
//* This method cleans up any empty buckets periodically by checking
//* if it has been fully allocated and then checking if all its
//* members no longer exist.
private static method perCleanup takes nothing returns nothing
local integer index=0
loop
exitwhen index>thistype.maxDBIndex
if index!=thistype.dbIndex and thistype.bucketIsEmpty(index) then
call DestroyTrigger(thistype.bucketDB[index].trig)
call thistype.bucketDB[index].destroy()
set thistype.bucketDB[index]=thistype.bucketDB[thistype.maxDBIndex]
set thistype.maxDBIndex=thistype.maxDBIndex-1
if thistype.maxDBIndex==thistype.dbIndex then
set thistype.dbIndex=index
endif
set index=index-1
endif
set index=index+1
endloop
endmethod
//* This is a initialization function necessary for the setup of
//* StructuredDD.
private static method onInit takes nothing returns nothing
local group grp
local region reg
local trigger autoAddUnits
local timer perCleanup
local unit FoG
static if ADD_ALL_UNITS then
//Add starting units
set grp=CreateGroup()
call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
call thistype.add(FoG)
call GroupRemoveUnit(grp,FoG)
endloop
//Add entering units
set autoAddUnits=CreateTrigger()
set reg=CreateRegion()
call RegionAddRect(reg,bj_mapInitialPlayableArea)
call TriggerRegisterEnterRegion(autoAddUnits,reg,null)
call TriggerAddCondition(autoAddUnits,Condition(function thistype.autoAddC))
set autoAddUnits=null
set reg=null
endif
//enable periodic cleanup:
set perCleanup=CreateTimer()
call TimerStart(perCleanup,PER_CLEANUP_TIMEOUT,true,function thistype.perCleanup)
set perCleanup=null
endmethod
endstruct
endlibrary
//TESH.scrollpos=238
//TESH.alwaysfold=0
library IntuitiveDamageSystem initializer Init requires Table, HeroSystem
//******************************************************************************
//* BY: Rising_Dusk
//* (Intuitive) Damage Detection System 1.14
//*
//* This library is the core for what has come to be known as the Intuitive
//* Damage Detection System, or IDDS for short. Simply by copying this library
//* into your map somewhere, you will have access to all of its features and
//* options. Below this documentation are some global variables that can be
//* edited to make the system more useful for your map, whatever it might be.
//* Please note that you should only change those globals listed under
//* configuration constants and damage type constants.
//*
//* An important note for the system is that all non-attack damage in your map
//* MUST BE TRIGGERED using the special function call included in this system,
//* UnitDamageTargetEx. This is how the system works to detect attacks, because
//* if the only non-triggered damage in your map originates from attacks, you
//* clearly know which damage packets are attacks. This allows users to use
//* orb abilities in their maps for whatever they want.
//*
//* function UnitDamageTargetEx takes unit source, unit target, real damage, ...
//* ...attacktype attackType, integer damageType, boolean ConsiderArmor returns boolean
//*
//* This is the function with which you will deal all triggered damage in your
//* map. The damageType argument is one of the predefined integer constants that
//* you can edit or add below. Default values for this with the system are
//* DAMAGE_TYPE_ATTACK, DAMAGE_TYPE_SPELL, and DAMAGE_TYPE_EXTRA. You can
//* trigger the system to treat triggered damage like it is an attack if you
//* want to by using DAMAGE_TYPE_ATTACK. It is very easy to make new damage
//* types in the system, just follow the instructions in the configuration
//* constants area. In addition, be sure that the constants you define do not
//* conflict with the predefined Blizzard constants. (ie. DAMAGE_TYPE_FIRE) If
//* these conflicts do exist, you will encounter multiply defined syntax errors.
//* The AttackType argument is the same as in the regular UnitDamageTarget
//* native. Also, the system allows you to consider armor when dealing damage or
//* not. Set the ConsiderArmor boolean argument to false if you want to ignore
//* armor for that damage, or true if you want to factor it in.
//*
//* function TriggerUnregisterDamageEvent takes trigger trg returns boolean
//* function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
//*
//* The TriggerRegisterDamageEvent function is used when initializing a damage
//* detection response trigger. By using this, it allows you to use a syntax
//* structure nigh-identical to the standard JASS2. It returns a boolean for
//* your convenience that is false if you pass it a null trigger. The system
//* also allows you to pass a positive, zero-inclusive integer to it as that
//* trigger's priority. The higher the number you pass, the later on in the
//* trigger executions it will fire. This is useful if you want shield
//* abilities, as you will want their priorities low so that they can block the
//* damage before it gets to other things. You are also allowed to unregister
//* a trigger from the system at any time if you want; this will likely never
//* have to be done for most maps.
//*
//* function SetDamage takes real dmg returns nothing
//* function SetDamageType takes integer dmgtype returns boolean
//*
//* With this function, you can modify the damage the system interprets for its
//* triggers. This function DOES NOT ACTUALLY CHANGE THE DAMAGE BEING DEALT, it
//* is merely a tool for users to use to change the internal variables. The user
//* will need to modify the damage himself by some other means. Similarly, the
//* SetDamageType function internally changes the damage type of a given packet
//* of damage. This can be useful if you want to convert DAMAGE_TYPE_ATTACK into
//* something else or if you want dynamic damagetypes in-game.
//*
//* function SetTriggerPriority takes trigger trg, integer priority returns boolean
//* function GetTriggerPriority takes trigger trg returns integer
//*
//* These functions let you set or get a given trigger's priority at will. These
//* functions both require that the trigger being passed to it is registered to
//* the IDDS system. If you pass an unregistered trigger to GetTriggerPriority,
//* it will return -1. If you pass a similar trigger to SetTriggerPriority, it
//* will return false.
//*
//* function IgnoreHigherPriority takes nothing returns boolean
//*
//* This function is one of the most important reasons for priorities to exist.
//* With it, you can tell the system to ignore higher priority triggers. This
//* is useful, for instance, if you have a triggered evasion ability and don't
//* want anything else to be done with that damage because it was dodged. Other,
//* similar damage-preventing routines will also find this function useful.
//*
//* function RegisterDamageType takes nothing returns integer
//*
//* This function is useful for declaring your own DAMAGE_TYPE_ETC constants
//* external to the system. By declaring your global variable and then calling
//* this on it as follows, you can register new damage types on the fly. This
//* is very useful if you want other systems or spells to introduce new damage
//* types that are either ignored or do special things for that application.
//*
//* function GetTriggerDamageType takes nothing returns integer
//* function GetTriggerDamageSource takes nothing returns unit
//* function GetTriggerDamageTarget takes nothing returns unit
//* function GetTriggerDamageBase takes nothing returns real
//* function GetTriggerDamage takes nothing returns real
//*
//* Like normal WC3 damage detection, the system has event responses for the
//* damage source, the target of the damage, the amount of damage dealt, and
//* other things. It also permits the detection of damage type, which is
//* something standard WC3 does not have. This lets you create on-attack spells
//* very easily whereas without the system it would be very difficult and
//* computationally costly. GetTriggerDamageBase returns the amount of damage
//* the unit was dealt at the beginning of a given trigger series, whereas
//* GetTriggerDamage returns whatever damage the unit has left to receive, if
//* it has been modified in any way with the SetDamage function mentioned
//* earlier.
//*
//* Once you understand all of the aforementioned aspects of the system, you're
//* ready to put it to use. I know it can be tricky to require all spells be
//* triggered, but this is the way of many great maps anyways, so such a
//* requirement is not so unreasonable. If you have any questions regarding the
//* system, please go to [url]www.wc3c.net[/url] and send a private message to the account
//* Rising_Dusk and I will respond as soon as I can. This system may only be
//* released at [url]www.wc3c.net[/url] and its existence on any other website is against
//* the author's will.
//*
//* Enjoy!
//*
globals
//* Configuration constants
private integer DamageTypeCount = 4
//* These are the damagetype constant globals for ease of use
constant integer DAMAGE_TYPE_ATTACK = 0
constant integer DAMAGE_TYPE_SPELL = 1
constant integer DAMAGE_TYPE_EXTRA = 2
constant integer DAMAGE_TYPE_IGNORED = 3
constant integer DAMAGE_TYPE_HEALING = 4
// constant integer DAMAGE_TYPE_ATTACK = 0
// constant integer DAMAGE_TYPE_IGNORED = 1
// constant integer DAMAGE_TYPE_SPELL = 2
// constant integer DAMAGE_TYPE_EXTRA = 3
//* To add new constants, simply follow the naming convention and increment
//* the number. You shouldn't change or remove DAMAGE_TYPE_ATTACK or
//* DAMAGE_TYPE_IGNORED, though, since they have special properties in the
//* system.
//* These are static constants used by the system and shouldn't be changed
private trigger RunTrigger = CreateTrigger()
private trigger AddTrigger = CreateTrigger()
private integer Count = 0
private Table TrigTable = 0
private Table RegiTable = 0
private boolean IgnPrior = false
private integer array NewDamageType
private real array NewDamage
private trigger array Trg
private integer array Priority
//* Temporary variables used by the system
private unit DamageSource = null
private unit DamageTarget = null
private integer DamageType = 0
private integer DamageId = 0
private real DamageBase = 0.
private real Damage = 0.
endglobals
//******************************************************************************
//******************************************************************************
//* Use an insertion sort algorithm to sort the trigger stack based on priority
private function TriggerSort takes nothing returns boolean
local integer i = 1
local integer j = 0
local integer p = 0
local trigger t = null
loop
exitwhen i >= Count
set t = Trg[i]
set p = Priority[i]
set j = i-1
loop
exitwhen j < 0 or Priority[j] <= p
set Priority[j+1] = Priority[j]
set Trg[j+1] = Trg[j]
set TrigTable[GetHandleId(Trg[j])] = j+1
set j = j - 1
endloop
set Priority[j+1] = p
set Trg[j+1] = t
set TrigTable[GetHandleId(t)] = j+1
set i = i + 1
endloop
set t = null
return true
endfunction
//******************************************************************************
//******************************************************************************
//* The function to call when you want to end a damage's trigger series
function IgnoreHigherPriority takes nothing returns boolean
if DamageSource != null then
//Make sure it was called in the right place
set IgnPrior = true
endif
return IgnPrior
endfunction
//* Changes the base damage for a trigger series on the fly
function SetDamage takes real dmg returns boolean
if DamageSource != null and dmg >= 0 then
//Make sure it was called in the right place
set NewDamage[DamageId] = dmg
set Damage = dmg
return true
endif
return false
endfunction
//* Changes the base damage type of the series
function SetDamageType takes integer dmgtype returns boolean
if DamageSource != null and dmgtype >= 0 then
//Make sure it was called in the right place
set NewDamageType[DamageId] = dmgtype
set DamageType = dmgtype
return true
endif
return false
endfunction
//* Returns the given trigger's priority if it's loaded to the system
function GetTriggerPriority takes trigger trg returns integer
if RegiTable[GetHandleId(trg)] == 0 then
return -1
endif
return Priority[TrigTable[GetHandleId(trg)]]
endfunction
//* Sets the given trigger's priority if it's loaded to the system
function SetTriggerPriority takes trigger trg, integer priority returns boolean
if RegiTable[GetHandleId(trg)] == 0 or priority < 0 then
return false
endif
set Priority[TrigTable[GetHandleId(trg)]] = priority
return TriggerSort()
endfunction
//******************************************************************************
//******************************************************************************
//* The new damage function used by the system
function UnitDamageTargetEx takes unit source, unit target, real damage, attacktype attackType, integer damageType, boolean ConsiderArmor, boolean isCrit returns boolean
local boolean b = false
set DamageType = damageType
set DamageSource = source
set CritDeath[GetHandleId(target)] = 0
if isCrit then
set CritDeath[GetHandleId(target)] = 1
endif
if ConsiderArmor then
set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_NORMAL, null)
else
set b = UnitDamageTarget(source, target, damage, false, false, attackType, DAMAGE_TYPE_UNIVERSAL, null)
endif
if not b or damageType == DAMAGE_TYPE_IGNORED then
set DamageType = DAMAGE_TYPE_ATTACK
set DamageSource = null
endif
return b
endfunction
//* The method by which one registers a trigger with the system
function TriggerRegisterDamageEvent takes trigger trg, integer priority returns boolean
if trg == null or priority < 0 then
return false
endif
if RegiTable[GetHandleId(trg)] == 0 then
set RegiTable[GetHandleId(trg)] = 1
endif
set Trg[Count] = trg
set Priority[Count] = priority
set TrigTable[GetHandleId(trg)] = Count
set Count = Count + 1
return TriggerSort()
endfunction
//* The method by which one unregisters a trigger from the system
function TriggerUnregisterDamageEvent takes trigger trg returns boolean
local integer i = 0
if trg == null then
return false
endif
set i = TrigTable[GetHandleId(trg)]
if trg != Trg[i] then
return false
endif
set Trg[i] = Trg[Count]
set Priority[i] = Priority[Count]
set TrigTable[GetHandleId(Trg[i])] = i
set RegiTable[GetHandleId(trg)] = 0
set Count = Count - 1
return TriggerSort()
endfunction
//* Initialization shorthand to register a new damage type externally
function RegisterDamageType takes nothing returns integer
local integer i = DamageTypeCount
set DamageTypeCount = DamageTypeCount + 1
return i
endfunction
//******************************************************************************
//******************************************************************************
//* Wrappers for the system that can get inlined anyways
function GetTriggerDamageType takes nothing returns integer
return DamageType
endfunction
function GetTriggerDamageSource takes nothing returns unit
return DamageSource
endfunction
function GetTriggerDamageTarget takes nothing returns unit
return DamageTarget
endfunction
function GetTriggerDamageBase takes nothing returns real
return DamageBase
endfunction
function GetTriggerDamage takes nothing returns real
return Damage
endfunction
//******************************************************************************
//******************************************************************************
private function RunConditions takes nothing returns boolean
//* The conditions for what must be true for damage detection to run
return GetEventDamage() >= 0.0001 and DamageType != DAMAGE_TYPE_IGNORED
endfunction
private function AddConditions takes nothing returns boolean
//* The conditions for registering a unit with the damage system
return true
endfunction
private function PreloadConditions takes unit u returns boolean
//* The conditions for preloading a unit to the damage system
return true
endfunction
//******************************************************************************
//******************************************************************************
globals
private integer array IDStack
private integer IDC = 0
private integer IDN = 0
endglobals
private function Run takes nothing returns nothing
local unit u = GetEventDamageSource()
local unit s = DamageSource
local unit t = GetTriggerUnit()
local integer i = 0
local integer id = 0
local integer d = DamageType
local real r = GetEventDamage()
local real b = r
//Allocate an id for this damage packet
if IDN > 0 then
set id = IDStack[IDN]
set IDN = IDN - 1
else
set id = IDC
set IDC = IDC + 1
endif
if DamageSource == null then
//Damage is of type attack
set d = DAMAGE_TYPE_ATTACK
set s = u
endif
loop
exitwhen i > Count or IgnPrior
//Ensure all variables are correct for nesting
set Damage = r
set DamageBase = b
set DamageTarget = t
set DamageSource = s
set DamageType = d
set DamageId = id
set NewDamage[id] = 0.
set NewDamageType[id] = -1
if IsTriggerEnabled(Trg[i]) and TriggerEvaluate(Trg[i]) then
call TriggerExecute(Trg[i])
endif
if NewDamage[id] > 0. then
//Update damage if it was changed
set r = NewDamage[id]
endif
if NewDamageType[id] >= 0 then
//Update damagetype if it was changed
set d = NewDamageType[id]
endif
set i = i + 1
endloop
set Damage = 0.
set DamageBase = 0.
set DamageTarget = null
set DamageSource = null
set DamageType = DAMAGE_TYPE_ATTACK
set DamageId = 0
set IgnPrior = false
set NewDamage[id] = 0.
//Return id to the stack
set IDN = IDN + 1
set IDStack[IDN] = id
set u = null
set s = null
set t = null
endfunction
private function Load takes nothing returns nothing
call TriggerRegisterUnitEvent(RunTrigger, GetEnteringUnit(), EVENT_UNIT_DAMAGED)
endfunction
//******************************************************************************
//******************************************************************************
private function PreloadUnits takes nothing returns boolean
if PreloadConditions(GetFilterUnit()) then
call TriggerRegisterUnitEvent(RunTrigger, GetFilterUnit(), EVENT_UNIT_DAMAGED)
endif
return false
endfunction
private function Init takes nothing returns nothing
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr b = Condition(function PreloadUnits)
local group g = CreateGroup()
//* Create the tables for use with the system
set TrigTable = Table.create()
set RegiTable = Table.create()
call TriggerAddAction(RunTrigger, function Run)
call TriggerAddCondition(RunTrigger, Condition(function RunConditions))
call GroupEnumUnitsInRect(g, r, b)
call RegionAddRect(re, r)
call TriggerRegisterEnterRegion(AddTrigger, re, null)
call TriggerAddAction(AddTrigger, function Load)
call TriggerAddCondition(AddTrigger, Condition(function AddConditions))
call RemoveRect(r)
call DestroyGroup(g)
call DestroyBoolExpr(b)
set re = null
set g = null
set b = null
set r = null
endfunction
endlibrary
//TESH.scrollpos=102
//TESH.alwaysfold=0
library ShieldSystem initializer Init requires IntuitiveBuffSystem
// The_Witcher's Shield System
//
// This is an easy to use shield system.
// it allows you to add shield points to a unit
// the shield works like in the game halo:
// the attacked unit doesn't receive any dmg, the shield gets it
// when the shield is down the unit is damaged
// the shield can reload constantly or after some seconds of not beeing attacked
//
// to give a unit a shield just use (if duration is 0 the shield will stay without a time limit)
//
// call AddShield( towhichunit, hitpoints, RegPerSec, TimeTillReg, damage factor, colorcode, destroy when shieldhp = 0, show the bar, Duration )
// unit real real real real string boolean boolean real
//
// you can check whether a unit has already a shield with (it will return a boolean)
// UnitHasShield( yourunit)
// unit
//
// to implement this system, just copy this trigger in your map
// it requires jngp to be edited/saved
//
// To get rid of a shield just use
// call DestroyShield( which unit's)
// unit
//
// to show or hide the shield bar use
// call ShowShield( WhichUnits, Show? )
// unit boolean
//
// to get information about an existing shield use:
// HP: GetShieldHp( unit )
// maxHP: GetShieldMaxHp( unit )
// percentHP: GetShieldHpPercent( unit )
// regeneration: GetShieldReg( unit )
// TimeTillReg: GetShieldTimeTillReg( unit )
// DamageFactor: GetShieldDamageFactor( unit )
//
// to change the values of an existing shield use:
// HP: SetShieldHp( unit, NewValue )
// maxHP: SetShieldMaxHp( unit, NewValue )
// percentHP: SetShieldHpPercent( unit, NewValue )
// regeneration: SetShieldReg( unit, NewValue )
// TimeTillReg: SetShieldTimeTillReg( unit, NewValue )
// DamageFactor: SetShieldDamageFactor( unit, NewValue )
//
// have fun^^
// The (very small^^) Setup part
globals
// the shieldbar's size (should be (7.5 * 0.023 / 10 - 0.00625) or 0.01(which isn't working for everyone) for a good result)
private constant real size = 7.5 * 0.023 / 10 - 0.00625
// A ability which gives a high instant life bonus
private constant integer lifeabi = 'A001'
// the timer interval (should be 0.01 but if laggy then just change it)
private constant real interval = 0.01
//the path of the special effect for untis with a shield
//another good effect: "Abilities\\Spells\\Human\\DivineShield\\DivineShieldTarget.mdl"
// private constant string sfx = "Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl"
//the attachement point for sfx
private constant string AtPoint = "chest"
endglobals
// end of Setup!!
private struct shield
unit u
real hp
real fullhp
real reg
real f
string code
texttag t
real r
effect fx
real remain
timer time
boolean kill
integer i
real damage = 0
boolean show
endstruct
globals
private trigger trg = CreateTrigger()
private group g = CreateGroup()
private hashtable h = InitHashtable()
private integer total = 0
private unit array units
private timer tim = CreateTimer()
endglobals
function UnitHasShield takes unit u returns boolean
return LoadInteger(h,GetHandleId(u),0) != 0
endfunction
function DestroyShield takes unit whichunits returns nothing
local shield dat = LoadInteger(h,GetHandleId(whichunits),0)
local shield dat2 = LoadInteger(h,GetHandleId(units[total-1]),0)
call Debug_Message("Destroy Shield")
if dat != 0 then
call DestroyTextTag(dat.t)
// add by Moco
set dat.t = null
call DestroyTimer(dat.time)
call DestroyEffect(dat.fx)
call FlushChildHashtable(h,GetHandleId(whichunits))
set total = total - 1
set units[dat.i] = units[total]
set dat2.i = dat.i
call dat.destroy()
// If unit already has old buff, remove it
// if UnitHasBuff(whichunits, BUFF_TYPE_ICE_BARRIER) then
// call UnitRemoveBuff(whichunits, BUFF_TYPE_ICE_BARRIER)
// endif
// if UnitHasBuff(whichunits, BUFF_TYPE_SHIELD) then
// call UnitRemoveBuff(whichunits, BUFF_TYPE_SHIELD)
// endif
if UnitHasBuff(whichunits, BUFF_TYPE_SOUL_SHIELD) then
call UnitRemoveBuff(whichunits, BUFF_TYPE_SOUL_SHIELD)
endif
endif
if total == 0 then
call PauseTimer(tim)
endif
endfunction
private function regeneration takes nothing returns nothing
local shield dat
local string s = "''''''''''''''''''''''''''''''''''''''''''''''''''"
local integer k
local integer i = 0
loop
exitwhen i >= total
set dat = LoadInteger(h,GetHandleId(units[i]),0)
if TimerGetRemaining(dat.time) == 0 then
if dat.hp < dat.fullhp then
set dat.hp = dat.hp + dat.reg
else
set dat.hp = dat.fullhp
endif
endif
if dat.remain > 0 then
set dat.remain = dat.remain - interval
elseif dat.remain != -100 then
call DestroyShield(dat.u)
endif
set k = R2I(50 * (dat.hp / dat.fullhp))
call SetTextTagText(dat.t, dat.code + SubString(s,0, k ) + "|r" + SubString(s,k + 1,StringLength(s)) , size)
call SetTextTagPos(dat.t,GetUnitX(dat.u) -40, GetUnitY(dat.u),-100)
// changed by MoCo for healin
if dat.damage > 0 then
// if dat.damage != 0 then
if dat.hp > (dat.damage * dat.f) then
set dat.hp = dat.hp - (dat.damage * dat.f)
call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.damage)
else
call SetWidgetLife( dat.u,GetWidgetLife(dat.u) + dat.hp)
set dat.hp = 0
endif
set dat.damage = 0
endif
call UnitRemoveAbility(dat.u,lifeabi)
if dat.hp <= 0 and dat.kill == true then
call DestroyShield(dat.u)
set i = i - 1
endif
set i = i + 1
endloop
set s = null
endfunction
private function attack takes nothing returns nothing
local shield dat = LoadInteger(h,GetHandleId(GetTriggerUnit()),0)
local timer t
if dat != 0 then
if dat.hp > 0 then
if GetEventDamage() > 0 then// add by MoCo
set dat.damage = dat.damage + GetEventDamage()
endif
endif
call TimerStart(dat.time,dat.r,false,null)
endif
endfunction
function AddShield takes unit towhich, real hp, real RegPerSec, real TimeTillReg, real dmgfactor, string colorcode, boolean destroy, boolean ShowBar, real Duration, string sfx returns nothing
local shield dat
if LoadInteger(h,GetHandleId(towhich),0) != 0 then
call DestroyShield(towhich)
endif
set dat = shield.create()
set dat.u = towhich
set dat.fullhp = hp
set dat.hp = hp
set dat.reg = RegPerSec / 100
set dat.f = dmgfactor
set dat.code = colorcode
set dat.r = TimeTillReg
set dat.kill = destroy
set dat.time = CreateTimer()
set dat.t = CreateTextTag()
set dat.show = ShowBar
set dat.fx = AddSpecialEffectTarget(sfx, dat.u, AtPoint)
set dat.remain = Duration
if dat.remain == 0 then
set dat.remain = -100
endif
call SetTextTagVisibility(dat.t,ShowBar)
set dat.i = total
if not IsUnitInGroup(dat.u,g) then
call GroupAddUnit(g,dat.u)
call TriggerRegisterUnitEvent( trg, towhich, EVENT_UNIT_DAMAGED )
endif
set units[total] = dat.u
set total = total + 1
call SaveInteger(h,GetHandleId(dat.u),0,dat)
if total == 1 then
call TimerStart(tim,interval,true,function regeneration)
endif
endfunction
private function kill takes nothing returns nothing
call DestroyShield(GetTriggerUnit())
endfunction
function ShowShield takes unit u, boolean flag returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.show = flag
call SetTextTagVisibility(dat.t,flag)
endif
endfunction
function GetShieldHpPercent takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.hp / dat.fullhp * 100.0
endif
return .0
endfunction
function GetShieldHp takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.hp
endif
return .0
endfunction
function GetShieldMaxHp takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.fullhp
endif
return .0
endfunction
function GetShieldReg takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.reg*100
endif
return .0
endfunction
function GetShieldTimeTillReg takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.r
endif
return .0
endfunction
function GetShieldDamageFactor takes unit u returns real
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
return dat.f
endif
return .0
endfunction
function SetShieldHpPercent takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.hp = dat.fullhp * new
if dat.fullhp < dat.hp then
set dat.hp = dat.fullhp
endif
endif
endfunction
function SetShieldHp takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.hp = new
if dat.fullhp < dat.hp then
set dat.hp = dat.fullhp
endif
endif
endfunction
function SetShieldMaxHp takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.fullhp = new
if dat.fullhp < dat.hp then
set dat.hp = dat.fullhp
endif
endif
endfunction
function SetShieldReg takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.reg = new/100
endif
endfunction
function SetShieldTimeTillReg takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.r = new
call TimerStart(dat.time,dat.r,false,null)
endif
endfunction
function SetShieldDamageFactor takes unit u, real new returns nothing
local shield dat = LoadInteger(h,GetHandleId(u),0)
if dat != 0 then
set dat.f = new
endif
endfunction
private function Init takes nothing returns nothing
// local trigger tt = CreateTrigger()
// call TriggerAddAction(tt, function kill)
// call TriggerRegisterAnyUnitEventBJ( tt, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction(trg, function attack)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library HandleTable initializer Init requires Table
// ====================================================================
//
// HandleTable by MoCo v1.0
//
// A simple toolset for storing an integer data field for handles
//
// ====================================================================
// Saves an integer for a handle
function SetHandleData takes handle h, integer data returns nothing
set HandleIdTable[ GetHandleId(h) ] = data
endfunction
// Retrieves integer for handle
function GetHandleData takes handle h returns integer
return HandleIdTable[ GetHandleId(h) ]
endfunction
// Releases the data
function ReleaseHandleData takes handle h returns nothing
call HandleIdTable.remove( GetHandleId( h ) )
endfunction
private function Init takes nothing returns nothing
set HandleIdTable = Table.create()
endfunction
endlibrary
//TESH.scrollpos=87
//TESH.alwaysfold=0
library SpellUtils initializer Init requires TimerUtils, EffectUtils, Table
// ====================================================================
//
// SpellUtils by MoCo v0.8
//
// A simple and easy to use toolset for spell structs handling.
//
// ====================================================================
globals
private constant integer SPELL_WARNING = 48
private constant integer SPELL_MAX = 128
Spell array spells[1]
private integer spell_count = 0
endglobals
struct Spell
unit caster = null
unit target = null
timer t = null
real x = 0
real y = 0
real damage = 0.0
boolean isCrit = false
real health = 0.0
real mana = 0.0
real armor = 0.0
real speed = 0.0
integer ticks = 0
integer effect_id = 0
trigger trg = null
integer name_id = 0
integer playerId = 0
method destroy takes nothing returns nothing
set this.caster = null
set this.target = null
if this.t != null then
call ReleaseTimer(this.t)
set this.t = null
endif
if this.trg != null then
call DestroyTrigger(this.trg)
set this.trg = null
endif
call this.deallocate()
endmethod
endstruct
function GetSpellCaster takes integer id returns unit
return spells[id].caster
endfunction
function GetSpellTarget takes integer id returns unit
return spells[id].target
endfunction
function GetSpellDamage takes integer id returns real
return spells[id].damage
endfunction
function GetSpellX takes integer id returns real
return spells[id].x
endfunction
function GetSpellY takes integer id returns real
return spells[id].y
endfunction
function GetSpellCrit takes integer id returns boolean
return spells[id].isCrit
endfunction
function GetSpellTicks takes integer id returns integer
return spells[id].ticks
endfunction
function GetSpellEffectId takes integer id returns integer
return spells[id].effect_id
endfunction
function GetSpell takes integer id returns Spell
return spells[id]
endfunction
function IncSpellTicks takes integer id returns nothing
set spells[id].ticks = spells[id].ticks + 1
endfunction
function SetSpellTicks takes integer id, integer ticks returns nothing
set spells[id].ticks = ticks
endfunction
function SetSpellEffectId takes integer id, integer effect_id returns nothing
set spells[id].effect_id = effect_id
endfunction
function ReleaseSpell takes integer spell_id returns nothing
local Spell spell = spell_id
if spell_id == 0 then
debug call BJDebugMsg("Error: Trying to release a NULL spell!")
else
call spell.destroy()
set spell_count = spell_count - 1
endif
endfunction
function RegisterSpell takes unit caster, unit target, real x, real y, real damage, boolean crit, real health, real mana, real armor, real speed, integer ticks, integer effect_id, integer name_id returns integer
local Spell thisSpell = Spell.create()
local integer spell_id = thisSpell
set spell_count = spell_count + 1
set thisSpell.caster = caster
set thisSpell.target = target
set thisSpell.x = x
set thisSpell.y = y
set thisSpell.damage = damage
set thisSpell.isCrit = crit
set thisSpell.health = health
set thisSpell.mana = mana
set thisSpell.armor = armor
set thisSpell.speed = speed
set thisSpell.ticks = ticks
set thisSpell.effect_id = effect_id
set thisSpell.name_id = name_id
// debug call BJDebugMsg("|cffBD57DFSpell|r reg. ID#"+I2S(spell_id))
set spells[spell_id] = thisSpell
if spell_id > SPELL_WARNING then
debug call BJDebugMsg("Warning: |cffBD57DFspells count|r higher than "+I2S(SPELL_WARNING)+" there might be unrecycled spells!")
endif
return spell_id
endfunction
private function TestConditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function TestReleaseActions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer i = S2I(SubString( GetEventPlayerChatString(), 2, 1 ))
call ReleaseSpell(i)
endfunction
private function TestRegisterActions takes nothing returns nothing
call RegisterSpell(null, null, 0, 0, 30, false, 0,0,0,0,0,1,0)
endfunction
private function ShowArray takes nothing returns nothing
local integer i = 0
local integer count = 0
debug call BJDebugMsg("|cffBD57DFSpell|r array:")
loop
exitwhen i > 8 // SPELL_WARNING
debug call BJDebugMsg("spells["+I2S(i)+"] = "+I2S(spells[i]) + " " + I2S(spells[i].name_id))
if spells[i] > 0 then
set count = count + 1
endif
set i = i + 1
endloop
debug call BJDebugMsg("|cffBD57DFSpells:|r "+I2S(count))
endfunction
private function ShowSpellCount takes nothing returns nothing
local integer i = 0
local integer count = 0
loop
exitwhen i > SPELL_WARNING // spells[i] == 0
if spells[i] > 0 then
set count = count + 1
endif
set i = i + 1
endloop
debug call BJDebugMsg("|cffBD57DFSpells:|r "+I2S(count))
endfunction
private function Init takes nothing returns nothing
local trigger trg
// set SpellTab = Table.create()
set trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "cs", false )
call TriggerAddCondition( trg, Condition( function TestConditions ) )
call TriggerAddAction( trg, function TestRegisterActions )
set trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "rs", false )
call TriggerAddCondition( trg, Condition( function TestConditions ) )
call TriggerAddAction( trg, function TestReleaseActions )
set trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "res", false )
call TriggerAddCondition( trg, Condition( function TestConditions ) )
call TriggerAddAction( trg, function ShowArray )
set trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "ss", false )
call TriggerAddCondition( trg, Condition( function TestConditions ) )
call TriggerAddAction( trg, function ShowSpellCount )
set trg = null
endfunction
endlibrary
//TESH.scrollpos=6
//TESH.alwaysfold=0
library EffectUtils initializer Init requires TimerUtils
// ====================================================================
//
// EffectUtils by MoCo
//
// A simple and easy to use toolset for timed effects.
//
// use RegisterEffect(yourEffect, lifeTime)
// - After the lifeTime runs out, the effect is automatically destroyed and recycled.
// - The RegisterEffect functions returns a unique effect id so you can access the effect during its lifeTime.
// - A Lifetime of 0 makes the effect permanent, so you should manually recycle it via ReleaseEffect(effect_id) later.
//
// use ReleaseEffect(effect id) to destroy and recycle a registered effect
// - You should always use this function to recycle permanent effects when you do not need them anymore.
// - You can as well use the function for timed effects to destroy them before the end of their lifeTime.
//
// use EFFECT_MAX to define the limit of simultanously active effects allowed
// - Effects are getting automatically recycled if the limit is exceeded.
// - A lower value means faster auto-recycling of permanent effects.
//
// ====================================================================
// Examples:
//
// (1)
//
// local effect e = AddSpecialEffect("myEffect", x, y)
// call RegisterEffect(e, lifeTime)
//
// (2)
//
// local integer effectId
// local effect e = AddSpecialEffectTarget("myEffect", u, "origin")
// set effectId = RegisterEffect(e, 0)
// ...
// call ReleaseEffect(effectId)
//
// ====================================================================
globals
private constant integer EFFECT_MAX = 256
private integer e_pointer = 0
private effect array effects[1]
endglobals
function ReleaseEffect takes integer id returns nothing
if effects[id] != null then
call DestroyEffect(effects[id])
set effects[id] = null
endif
endfunction
private function TimedEffectFinished takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
call ReleaseTimer(t)
set t = null
call ReleaseEffect(id)
endfunction
// Effects with timed life are automatically destroyed
function RegisterEffect takes effect e, real lifespan returns integer
local timer t
local integer id = e_pointer
// If an old effect hasn't cleaned up -> destroy
if effects[id] != null then
call DestroyEffect(effects[id])
debug call BJDebugMsg("An effect hasn't been properly released!")
endif
// Store Effect and inc ID
set effects[id] = e
if e_pointer < EFFECT_MAX - 1 then
set e_pointer = e_pointer + 1
else
set e_pointer = 0
endif
// Timed life?
if lifespan > 0 then
set t = NewTimer()
call SetTimerData(t, id)
call TimerStart(t, lifespan, false, function TimedEffectFinished)
endif
set t = null
return id
endfunction
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen i > (EFFECT_MAX-1)
set effects[i] = null
set i = i + 1
endloop
endfunction
endlibrary
//TESH.scrollpos=11
//TESH.alwaysfold=0
library IsUnitInSight requires Math
function IsUnitBehind takes unit attacker, unit target returns boolean
local real face = GetUnitFacing(target)
local real rangle = bj_RADTODEG*Atan2(GetUnitY(attacker)-GetUnitY(target),GetUnitX(attacker)-GetUnitX(target))
// debug call BJDebugMsg( "T Facing: " + R2S(face) + " Rangle: " + R2S(rangle) + " Rabs(face-rangle)+ " + R2S(RAbs(face-rangle)) + " Rabs(face-angle-360): "+R2S(RAbs(face-rangle-360)) )
return RAbs(face-rangle) > BACKSTAB_ANGLE and RAbs(face-rangle-360) > BACKSTAB_ANGLE
endfunction
function IsUnitInSightOfUnit takes unit observer, unit target, real fov returns boolean
local real face = GetUnitFacing(observer)
local real angle = bj_RADTODEG*Atan2(GetUnitY(observer)-GetUnitY(target), GetUnitX(observer)-GetUnitX(target))
local real r1 = face-angle
local real r2 = r1-360
// we do not want to use the RabsBJ function so we do a manual conversion here
if r1 < 0 then
set r1 = -r1
endif
if r2 < 0 then
set r2 = -r2
endif
return r1 > FIELD_OF_VIEW and r2 > FIELD_OF_VIEW
endfunction
function IsUnitInSight takes unit observer, unit target returns boolean
local real face = GetUnitFacing(observer)
local real angle = bj_RADTODEG*Atan2(GetUnitY(observer)-GetUnitY(target), GetUnitX(observer)-GetUnitX(target))
local real r1 = face-angle
local real r2 = r1-360
if r1 < 0 then
set r1 = -r1
endif
if r2 < 0 then
set r2 = -r2
endif
return r1 > FIELD_OF_VIEW and r2 > FIELD_OF_VIEW
endfunction
endlibrary
//TESH.scrollpos=93
//TESH.alwaysfold=0
library CastBar requires TimerUtils
/**************************************************************
*
* CastBar v1.0.0 A a simplified version of TriggerHappy's ProgressBar by MoCo
*
* This library allows you to easily use cast bars.
* Technically, it works by creating a dummy unit with a special model and changing
* the animation speed to increase or reduce the bar speed.
*
* Just create a new CastBar struct, set it up as you like and assign the target unit once (the bar is displayed over this unit).
* Then just start the cast bar by calling bar.startCastBar(real duration) and the bar fills over the duration.
* After the bar has done it's job, it's automatically hidden.
*
*
* Options:
* x - set X coordinate
* y - set Y coordinate
* xOffset - offset of the target unit, if any.
* yOffset - offset of the target unit, if any.
* zOffset - how high the bar is from the ground.
* color - allows you to tint the bar or add transparency
* target - pick which unit the bar should hover over
* size - set model scale
*
* Usage:
* local CastBar bar = CastBar.create()
* set bar.zOffset = 150
* set bar.color = PLAYER_COLOR_RED
* set bar.targetUnit = CreateUnit(Player(0), 'hfoo', 0, 0, 0)
*
* call bar.startCastBar(real duration)
*
* Installation:
* 1. Copy the dummy unit over to your map
* 2. Change the DUMMY constant to fit the Raw code of the dummy.
* 3. Copy this and all required libraries over to your map.
*
* Thanks to JesusHipster for the Progress Bar models
* and to Vexorian for TimerUtils
*
**************************************************************/
globals
private constant integer PROGRESS_BAR_DUMMY = 'e001' // the default one
private constant player PROGRESS_BAR_OWNER = Player(PLAYER_NEUTRAL_PASSIVE) // owner of the dummy
endglobals
struct CastBar
unit bar
unit target
real xOffset = 0
real yOffset = 0
boolean active = false
timer t = null
method operator x= takes real x returns nothing
call SetUnitX(this.bar, x)
endmethod
method operator x takes nothing returns real
return GetUnitX(this.bar)
endmethod
method operator y= takes real y returns nothing
call SetUnitY(this.bar, y)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.bar)
endmethod
method operator zOffset= takes real offset returns nothing
call SetUnitFlyHeight(this.bar, offset, 0)
endmethod
method operator zOffset takes nothing returns real
return GetUnitFlyHeight(this.bar)
endmethod
method operator size= takes real size returns nothing
call SetUnitScale(this.bar, size, size, size)
endmethod
method operator color= takes playercolor color returns nothing
call SetUnitColor(this.bar, color)
endmethod
method show takes boolean flag returns nothing
call UnitRemoveAbility(this.bar, 'Aloc')
call ShowUnit(this.bar, flag)
call UnitAddAbility(this.bar, 'Aloc')
endmethod
method RGB takes integer red, integer green, integer blue, integer alpha returns nothing
call SetUnitVertexColor(this.bar, red, green, blue, alpha)
endmethod
method destroy takes nothing returns nothing
if this.bar != null then
call RemoveUnit(this.bar)
endif
set this.bar = null
set this.target = null
set this.xOffset = 0
set this.yOffset = 0
set this.active = false
if (this.t != null) then
call ReleaseTimer(this.t)
set this.t = null
endif
// call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.bar = CreateUnit(PROGRESS_BAR_OWNER, PROGRESS_BAR_DUMMY, 0, 0, 0)
call SetUnitAnimationByIndex(this.bar, 1)
call SetUnitTimeScale(this.bar, 0)
return this
endmethod
private static method releaseBar takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call ReleaseTimer(GetExpiredTimer())
set this.t = null
set this.active = false
call this.show(false)
endmethod
method startCastBar takes real duration returns nothing
local real timeScale = 1.0 / duration
if (this.target != null) and not this.active then
set this.active = true
set this.t = NewTimer()
call SetTimerData(this.t, this)
call TimerStart(this.t, duration, false, function thistype.releaseBar)
call SetUnitX(this.bar, GetUnitX(this.target) - xOffset)
call SetUnitY(this.bar, GetUnitY(this.target) - yOffset)
call this.show(true)
call SetUnitAnimationByIndex(this.bar, 1)
call SetUnitTimeScale(this.bar, timeScale)
endif
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library IsSomethingInBetween requires PathingType
globals
private constant integer STEPS = 12 // A lower value means better performance but lower accuracy
// Should be set depending on the distances needed
endglobals
function WallInBetween takes real uX, real uY, real tX, real tY returns boolean
local real IncX = (tX-uX)/STEPS
local real IncY = (tY-uY)/STEPS
local real x = uX
local real y = uY
local integer i = 0
local boolean wallCheck = false
loop
exitwhen i > STEPS or wallCheck
if IsTerrainWalkable(x,y) == false then
set wallCheck = true
endif
set x = x + IncX
set y = y + IncY
set i = i + 1
endloop
return wallCheck
endfunction
endlibrary
//TESH.scrollpos=36
//TESH.alwaysfold=0
library SaveInventory initializer Init
globals
constant integer SAFE_SYSTEM_SAFE = 'h007'
private constant real SAFE_SPOT_X = -7360
private constant real SAFE_SPOT_Y = -7647
private unit array Safes[1]
private boolean array SafesFilled[1]
endglobals
function SaveInventory takes unit hero returns nothing
local integer slot = 0
local item thisItem
local integer playerId = GetPlayerId(GetOwningPlayer(hero))
if SafesFilled[playerId] then
debug call BJDebugMsg("SaveInventory System Error: two inventories saved for one player at a time!")
else
set SafesFilled[playerId] = true
// save items in hero inventory
loop
exitwhen slot > 5
set thisItem = UnitItemInSlot(hero, slot)
if thisItem != null then
call UnitRemoveItem(hero, thisItem)
call UnitAddItem(Safes[playerId], thisItem)
endif
set slot = slot + 1
endloop
endif
set thisItem = null
endfunction
function LoadInventory takes unit hero returns nothing
local integer slot = 0
local item thisItem
local integer playerId = GetPlayerId(GetOwningPlayer(hero))
if SafesFilled[playerId] then
loop
exitwhen slot > 5
set thisItem = UnitItemInSlot(Safes[playerId], slot)
if thisItem != null then
call UnitRemoveItem(Safes[playerId], thisItem)
call UnitAddItem(hero, thisItem)
endif
set slot = slot + 1
endloop
set SafesFilled[playerId] = false
else
debug call BJDebugMsg("SaveInventory System Error: Unable to load saved inventory!")
endif
set thisItem = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local integer i = 0
loop
exitwhen i > 11
set Safes[i] = CreateUnit(Player(i), SAFE_SYSTEM_SAFE, SAFE_SPOT_X, SAFE_SPOT_Y, bj_UNIT_FACING)
set SafesFilled[i] = false
set i = i + 1
endloop
// debug call BJDebugMsg("SaveInventory System initialized!")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
globals
// Map information
constant string TITLE = "|cff9577F8THE SHADOW OVER BLACKWOOD"
constant string VERSION = "1.01"
constant string VERSION_TEXT = "|cffFFB06Av"+VERSION+" (BETA)|r"
constant string AUTHOR = "|cff616161by MoCo|r"
constant string SCORE_TITLE = "|c009999ffS|c009693ffh|c00938effa|c009189ffd|c008e84ffo|c008c7fffw |c008775ffo|c008470ffv|c00826bffe|c007f66ffr |c007a5bffB|c007756ffl|c007551ffa|c00724cffc|c007047ffk|c006d42ffw|c006b3dffo|c006838ffo|c006633ffd|r "+VERSION_TEXT
constant boolean SCREENSHOT_MODE = false // only affects DEBUG
// Debugging options
constant boolean FULL_VISION = false // default: false
constant boolean NO_SHOUTS = false // default: false
constant boolean STATE_TESTER = false // default: false
constant boolean SHOW_WAYPOINTS = false // default: false
constant boolean MAX_GUARDS = false // default: false | If set to true, the map uses all available guards (default: false)
constant boolean FORCE_TEST_SPAWN = false // default: false
constant integer TEST_SPAWN = 2
constant integer START_SKILL_POINTS = 1
// Time scale
constant real TIME_SCALE = 0.10 // 1 game hour is 20 real time seconds by default;
// a game goes from 21:00 til 6:00 = 9 game hours = 180 real time seconds (3 minutes).
// We want about 30 minutes, so let's use a scale of 0.10
// Game preferences
constant real CAMERA_ZOFFSET = 200 // Z offset of game camera (TDMS: -130)
constant real CAMERA_ANGLE_OF_ATTACK = 290 // normal game cam: 304 (TDMS: 296)
// Tags
constant string DEBUG = "|cffEA34DFDebug-Info:|r "
constant string INFO = "|cffFFC786Info:|r "
constant string EVENT = "|cffF7A647Game Info:|r "
constant string HINT = "|cff34A3EAHint:|r "
constant string GET_READY = "|cffFE2A2AGet Ready!|r "
constant string ERROR = "|cffF63B3BError:|r "
constant string SHADOW_C1 = "|cff726BB1Voice from the Shadows:|r"
constant string SOUL_STRING = "|cffC2A0F6+1 soul|r"
constant string RELOAD_STRING = "|cffFFE2AAreloading..|r"
constant string BAR_COLOR_DARK = "2B2B2B"
constant string BAR_COLOR_BLUE = "3091FF"
constant string PROBLEM_COLOR = "D45151"
constant string WARNING_COLOR = "FFD98F"
constant real TAG_SIZE = 0.02 // // 0.0184
constant real CRIT_TAG_SIZE = 0.03
constant integer HOLD_POSITION = 851993
constant integer PLAYER_VAMPIRES_START_ID = 0 // First vampire player slot
constant integer PLAYER_VAMPIRES_END_ID = 5 // Last vampire player slot
constant integer PLAYER_HUNTERS_START_ID = 6 // First hunter player slot
constant integer PLAYER_HUNTERS_END_ID = 8 // Last hunter player slot
// constant integer VAMPIRE_BOUNTY = 150
constant real VAMPIRE_RESPAWN_TIME = 20 // Vampires spawn pretty fast
constant real HUNTER_RESPAWN_TIME = 20 // Hunters as well
constant real FAST_TRANSFORM_FACTOR = 0.65 // Time factor for fast transform ability
constant integer VAMPIRE_OVERLORD_LEVEL = 8 // Level at which overlord form is given
constant real VAMPIRE_LEVEL_SIZE_SCALE_INC = 0.04 // Vampires grow slightly bigger in size with higher levels
// Vampire UnitType IDs
constant integer VAMPIRE = 'U000'
constant integer RAT = 'U002'
constant integer WOLF = 'U001'
constant integer BAT = 'U003'
constant integer GHOST = 'U005'
constant integer OVERLORD = 'U006'
constant integer VAMPIRE_VILLAGER = 'U005'
constant integer SPAWN = 'u004'
constant integer ZOMBIE = 'n00I'
constant integer GHOST_MERCHANT = 'u008'
// Townsfolk and hunters
constant integer VILLAGER1 = 'n00J'
constant integer VILLAGER2 = 'n00K'
constant integer VILLAGER3 = 'n00L'
constant integer GUARD = 'n000'
constant integer ARCHER = 'e000'
constant integer ARCHER_TOWER = 'e002'
constant integer PRIEST = 'n001'
constant integer INQUISITOR = 'h000'
constant integer GUNSLINGER = 'H002'
constant integer ASSASSIN = 'H003'
constant integer MAGE = 'H004'
constant integer FIRE_MAGE = 'H008'
constant integer FROST_MAGE = 'H009'
constant integer CITY_RAT = 'n002'
// Animals
constant integer RABBIT = 'necr'
constant integer CHICKEN = 'nech'
constant integer RACOON = 'nrac'
constant integer PIG = 'npig'
constant integer SHEEP = 'nshe'
constant integer DEER = 'nder'
constant integer WILD_WOLF = 'n008'
constant integer GIANT_WOLF = 'n00G'
constant integer BEAR = 'n007'
// Animal spawn chances
constant real RABBIT_WEIGHT = 1.00
constant real RACOON_WEIGHT = 1.00
constant real DEER_WEIGHT = 0.30
constant real WOLF_WEIGHT = 0.25
constant real BEAR_WEIGHT = 0.05
constant real BOUNTY_AREA = 250
constant integer BOUNTY_VAMPIRE = 500 // Base bounty given for vampire kill
constant integer BOUNTY_VAMPIRE_LEVEL_BONUS = 25 // Level bonus
constant integer BOUNTY_SPAWN = 100
constant integer BOUNTY_ZOMBIE = 30
constant integer CRATE_GOLD = 100
constant integer HUNTER_START_GOLD = 150
constant real FIELD_OF_VIEW = 115.00 // Real FoV is: 180 - 2x (FIELD_OF_VIEW-90)
constant real BACKSTAB_ANGLE = 120.00
constant real VILLAGER_SIGHT_RANGE = 480.00 // 420
constant real START_TALKING_RANGE = 110.00
constant real GUARD_GIVEUP_CHASING_RANGE = 600.00
constant real GUARD_ALERT_RANGE = 512.00
constant real GUARD_RAT_SMASH_RANGE = 100.00
constant real BAR_Z_OFFSET = 150
constant real BAR_TAG_Z_OFFSET = 170
constant integer MAX_BLOOD = 100
constant integer MAX_BLOOD_VILLAGER = 100
constant integer MAX_BLOOD_DEER = 100
constant integer MAX_BLOOD_RABBIT = 30
constant integer MAX_BLOOD_CHICKEN = 30
constant integer MAX_BLOOD_RACOON = 40
constant integer MAX_BLOOD_PIG = 60
constant integer MAX_BLOOD_SHEEP = 50
constant integer BLOOD_SUCK_DRAIN_AMOUNT = 5
constant integer SUCK_BLOOD_XP_GAIN = 10
constant real BLOOD_SUCK_LIFE_FACTOR = 0.048
constant integer SUCKED_TO_DEATH_BLOOD = 15
constant integer MAX_SHOTS_GUNSLINGER = 12
constant integer MAX_SHOTS_ASSASSIN = 1
constant real BASE_RELOAD_TIME_GUNSLINGER = 2.5
constant real FAST_RELOAD_1_GUNSLINGER = 2.0
constant real FAST_RELOAD_2_GUNSLINGER = 1.5
constant real FAST_RELOAD_3_GUNSLINGER = 1.0
constant real FAST_RELOAD_4_GUNSLINGER = 0.5
constant real BASE_RELOAD_TIME_ASSASSIN = 1.25
constant real INVESTIGATION_AREA = 64
constant integer INVESTIGATION_TICKS = 5
constant integer MAX_CIVILIANS = 30
constant integer START_CIVILIANS = 30 // How many villagers to spawn at game start
constant real GUARD_STAYPUT_COUNT_FACTOR = 0.6 // Percentage of all pre-placed guards to use in the game
constant integer MAX_PATROL_GUARDS_COUNT = 30 // Number of guards patrolling on the streets
constant real ESCORT_CHANCE = 25 // chance that a patrolling guard is escorted by another guard
constant real PARK_VISIT_CHANCE = 20 //
constant real TORCH_CHANCE = 30 // Generic chance that a WP user has a torch
constant real CITY_VILLAGER_USES_WP_CHANCE = 40 // Chance that a city spawned villager uses Waypoints instead of just wandering
constant real SPAWN_WEIGHT_CITY = 0.70
constant real SPAWN_WEIGHT_FOREST_NORTH = 0.30
constant real SPAWN_WEIGHT_FOREST_SOUTH = 0.20
constant real SPAWN_WEIGHT_FOREST_WEST = 0.25
constant real CRATE_USE_FACTOR = 0.5
constant real WINE_USE_FACTOR = 0.5
constant real ANIMAL_AREA_1_WEIGHT = 1.05
constant real ANIMAL_AREA_2_WEIGHT = 0.90
constant real ANIMAL_AREA_3_WEIGHT = 1.00
constant real ANIMAL_AREA_4_WEIGHT = 1.00
constant real ANIMAL_AREA_5_WEIGHT = 0.20
constant real ANIMAL_MAX_COUNT = 30
constant real SPIDER_COUNT = 30
constant real VAMPIRE_TRACKER_INTERVAL = 5.0
constant real VAMPIRE_TRACKER_DISTANCE = 3200. // 4096.
constant real SIXTH_SENSE_INTERVAL = 3.0
constant real SIXTH_SENSE_DISTANCE = 1500
constant integer LOOKOUT_START_TICKS_MIN = 15 // Min. ticks elapsed in state before starting wondering
constant integer LOOKOUT_START_TICKS_MAX = 50 // Max. ticks elapsed in state before starting wondering
constant integer LOOKOUT_TICKS_MIN = 4 // End of lookout state min ticks
constant integer LOOKOUT_TICKS_MAX = 12 // End of lookout state max ticks
constant integer LOOKOUT_INVESTIGATE_TICKS_MIN = 8 // End of lookout state (investigation) min ticks
constant integer LOOKOUT_INVESTIGATE_TICKS_MAX = 14 // End of lookout state (investigation) max ticks
constant integer LOOKOUT_TIME_TICKS_MIN = 4 // 1 sec Min. ticks after a new lookout action is performed
constant integer LOOKOUT_TIME_TICKS_MAX = 8 // 2.5 sec Max. ticks after a new lookout action is performed
constant real WONDERING_REFRESH = 1.5
constant integer INVESTIGATION_TICKS_MIN = 5
constant integer INVESTIGATION_TICKS_MAX = 10
constant integer TRANSFORMATION_TICKS_MIN = 15
constant integer TRANSFORMATION_TICKS_MAX = 60
constant real AI_REFRESH_INTERVAL = 0.5
constant real STATE_TESTER_REFRESH = 1.0
constant real SHOUT_PERIOD = 1.2
constant real TALKING_PERIOD = 1.2
constant real TALKING_CHANCE = 50
constant integer TALKING_COUNT_MIN = 7
constant integer TALKING_COUNT_MAX = 15
constant integer CALMING_DOWN_TICKS = 14 // After villagers were set in panic
constant integer CALMING_DOWN_TICKS_GUARD = 10 // After a guard was chasing a monster
constant integer MAX_CHASING_TICKS = 50
constant integer SHADOW_PLAYER_ID = 9
constant real CIVILIAN_MOVE_SPEED_NORMAL = 50
constant real CIVILIAN_MOVE_SPEED_PANIC = 290
constant real GUARD_MOVE_SPEED_PATROL = 70
constant real GUARD_MOVE_SPEED_NORMAL = 240
constant real VILLAGER_MOVE_SPEED_FEAR = 250
constant real INQUISITOR_MOVE_SPEED = 350
// AI states
constant integer VILLAGER_STATE_UNDEFINED = 0
constant integer VILLAGER_STATE_DEFAULT = 1
constant integer VILLAGER_STATE_STAND = 2
constant integer VILLAGER_STATE_WANDERING = 3
constant integer VILLAGER_STATE_TALKING = 4
constant integer VILLAGER_STATE_PANIC = 5
constant integer VILLAGER_STATE_LOOKOUT = 6
constant integer VILLAGER_STATE_ON_WAYPOINTS = 7
constant integer VILLAGER_STATE_PARALYZED = 8
constant integer VILLAGER_STATE_TRANSFORMING = 9
constant integer VILLAGER_STATE_SLEEP = 10
constant integer VILLAGER_STATE_FEAR = 11
constant integer VILLAGER_STATE_WORK = 12
constant integer VILLAGER_STATE_DEAD = 13
// Guard state
constant integer VILLAGER_STATE_GUARD_HOLDGROUND = 14
constant integer VILLAGER_STATE_GUARD_PATROL = 15
constant integer VILLAGER_STATE_GUARD_ESCORT = 16
constant integer VILLAGER_STATE_GUARD_INVESTIGATE = 17
constant integer VILLAGER_STATE_GUARD_ATTACK = 18
constant real GENERIC_AOE_RANGE = 400.00
constant real GENERIC_DOT_INTERVAL = 1.0
constant integer ODER_STOP = 851972
constant real HOME_PUFFER = 32
constant real SEEN_PUFFER = 32
constant real FACING_BUFFER = 1.
constant integer ORDER_ATTACK = 851983
intpool AnimalAreaPool
rect array AnimalAreas[1]
integer array IngredientInfoAbilities[1]
// Strings
// ==================================================================================
// String arrays
string array SPELL_NAMES[1]
string array StateNames[1]
// Villager colors (for comments etc)
string array VillagerColors[1]
integer VillagerColorCount = 0
// PlayerColors
string array PlayerColors[1]
string array PlayerNames[1]
// Civilian panic souhts (vampire)
string array PanicShouts[1]
integer PanicShoutsCount = 0
// Civilian panic shouts (wolf)
string array PanicShoutsWolf[1]
integer PanicShoutsWolfCount = 0
// Civilian Lookout comments
string array LookoutComments[1]
integer LookoutCommentsCount = 0
// Guard reach Investigation area comments
string array InvestigationAreaComments[1]
integer InvestigationAreaCommentsCount = 0
// Guard lookout comments
string array LookoutCommentsGuards[1]
integer LookoutCommentsGuardsCount = 0
// Guard stop chasing comments
string array StopChasingComments[1]
integer StopChasingCommentsCount = 0
// WTF shouts
string array WTFShouts[1]
integer WTFShoutsCount = 0
string array RatShouts[1]
integer RatShoutsCount = 0
// Guard attack comments
string array AttackShouts[1]
integer AttackShoutsCount = 0
// Guard kills comments
string array GuardKillsComments[1]
integer GuardKillsCommentsCount = 0
// Vampire escapes comments
string array EscapeComments[1]
integer EscapeCommentsCount = 0
// Death Messages (Shadow)
string array ShadowDeathMessages[1]
integer ShadowDeathMessageCount = 0
// Revive Messages (Shadow)
string array ShadowReviveMessages[1]
integer ShadowReviveMessageCount = 0
Table HandleIdTable
integer array Waypoints[1]
rect array Homes[1]
integer HOME_COUNT = 0
unit BehindTesterAttacker
// Counters
integer VillagerCount = 0
integer CivilianCount = 0
integer GuardCount = 0
integer GuardCountPatrol = 0
integer GuardCountStayput = 0
integer AnimalCount = 0
// Debugging stuff
integer HEAVY_CALC_COUNT = 0
unit testUnit = null
unit TEST_VAMPIRE = null
// Used for core function (villager notices threat)
group targetGroup = null
force ForceHunters = null
force ForceVampires = null
integer array HeroStructIdByPlayer[1]
unit array HeroByPlayer[1]
// Score System
multiboard Score_Table = null // Don't use "= CreateMultiboard()"! here else the game will crash
integer array ScoreBoard_Positions[1]
timer GameTime
integer GameTime_Minutes
integer GameTime_Seconds
integer array Score_Kills[1]
integer array Score_PvP[1]
integer array Score_Deaths[1]
integer array Score_Levels[1]
real array Score_Damage[1]
real array Score_Healing[1]
integer ClockRow
integer VampirePlayerCount = 0
integer HunterPlayerCount = 0
integer PlayerCount = 0
timer array ReviveTimers[1]
timerdialog array ReviveTimerWindows[1]
boolean OverlordOnMap = false
integer OverlordPlayer = 0
endglobals
//TESH.scrollpos=100
//TESH.alwaysfold=0
library MapInitialization initializer Init requires TimerUtils
globals
endglobals
public function Init_Game takes nothing returns nothing
if DEBUG_MODE and FULL_VISION then
set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
call FogModifierStart(bj_lastCreatedFogModifier)
endif
set targetGroup = CreateGroup()
call EnablePreSelect( true, false )
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, 21.00 )
call SetTimeOfDayScale(TIME_SCALE)
// call SuspendTimeOfDay(true)
// Computer must see all in order for AI scripts to work properly!
set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(11), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
call FogModifierStart(bj_lastCreatedFogModifier)
// Lock Minimap
call EnableMinimapFilterButtons( false, false )
call SetAllyColorFilterState( 0 )
call SetCreepCampFilterState( false )
// Vampire spawn player
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(0), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(1), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(2), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(3), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(4), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(SHADOW_PLAYER_ID), Player(5), bj_ALLIANCE_ALLIED )
call SetPlayerAllianceStateBJ( Player(0), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
call SetPlayerAllianceStateBJ( Player(1), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
call SetPlayerAllianceStateBJ( Player(2), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
call SetPlayerAllianceStateBJ( Player(3), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
call SetPlayerAllianceStateBJ( Player(4), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
call SetPlayerAllianceStateBJ( Player(5), Player(SHADOW_PLAYER_ID), bj_ALLIANCE_ALLIED_VISION )
set AnimalAreas[0] = null
set AnimalAreas[1] = gg_rct_AnimalArea1
set AnimalAreas[2] = gg_rct_AnimalArea2
set AnimalAreas[3] = gg_rct_AnimalArea3
set AnimalAreas[4] = gg_rct_AnimalArea4
set AnimalAreas[5] = gg_rct_AnimalArea5
set AnimalAreaPool = intpool.create()
call AnimalAreaPool.addInt(1, ANIMAL_AREA_1_WEIGHT) // Animal area 1
call AnimalAreaPool.addInt(2, ANIMAL_AREA_2_WEIGHT) // Animal area 2
call AnimalAreaPool.addInt(3, ANIMAL_AREA_3_WEIGHT) // Animal area 3
call AnimalAreaPool.addInt(4, ANIMAL_AREA_4_WEIGHT) // Animal area 4
call AnimalAreaPool.addInt(5, ANIMAL_AREA_5_WEIGHT) // Animal area 5
// call RemoveAllGuardPositions( Player(11) )
endfunction
private function InitVillagerColors takes nothing returns nothing
// Villager colors
set VillagerColors[0] = "CCB9A7"
set VillagerColors[1] = "8F8880"
set VillagerColors[2] = "857361"
set VillagerColors[3] = "76706B"
set VillagerColors[4] = "928E8A"
set VillagerColors[5] = "CFBAA6"
set VillagerColors[6] = "625950"
set VillagerColors[7] = "87817B"
set VillagerColors[8] = "B79B80"
set VillagerColors[9] = "5C5853"
set VillagerColors[10] = "7A6856"
set VillagerColors[11] = "998068"
set VillagerColors[12] = "BFAF9F"
set VillagerColors[13] = "C8C1BA"
set VillagerColors[14] = "AD8F72"
set VillagerColors[15] = "E4C8AD"
set VillagerColors[16] = "DAC1A9"
set VillagerColors[17] = "969491"
set VillagerColors[18] = "C4B19F"
set VillagerColors[19] = "7D6B5A"
set VillagerColors[20] = "595550"
set VillagerColorCount = 21
// Init Colors
set PlayerColors[0] = "FF0202"
set PlayerColors[1] = "0041FF"
set PlayerColors[2] = "1BE5B8"
set PlayerColors[3] = "530080"
set PlayerColors[4] = "FFFC00"
set PlayerColors[5] = "FE890D"
set PlayerColors[6] = "1FBF00"
set PlayerColors[7] = "E45AAF"
set PlayerColors[8] = "949596"
set PlayerColors[9] = "7DBEF1"
set PlayerColors[10] = "0F6145"
set PlayerColors[11] = "4D2903"
set PlayerColors[GetPlayerId(Player(PLAYER_NEUTRAL_AGGRESSIVE))] = "DA4949"
set PlayerColors[GetPlayerId(Player(bj_PLAYER_NEUTRAL_VICTIM))] = "B6B6B6"
set PlayerColors[GetPlayerId(Player(bj_PLAYER_NEUTRAL_EXTRA))] = "B6B6B6"
set PlayerColors[GetPlayerId(Player(PLAYER_NEUTRAL_PASSIVE))] = "94D598"
// Player Names
set PlayerNames[0] = "|cff" + PlayerColors[0] + GetPlayerName(Player(0)) + "|r"
set PlayerNames[1] = "|cff" + PlayerColors[1] + GetPlayerName(Player(1)) + "|r"
set PlayerNames[2] = "|cff" + PlayerColors[2] + GetPlayerName(Player(2)) + "|r"
set PlayerNames[3] = "|cff" + PlayerColors[3] + GetPlayerName(Player(3)) + "|r"
set PlayerNames[4] = "|cff" + PlayerColors[4] + GetPlayerName(Player(4)) + "|r"
set PlayerNames[5] = "|cff" + PlayerColors[5] + GetPlayerName(Player(5)) + "|r"
set PlayerNames[6] = "|cff" + PlayerColors[6] + GetPlayerName(Player(6)) + "|r"
set PlayerNames[7] = "|cff" + PlayerColors[7] + GetPlayerName(Player(7)) + "|r"
set PlayerNames[8] = "|cff" + PlayerColors[8] + GetPlayerName(Player(8)) + "|r"
set PlayerNames[9] = "|cff" + PlayerColors[9] + GetPlayerName(Player(9)) + "|r"
set PlayerNames[10] = "|cff" + PlayerColors[10] + GetPlayerName(Player(10)) + "|r"
set PlayerNames[11] = "|cff" + PlayerColors[11] + GetPlayerName(Player(11)) + "|r"
set PlayerNames[GetPlayerId(Player(PLAYER_NEUTRAL_AGGRESSIVE))] = "|cff" + PlayerColors[10] + "NEUTRAL HOSTILE|r"
set PlayerNames[GetPlayerId(Player(PLAYER_NEUTRAL_PASSIVE))] = "|cff" + PlayerColors[11] + "NEUTRAL PASSIVE|r"
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerAddAction( trg, function Init_Game )
call TriggerExecute(trg)
set trg = CreateTrigger( )
call TriggerAddAction( trg, function InitVillagerColors )
call TriggerExecute(trg)
set trg = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope InitStrings initializer Init
private function InitSomeStrings takes nothing returns nothing
// State names
set StateNames[VILLAGER_STATE_UNDEFINED] = "undef."
set StateNames[VILLAGER_STATE_STAND] = "stand"
set StateNames[VILLAGER_STATE_WANDERING] ="wander"
set StateNames[VILLAGER_STATE_TALKING] = "talking"
set StateNames[VILLAGER_STATE_PANIC] = "panic"
set StateNames[VILLAGER_STATE_LOOKOUT] = "lookout"
set StateNames[VILLAGER_STATE_ON_WAYPOINTS] = "waypoint"
set StateNames[VILLAGER_STATE_PARALYZED] = "paralyzed"
set StateNames[VILLAGER_STATE_TRANSFORMING] = "transforming"
set StateNames[VILLAGER_STATE_WORK] = "working"
set StateNames[VILLAGER_STATE_GUARD_HOLDGROUND] = "holdground"
set StateNames[VILLAGER_STATE_GUARD_PATROL] = "patrol"
set StateNames[VILLAGER_STATE_GUARD_ESCORT] = "escort"
set StateNames[VILLAGER_STATE_GUARD_ATTACK] = "attack"
set StateNames[VILLAGER_STATE_GUARD_INVESTIGATE] = "investigate"
// Lookout comments
set LookoutComments[0] = "Did I hear something?"
set LookoutComments[1] = "This feels strange"
set LookoutComments[2] = "Something moving in the shadows?"
set LookoutComments[3] = "Someone moving?"
set LookoutComments[4] = "Hello? Is there somebody?"
set LookoutComments[5] = "This night gives me the creeps!"
set LookoutComments[6] = "Could swear I've seen someone.."
set LookoutComments[7] = "Is someone there?"
set LookoutComments[8] = "Night lasts forever.."
set LookoutComments[9] = "Is it true what they say about those vampires?"
set LookoutComments[10] = "What a frosty night!"
set LookoutComments[11] = "I'm not feeling well.."
set LookoutComments[12] = "This place scares me"
set LookoutComments[13] = "Can't get any sleep tonight"
set LookoutComments[14] = "What a dark night.."
set LookoutComments[15] = "So much guards in the city.."
set LookoutCommentsCount = 16
// Guard Lookout comments
set LookoutCommentsGuards[0] = "Did I hear something?"
set LookoutCommentsGuards[1] = "They don't pay me enough for this!"
set LookoutCommentsGuards[2] = "Something moving in the shadows?"
set LookoutCommentsGuards[3] = "Someone moving?"
set LookoutCommentsGuards[4] = "Hello? Is there anybody?"
set LookoutCommentsGuards[5] = "This night gives me the creeps!"
set LookoutCommentsGuards[6] = "Could swear I've seen something.."
set LookoutCommentsGuards[7] = "Is someone there?"
set LookoutCommentsGuards[8] = "Night lasts forever.."
set LookoutCommentsGuards[9] = "I don't believe in any vampires!"
set LookoutCommentsGuards[10] = "What a frosty night"
set LookoutCommentsGuards[11] = "I think I'm getting a cold out here"
set LookoutCommentsGuards[12] = "What I'd give for coffee right now"
set LookoutCommentsGuards[13] = "I think I'm gettin' rusty"
set LookoutCommentsGuards[14] = "What a dark night"
set LookoutCommentsGuards[15] = "I'm not afraid of any vampires!"
set LookoutCommentsGuards[16] = "Better stay away from me!"
set LookoutCommentsGuards[17] = "This job is damn boring!"
set LookoutCommentsGuards[18] = "Wish I hadn't come here at all.."
set LookoutCommentsGuards[19] = "Don't mess with me!"
set LookoutCommentsGuardsCount = 20
// Reach Investigation area comments
set InvestigationAreaComments[0] = "So.. where it is?"
set InvestigationAreaComments[1] = "Hmm.."
set InvestigationAreaComments[2] = "Anyone here?"
set InvestigationAreaComments[3] = "Something's wrong here?"
set InvestigationAreaComments[4] = "Hello? Is there anybody?"
set InvestigationAreaComments[5] = "Someone's here?!"
set InvestigationAreaComments[6] = "So where is this monster?!"
set InvestigationAreaComments[7] = "I cannot see anything.."
set InvestigationAreaComments[8] = "Must be false alarm.."
set InvestigationAreaComments[9] = "Must have some kind of hallucination.."
set InvestigationAreaComments[10] = "Nothing's here"
set InvestigationAreaComments[11] = "All clear over here"
set InvestigationAreaCommentsCount = 12
// Panic shouts
set PanicShouts[0] = "HELP!"
set PanicShouts[1] = "VAMPIRES!"
set PanicShouts[2] = "HELP ME!"
set PanicShouts[3] = "IT'S HUNTING ME!"
set PanicShouts[4] = "A VAMPIRE!"
set PanicShouts[5] = "I DON'T WANNA DIE!"
set PanicShouts[6] = "OH NOOO!"
set PanicShouts[7] = "GUARDS!"
set PanicShouts[8] = "I'M BEING HUNTED!"
set PanicShouts[9] = "THE VAMPIRES ARE COMING!"
set PanicShouts[10] = "OH GOD NO!"
set PanicShoutsCount = 11
// Panic shouts wolf
set PanicShoutsWolf[0] = "HELP!"
set PanicShoutsWolf[1] = "A WOLF!"
set PanicShoutsWolf[2] = "HELP ME!"
set PanicShoutsWolf[3] = "IT'S HUNTING ME!"
set PanicShoutsWolf[4] = "GET THE BEAST!"
set PanicShoutsWolf[5] = "I DON'T WANNA DIE!"
set PanicShoutsWolf[6] = "OH NOOO!"
set PanicShoutsWolf[7] = "GUARDS!"
set PanicShoutsWolf[8] = "I'M BEING HUNTED!"
set PanicShoutsWolf[9] = "THE WOLVES ARE COMING!"
set PanicShoutsWolf[10] = "OH GOD NO!"
set PanicShoutsWolfCount = 11
// WTF shouts
set WTFShouts[0] = "What the.. ?!"
set WTFShouts[1] = "What?!"
set WTFShouts[2] = "WTF?!"
set WTFShouts[3] = "Damn you!"
set WTFShouts[4] = "Huh?!"
set WTFShouts[5] = "...?!"
set WTFShouts[6] = "!!!"
set WTFShouts[7] = "Oh no!"
set WTFShouts[8] = "Oh my.."
set WTFShoutsCount = 9
// Rat shouts
set RatShouts[0] = "Damn rat!"
set RatShouts[1] = "A rat!"
set RatShouts[2] = "Hate those rats!"
set RatShouts[3] = "Hate those beast !"
set RatShouts[4] = "Die you dirty rat!"
set RatShouts[5] = "Those damn rats are everywhere"
set RatShouts[6] = "I squish you!"
set RatShouts[7] = "I smash you!"
set RatShoutsCount = 8
// Attack shouts
set AttackShouts[0] = "I WILL GET YOU!"
set AttackShouts[1] = "HOLD ON YOU BASTARD!"
set AttackShouts[2] = "YOU ARE DEAD!"
set AttackShouts[3] = "I WILL KILL YOU!"
set AttackShouts[4] = "IN THE NAME OF THE LORD!"
set AttackShouts[5] = "EVIL FACE MY WEAPON EVIL!"
set AttackShouts[6] = "YOU CAN RUN BUT YOU CAN'T HIDE!"
set AttackShouts[7] = "YOU ARE NO MATCH FOR ME!"
set AttackShoutsCount = 8
// Stop chasing comments
set StopChasingComments[0] = "Can't keep up any longer.."
set StopChasingComments[1] = "Seems to be gone now"
set StopChasingComments[2] = "Whatever it was - it's gone now"
set StopChasingComments[3] = "Not worth my time"
set StopChasingComments[4] = "Enough for me"
set StopChasingComments[5] = "Yeah, run away!"
set StopChasingComments[6] = "Stay away from now!"
set StopChasingComments[7] = "And don't come back!"
set StopChasingComments[8] = "I'm too old for this!"
set StopChasingCommentsCount = 9
// Stop chasing comments
set GuardKillsComments[0] = "Got ya!"
set GuardKillsComments[1] = "And stay down!"
set GuardKillsComments[2] = "Face the dirt!"
set GuardKillsComments[3] = "Got one!"
set GuardKillsComments[4] = "Terminated!"
set GuardKillsComments[5] = "One more!"
set GuardKillsComments[6] = "Die!"
set GuardKillsComments[7] = "Who's next?"
set GuardKillsComments[8] = "Don't mess with me!"
set GuardKillsComments[9] = "Die you bastard!"
set GuardKillsComments[10] = "Die monster!"
set GuardKillsCommentsCount = 11
// Vampire escapes comments
set EscapeComments[0] = "Damn! It escaped me!"
set EscapeComments[1] = "And gone.."
set EscapeComments[2] = "Damn! It get's away!"
set EscapeComments[3] = "Yeah, fly away you coward!"
set EscapeComments[4] = "I'll get you later!"
set EscapeCommentsCount = 5
// Shadow death messages
set ShadowDeathMessages[0] = "Be more careful next time!"
set ShadowDeathMessages[1] = "Revenge will be ours!"
set ShadowDeathMessages[2] = "Do not be that risky next time!"
set ShadowDeathMessages[3] = "You'll be back soon enough."
set ShadowDeathMessages[4] = "Bad luck my friend.."
set ShadowDeathMessages[5] = "While you regenerate, our enemies grow stronger!"
set ShadowDeathMessages[6] = "Bad move."
set ShadowDeathMessageCount = 7
// Shadow revive messages
set ShadowReviveMessages[0] = "You live again!"
set ShadowReviveMessages[1] = "Go and smash our enemies!"
set ShadowReviveMessages[2] = "Time for more blood my friend!"
set ShadowReviveMessages[3] = "Do not dissapoint me again!"
set ShadowReviveMessages[4] = "Time to fulfill our mission!"
set ShadowReviveMessages[5] = "Time to bring darkness!"
set ShadowReviveMessages[6] = "Our enemies fear your return!"
set ShadowReviveMessageCount = 7
call Debug_Message("Strings successfully initialized!")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerAddAction( trg, function InitSomeStrings )
call TriggerExecute(trg)
set trg = null
endfunction
endscope
//TESH.scrollpos=267
//TESH.alwaysfold=0
library BasicFunctions requires TimerUtils, Math
globals
private location TempLocation = null
endglobals
function Chance takes integer i returns boolean
if GetRandomInt(0,100) <= i then
return true
endif
return false
endfunction
function GameVictory takes integer startId, integer endId returns nothing
local integer i
set i = startId
loop
exitwhen i > endId
call CustomVictoryBJ( Player(i), true, true )
set i = i + 1
endloop
endfunction
function GameDefeat takes integer startId, integer endId returns nothing
local integer i
set i = startId
loop
exitwhen i > endId
call CustomDefeatBJ( Player(i), "TRIGSTR_2123" )
set i = i + 1
endloop
endfunction
function Blank_Message takes string text returns nothing
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, text )
endfunction
function Game_Message takes string text returns nothing
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, INFO + text )
endfunction
function Game_Message_Player takes integer player_id, string text returns nothing
call DisplayTimedTextToPlayer( Player(player_id), 0, 0, 15.00, INFO + text )
endfunction
function Hint_Message takes string text returns nothing
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 10.00, HINT + text )
endfunction
function Error_Message takes integer player_id, string text returns nothing
call DisplayTimedTextToPlayer( Player(player_id), 0, 0, 15.00, ERROR + text )
endfunction
function Problem_Message takes integer playerId, string text returns nothing
call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 15.00, "|cff"+PROBLEM_COLOR+text+"|r" )
endfunction
function Warning_Message takes integer playerId, string text returns nothing
call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 15.00, "|cff"+WARNING_COLOR+text+"|r" )
endfunction
function Debug_Message takes string text returns nothing
if DEBUG_MODE and not SCREENSHOT_MODE then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, DEBUG + text )
endif
endfunction
function Info_Message takes string text returns nothing
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, DEBUG + text )
endfunction
function Vampire_Message takes player pl, string text returns nothing
call DisplayTimedTextToPlayer( pl, 0, 0, 10.00, text )
endfunction
function IsVampire takes unit u returns boolean
return GetUnitTypeId(u) == VAMPIRE
endfunction
function CanPickupIngredients takes unit u returns boolean
return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == VAMPIRE_VILLAGER or GetUnitTypeId(u) == OVERLORD
endfunction
function IsWolf takes unit u returns boolean
return GetUnitTypeId(u) == WOLF
endfunction
function IsHuman takes unit u returns boolean
return GetPlayerRace( GetOwningPlayer(u) ) == RACE_HUMAN
endfunction
function IsCivilian takes unit u returns boolean
return GetUnitTypeId(u) == VILLAGER1 or GetUnitTypeId(u) == VILLAGER2 or GetUnitTypeId(u) == VILLAGER3
endfunction
function IsGuard takes unit u returns boolean
return GetUnitTypeId(u) == GUARD or GetUnitTypeId(u) == ARCHER or GetUnitTypeId(u) == PRIEST or GetUnitTypeId(u) == ARCHER_TOWER or GetUnitTypeId(u) == INQUISITOR
endfunction
function IsVillager takes unit u returns boolean
return ( IsGuard(u) or IsCivilian(u) )
endfunction
function IsHunter takes unit u returns boolean
return GetUnitTypeId(u) == GUNSLINGER or GetUnitTypeId(u) == ASSASSIN or GetUnitTypeId(u) == MAGE or GetUnitTypeId(u) == FROST_MAGE or GetUnitTypeId(u) == FIRE_MAGE// Frost mage etc.
endfunction
function IsUndead takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_UNDEAD)
endfunction
function IsVampiricThreat takes unit u returns boolean
return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == SPAWN or GetUnitTypeId(u) == OVERLORD
endfunction
function IsVampireAnimalForm takes unit u returns boolean
return GetUnitTypeId(u) == RAT or GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == BAT
endfunction
function IsPlayerVampiric takes unit u returns boolean
return GetUnitTypeId(u) == VAMPIRE or GetUnitTypeId(u) == RAT or GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == BAT or GetUnitTypeId(u) == OVERLORD or GetUnitTypeId(u) == VAMPIRE_VILLAGER
endfunction
function IsVampirePlayer takes unit u returns boolean
return GetPlayerRace( GetOwningPlayer(u) ) == RACE_UNDEAD
endfunction
function IsBeast takes unit u returns boolean
return GetUnitTypeId(u) == WOLF or GetUnitTypeId(u) == WILD_WOLF or GetUnitTypeId(u) == GIANT_WOLF or GetUnitTypeId(u) == BEAR
endfunction
function IsVampiricTypeId takes integer id returns boolean
return id == VAMPIRE or id == SPAWN or id == OVERLORD
endfunction
function IsBeastTypeId takes integer id returns boolean
return id == WOLF or id == WILD_WOLF or id == GIANT_WOLF or id == BEAR
endfunction
function IsThreat takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_ANCIENT)
endfunction
function ShareVision takes unit u, integer idRangeBegin, integer idRangeEnd, boolean flag returns nothing
local integer i = 0
set i = idRangeBegin
loop
exitwhen i > idRangeEnd
if i != GetPlayerId(GetOwningPlayer(u)) then
call UnitShareVision(u, Player(i), flag)
endif
set i = i + 1
endloop
endfunction
function Shadow_Message takes integer playerId, string text, boolean showAll returns nothing
if showAll then
call DisplayTimedTextToPlayer( Player(0), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
call DisplayTimedTextToPlayer( Player(1), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
call DisplayTimedTextToPlayer( Player(2), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
call DisplayTimedTextToPlayer( Player(3), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
call DisplayTimedTextToPlayer( Player(4), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
call DisplayTimedTextToPlayer( Player(5), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
else
call DisplayTimedTextToPlayer( Player(playerId), 0, 0, 10.00, SHADOW_C1+" |cffC1BAF9"+text+"|r" )
endif
endfunction
function CreateTagOnUnit takes unit TargetUnit, string Text returns nothing
local integer id = GetPlayerId(GetOwningPlayer(TargetUnit))
local texttag t = CreateTextTag()
call SetTextTagText(t, Text, 0.0184)
call SetTextTagPos(t, GetUnitX(TargetUnit), GetUnitY(TargetUnit), 0.00)
call SetTextTagVelocity(t, 0, 0.03)
call SetTextTagVisibility(t, true)
call SetTextTagFadepoint(t, 3)
call SetTextTagLifespan(t, 4)
call SetTextTagPermanent(t, false)
set t = null
endfunction
function CreateDamageTag takes unit source, unit target, string s returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.0184)
call SetTextTagColor(t, 200, 0, 30, 255)
call SetTextTagPos(t, GetUnitX(target), GetUnitY(target), 0.00)
call SetTextTagVelocity(t, 0, 0.03)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 3)
call SetTextTagLifespan(t, 4)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(source) == GetLocalPlayer() then
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
function UnitHasItemOfType takes unit whichUnit, integer itemId returns boolean
local integer index
local item indexItem = null
local boolean found = false
set index = 0
loop
set indexItem = UnitItemInSlot(whichUnit, index)
if (indexItem != null) and (GetItemTypeId(indexItem) == itemId) then
set found = true
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
set indexItem = null
return found
endfunction
function UpdateScoreBoard takes integer playerId returns nothing
local multiboarditem field
local integer row
// call Debug_Message("Update Scoreboard")
if playerId <= 8 then
set row = ScoreBoard_Positions[playerId]
// Name
set field = MultiboardGetItem(Score_Table, row, 0)
call MultiboardSetItemValue( field, " " + PlayerNames[playerId] )
// Kills
set field = MultiboardGetItem(Score_Table, row, 1)
call MultiboardSetItemValue( field, " " + I2S(Score_Kills[playerId]) )
// PvP
set field = MultiboardGetItem(Score_Table, row, 2)
call MultiboardSetItemValue( field, " " + I2S(Score_PvP[playerId]) )
// Level
set field = MultiboardGetItem(Score_Table, row, 3)
call MultiboardSetItemValue( field, " " + I2S(GetHeroLevel(HeroByPlayer[playerId])) )
// Deaths
set field = MultiboardGetItem(Score_Table, row, 4)
call MultiboardSetItemValue( field, " " + I2S(Score_Deaths[playerId]) )
endif
set field = null
endfunction
private function InitVillagerCountFields takes nothing returns nothing
local multiboarditem field = null
set field = MultiboardGetItem(Score_Table, ClockRow, 2)
call MultiboardSetItemStyle( field, true, false )
call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
call MultiboardSetItemValue( field, "0" )
set field = MultiboardGetItem(Score_Table, ClockRow, 3)
call MultiboardSetItemStyle( field, true, false )
call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
call MultiboardSetItemValue( field, "0" )
endfunction
function UpdateVillagerCount takes nothing returns nothing
local multiboarditem field = null
call Debug_Message("BLUB 1")
if (Score_Table != null) then
set field = MultiboardGetItem(Score_Table, ClockRow, 2)
call MultiboardSetItemValue( field, I2S(CivilianCount) )
set field = MultiboardGetItem(Score_Table, ClockRow, 3)
call MultiboardSetItemValue( field, I2S(GuardCount) )
endif
call Debug_Message("BLUB 2")
endfunction
private function Set_Clock takes nothing returns nothing
local multiboarditem clockfield = null
set clockfield = MultiboardGetItem(Score_Table, ClockRow, 1)
set GameTime_Minutes = ( R2I(TimerGetElapsed(GameTime)) / 60 )
set GameTime_Seconds = ModuloInteger(R2I(TimerGetElapsed(GameTime)), 60)
if GameTime_Seconds >= 10 then
call MultiboardSetItemValue( clockfield, I2S(GameTime_Minutes) + ":" + I2S(GameTime_Seconds) )
else
call MultiboardSetItemValue( clockfield, I2S(GameTime_Minutes) + ":0" + I2S(GameTime_Seconds) )
endif
set clockfield = null
endfunction
function Init_Score_Board takes nothing returns nothing
local integer i // rows
local integer j // columns
local multiboarditem field = null
local trigger trg
local timer t = GetExpiredTimer()
local integer row
call ReleaseTimer(t)
set t = null
call Debug_Message("Init Score Board..")
// Start game timeer
set GameTime = NewTimer()
call TimerStart( GameTime, 999999.00, false, null )
// Now create the Multiboard
set Score_Table = CreateMultiboard()
// Set row count
call MultiboardSetRowCount(Score_Table, 5+PlayerCount)
// Set number of columns
call MultiboardSetColumnCount(Score_Table, 5)
// Set title
call MultiboardSetTitleText(Score_Table, SCORE_TITLE)
// Display
call MultiboardDisplay(Score_Table, true)
// Adjust color and display style for all fields
set i = 0
loop
exitwhen ( i > MultiboardGetRowCount(Score_Table)-1 )
set j = 0
loop
exitwhen ( j > MultiboardGetColumnCount(Score_Table)-1 )
set field = MultiboardGetItem(Score_Table, i, j)
call MultiboardSetItemStyle( field, true, false )
call MultiboardSetItemValueColor( field, 220, 220, 220, 255 )
set j = j + 1
endloop
set i = i + 1
endloop
// Adjust column width
set i = 0
loop
exitwhen ( i > MultiboardGetRowCount(Score_Table)-1 )
// Player names
set field = MultiboardGetItem(Score_Table, i, 0)
call MultiboardSetItemWidth(field, 0.070)
// Kills
set field = MultiboardGetItem(Score_Table, i, 1)
call MultiboardSetItemWidth(field, 0.025)
// PvP
set field = MultiboardGetItem(Score_Table, i, 2)
call MultiboardSetItemWidth(field, 0.025)
// Level
set field = MultiboardGetItem(Score_Table, i, 3)
call MultiboardSetItemWidth(field, 0.02)
// Deaths
set field = MultiboardGetItem(Score_Table, i, 4)
call MultiboardSetItemWidth(field, 0.01)
set i = i + 1
endloop
// Vampire Headline
// ================
set field = MultiboardGetItem(Score_Table, 0, 0)
call MultiboardSetItemValue( field, "|cffB292DAVampires:|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, 0, 1) // Kills
call MultiboardSetItemValue( field, "|cffD60505Kills|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, 0, 2) // PvP
call MultiboardSetItemValue( field, "|cffFD986CPvP|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, 0, 3) // Level
call MultiboardSetItemValue( field, "|cffFFDD8DLv|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, 0, 4) // Death
call MultiboardSetItemStyle( field, true, true )
call MultiboardSetItemIcon(field, "ReplaceableTextures\\CommandButtons\\BTNPunisher.blp")
// Hunter Headline
// ================
set row = VampirePlayerCount+2
set field = MultiboardGetItem(Score_Table, row, 0)
call MultiboardSetItemValue( field, "|cffD7B894Hunters:|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, row, 1) // Kills
call MultiboardSetItemValue( field, "|cffD60505Kills|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, row, 2) // PvP
call MultiboardSetItemValue( field, "|cffFD986CPvP|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, row, 3) // Level
call MultiboardSetItemValue( field, "|cffFFDD8DLv|r" )
call MultiboardSetItemValueColor( field, 255, 255, 255, 255 )
set field = MultiboardGetItem(Score_Table, row, 4) // Death
call MultiboardSetItemStyle( field, true, true )
call MultiboardSetItemIcon(field, "ReplaceableTextures\\CommandButtons\\BTNPunisher.blp")
// Game Time
set ClockRow = ( PlayerCount + 4 )
set field = MultiboardGetItem(Score_Table, ClockRow, 0)
call MultiboardSetItemValueColor( field, 100, 100, 100, 255 )
call MultiboardSetItemValue( field, "Game Time:" )
set field = MultiboardGetItem(Score_Table, ClockRow, 1)
call MultiboardSetItemValueColor( field, 180, 180, 180, 255 )
call MultiboardSetItemValue( field, "0:00" )
call MultiboardDisplay( Score_Table, true )
// Update Clock
set trg = CreateTrigger()
call TriggerRegisterTimerEvent(trg, 1, true)
call TriggerAddAction(trg, function Set_Clock)
// Update for Vampire players
set i = 0
loop
exitwhen i > 5
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
call UpdateScoreBoard(i)
endif
set i = i + 1
endloop
// Update for Hunter players
set i = 6
loop
exitwhen i > 8
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
call UpdateScoreBoard(i)
endif
set i = i + 1
endloop
call InitVillagerCountFields()
call UpdateVillagerCount()
// call UpdateScoreBoard()
// set MultiBoardSetUp = true
set field = null
set trg = null
endfunction
function IncScoreKills takes integer playerId returns nothing
set Score_Kills[playerId] = Score_Kills[playerId] + 1
call UpdateScoreBoard(playerId)
endfunction
function IncScorePvP takes integer playerId returns nothing
set Score_PvP[playerId] = Score_PvP[playerId] + 1
call UpdateScoreBoard(playerId)
endfunction
function IncScoreDeaths takes integer playerId returns nothing
set Score_Deaths[playerId] = Score_Deaths[playerId] + 1
call UpdateScoreBoard(playerId)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library TemporaryVisibilityMod initializer Init requires TimerUtils
globals
endglobals
private function VisModFinished takes nothing returns nothing
local VisMod vis = GetTimerData(GetExpiredTimer())
call vis.destroy()
endfunction
struct VisMod
fogmodifier fogMod = null
timer t = null
static method create takes integer playerId, real x, real y, real radius, real duration returns thistype
local thistype this = thistype.allocate()
set this.fogMod = CreateFogModifierRadius(Player(playerId), FOG_OF_WAR_VISIBLE, x, y, radius, true, true)
set this.t = NewTimer()
call SetTimerData(t, this)
call TimerStart(this.t, duration, false, function VisModFinished)
return this
endmethod
public method destroy takes nothing returns nothing
call DestroyFogModifier(this.fogMod)
set this.fogMod = null
call ReleaseTimer(this.t)
set this.t = null
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
function CreateTimedVisibility takes integer playerId, real x, real y, real radius, real duration returns nothing
local VisMod vis = VisMod.create(playerId,x,y,radius,duration)
call Debug_Message("Temporary vision")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Camera initializer Init
private function Game_Camera_Conditions takes nothing returns boolean
return true // CutScene == false and SceneCamera == null
endfunction
private function Scene_Camera_Conditions takes nothing returns boolean
return false // CutScene and SceneCamera != null
endfunction
private function Game_Camera takes nothing returns nothing
call SetCameraField(CAMERA_FIELD_ZOFFSET, CAMERA_ZOFFSET, 0)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, CAMERA_ANGLE_OF_ATTACK, 0)
// call Debug_Message("Cam?")
endfunction
private function Scene_Camera takes nothing returns nothing
// call CameraSetupApplyForceDuration(SceneCamera, true, 0.00)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterTimerEvent(trg, 0.025, true)
call TriggerAddCondition(trg, function Game_Camera_Conditions )
call TriggerAddAction( trg, function Game_Camera )
set trg = CreateTrigger( )
call TriggerRegisterTimerEvent(trg, 0.025, true)
call TriggerAddCondition(trg, function Scene_Camera_Conditions )
call TriggerAddAction( trg, function Scene_Camera )
set trg = null
endfunction
endscope
//TESH.scrollpos=104
//TESH.alwaysfold=0
scope GameStart initializer Init
globals
private constant integer VAMPIRE_PLAYER_COUNT = 6
private unit array HeroSelectors[1]
private unit CAMP_FIRE
private boolean array PlayerSelected[1]
endglobals
private function SpawnVampireForPlayers takes integer playerId returns nothing
local integer i = CheckOutVampireRespawn()
local real x = GetRectCenterX(VampireSpawns[i])
local real y = GetRectCenterY(VampireSpawns[i])
local unit u = CreateUnit(Player(playerId), VAMPIRE, x, y, bj_UNIT_FACING)
local effect e
call RegisterVampire(u)
set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", u, "origin")
call DestroyEffect(e)
set e = null
if (GetLocalPlayer() == Player(playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ClearSelection()
call SelectUnit(u, true)
call PanCameraToTimed(x, y, 0.5)
endif
call Shadow_Message( playerId, "You are alive, good.. now drink some blood to grow stronger.", false)
set u = null
endfunction
private function Actions takes nothing returns nothing
local integer i = 0
local real x
local real y
local timer t
local integer scorePosition = 0
set ForceHunters = CreateForce()
set ForceVampires = CreateForce()
// loop vammpire players
set scorePosition = 1
set i = PLAYER_VAMPIRES_START_ID
loop
exitwhen i > PLAYER_VAMPIRES_END_ID
set HeroByPlayer[i] = null
if GetPlayerController(Player(i)) == MAP_CONTROL_USER and GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
call ForceAddPlayer(ForceVampires, Player(i))
set VampirePlayerCount = VampirePlayerCount + 1
set ScoreBoard_Positions[i] = scorePosition
set scorePosition = scorePosition + 1
call SpawnVampireForPlayers(i)
endif
set i = i + 1
endloop
// loop hunter players
set scorePosition = scorePosition + 2
set i = PLAYER_HUNTERS_START_ID
loop
exitwhen i > PLAYER_HUNTERS_END_ID
set PlayerSelected[i] = false
set HeroByPlayer[i] = null
if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
call ForceAddPlayer(ForceHunters, Player(i))
set HunterPlayerCount = HunterPlayerCount + 1
set ScoreBoard_Positions[i] = scorePosition
set scorePosition = scorePosition + 1
call Debug_Message("Init Hunter Player: "+I2S(i))
if GetPlayerController(Player(i)) == MAP_CONTROL_USER then
set x = GetUnitX(CAMP_FIRE) - 64
set y = GetUnitY(CAMP_FIRE) + 64
call PanCameraToTimedForPlayer(Player(i), x, y, 0.5)
set HeroSelectors[i] = CreateUnit(Player(i), 'e003', x, y, bj_UNIT_FACING)
call SelectUnitForPlayerSingle(CAMP_FIRE, Player(i))
else
endif
endif
set i = i + 1
endloop
set PlayerCount = VampirePlayerCount + HunterPlayerCount
set t = NewTimer()
call TimerStart(t, 1.0, false, function Init_Score_Board )
set t = null
endfunction
private function HunterChoosenConditions takes nothing returns boolean
return IsHunter(GetTriggerUnit()) and not PlayerSelected[GetPlayerId(GetOwningPlayer(GetTriggerUnit()))]
endfunction
private function HunterChoosen takes nothing returns nothing
local unit u = GetTriggerUnit()
local integer playerId = GetPlayerId(GetOwningPlayer(u))
local item i
set PlayerSelected[playerId] = true
call UnitAddType(u, UNIT_TYPE_PEON)
call RemoveUnit(HeroSelectors[playerId])
call SelectUnitForPlayerSingle(u, Player(playerId))
set i = CreateItem('I017', GetUnitX(u), GetUnitY(u))
call UnitAddItem(u, i)
set i = CreateItem('I017', GetUnitX(u), GetUnitY(u))
call UnitAddItem(u, i)
call Game_Message(PlayerNames[playerId] + "has picked a hero: " + GetUnitName(u))
call RegisterHunter(u)
set u = null
set i = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set CAMP_FIRE = gg_unit_n006_0001
// call Actions( )
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, bj_mapInitialPlayableArea )
call TriggerAddCondition( trg, Condition( function HunterChoosenConditions ) )
call TriggerAddAction( trg, function HunterChoosen )
set trg = CreateTrigger()
call TriggerAddAction( trg, function Actions )
call TriggerExecute(trg)
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Daybreak initializer Init
globals
private boolean Daybreak = false
endglobals
private function Actions takes nothing returns nothing
if not Daybreak then
set Daybreak = true
call Game_Message("The new day has come - The vampires lose the game!")
endif
call GameDefeat(PLAYER_VAMPIRES_START_ID, PLAYER_VAMPIRES_END_ID)
call GameVictory(PLAYER_HUNTERS_START_ID, PLAYER_HUNTERS_END_ID)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterGameStateEventTimeOfDay( trg, EQUAL, 6.00 )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library VillagerSystem initializer Init requires HandleTable, BasicFunctions, Alloc, ItemFunctions, StructuredDD, IsUnitInSight
globals
rect VillageArea1
rect VillageArea2
integer array VillagerTypes[1]
private unit ThreatUnit = null
endglobals
function GetVillagerState takes unit u returns integer
local Villager v = GetHandleData(u)
return v.state
endfunction
private function UnitIsWandering takes unit u returns boolean
return GetVillagerState(u) == VILLAGER_STATE_WANDERING
endfunction
private function UnitIsTalking takes unit u returns boolean
return GetVillagerState(u) == VILLAGER_STATE_TALKING
endfunction
private function UnitHasPanic takes unit u returns boolean
return GetVillagerState(u) == VILLAGER_STATE_PANIC
endfunction
private function UnitHasBlood takes unit u returns boolean
local Villager v = GetHandleData(u)
return v.blood > 0
endfunction
private function StartTalkingConditions takes nothing returns boolean
return ( IsCivilian(GetTriggerUnit()) and UnitIsWandering(GetTriggerUnit()) and UnitHasBlood(GetTriggerUnit()) and GetRandomReal(0,100) <= TALKING_CHANCE )
endfunction
private function BackAttackConditions takes nothing returns boolean
return GetVillagerState(GetTriggerUnit()) == VILLAGER_STATE_GUARD_HOLDGROUND
endfunction
private function GuardSmashRatConditions takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == RAT or GetUnitTypeId(GetTriggerUnit()) == CITY_RAT
endfunction
function RegisterSpawn takes unit u returns integer
local Vampire vamp
// Throw double registration warning
if GetHandleData(u) != 0 then
call Debug_Message("|cffFF0000Error:|r Double registration of vampire spawn!")
endif
// Create struct data
set vamp = Vampire.create(u)
// Adjust color
call SetUnitColor( u, ConvertPlayerColor(12) )
// Share vision with vampire players
call UnitShareVision(u, Player(0), true)
call UnitShareVision(u, Player(1), true)
call UnitShareVision(u, Player(2), true)
call UnitShareVision(u, Player(3), true)
call UnitShareVision(u, Player(4), true)
call UnitShareVision(u, Player(5), true)
// Register for damage detection
call StructuredDD.add(u)
return vamp
endfunction
function DisableGuardRatSmash takes integer id returns nothing
local Villager v = id
if v.rat_trigger != null then
call DisableTrigger(v.rat_trigger)
endif
endfunction
function EnableGuardRatSmash takes integer id returns nothing
local Villager v = id
if v.rat_trigger != null then
call EnableTrigger(v.rat_trigger)
endif
endfunction
function DisableTalking takes integer id returns nothing
local Villager v = id
if v.talk_trigger != null then
call DisableTrigger(v.talk_trigger)
endif
endfunction
function EnableTalking takes integer id returns nothing
local Villager v = id
if v.talk_trigger != null then
call EnableTrigger(v.talk_trigger)
endif
endfunction
function GoNextWaypoint takes integer id returns nothing
local Villager v = id
local Waypoint wp = Waypoints[v.wpNext]
call IssuePointOrder(v.u, "move", wp.x, wp.y)
endfunction
private function MoveAroundMap takes integer id returns nothing
local Villager v = id
local real x
local real y
set x = GetRandomReal(GetRectMinX(bj_mapInitialPlayableArea), GetRectMaxX(bj_mapInitialPlayableArea))
set y = GetRandomReal(GetRectMinY(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea))
call IssuePointOrder(v.u, "move", x, y)
endfunction
private function MoveAroundTown takes integer id returns nothing
local Villager v = id
local real r = GetRandomReal(0, 100)
local real x
local real y
if r <= PARK_VISIT_CHANCE then
set x = GetRandomReal(GetRectMinX(VillageArea2), GetRectMaxX(VillageArea2))
set y = GetRandomReal(GetRectMinY(VillageArea2), GetRectMaxY(VillageArea2))
else
set x = GetRandomReal(GetRectMinX(VillageArea1), GetRectMaxX(VillageArea1))
set y = GetRandomReal(GetRectMinY(VillageArea1), GetRectMaxY(VillageArea1))
endif
call IssuePointOrder(v.u, "move", x, y)
endfunction
function CreateTalkingTag takes integer id, string text returns nothing
local Villager v = id
local texttag t = null
// We do not need to create a tag if the villager is not visible
if IsUnitVisible(v.u, Player(SHADOW_PLAYER_ID)) then
set t = CreateTextTag()
set text = "|c00" + v.colorString + text + "|r"
call SetTextTagText(t, text, 0.0184)
call SetTextTagPos(t, GetUnitX(v.u), GetUnitY(v.u), 0.00)
call SetTextTagVelocity(t, 0, 0.02)
call SetTextTagVisibility(t, false)
if IsUnitVisible(v.u, GetLocalPlayer()) then
call SetTextTagVisibility(t, true)
endif
call SetTextTagFadepoint(t, 1)
call SetTextTagLifespan(t, 2)
call SetTextTagPermanent(t, false)
set t = null
endif
endfunction
private function CreateGuardAlertTag takes unit u returns nothing
local integer id = GetPlayerId(GetOwningPlayer(u))
local texttag t = null
if IsUnitVisible(u, Player(SHADOW_PLAYER_ID)) then
set t = CreateTextTag()
call SetTextTagColor(t, 66, 200, 255, 255)
call SetTextTagText(t, "!", 0.05)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
// call SetTextTagVelocity(t, 0, 0.02)
call SetTextTagVisibility(t, true)
call SetTextTagFadepoint(t, 1)
call SetTextTagLifespan(t, 2)
call SetTextTagPermanent(t, false)
set t = null
endif
endfunction
function CreateShoutTag takes integer vil, string text returns nothing
local Villager v = vil
local texttag t = null
local integer i
if (NO_SHOUTS == false) and IsUnitVisible(v.u, Player(SHADOW_PLAYER_ID)) then
set t = CreateTextTag()
set i = GetRandomInt(1,8)
if v.isGuard then
set text = "|c00" + v.colorString + text + "|r"
else
call SetTextTagColor(t, 200, 0, 30, 255)
endif
call SetTextTagText(t, text, 0.0184)
call SetTextTagPos(t, GetUnitX(v.u), GetUnitY(v.u), 0.00)
call SetTextTagVelocity(t, 0, 0.04)
call SetTextTagVisibility(t, false)
if IsUnitVisible(v.u, GetLocalPlayer()) then
call SetTextTagVisibility(t, true)
endif
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1)
call SetTextTagPermanent(t, false)
set t = null
endif
set t = null
endfunction
function CreateVampireTag takes unit u, string text returns nothing
local texttag t = CreateTextTag()
call SetTextTagColor(t, 200, 0, 30, 255)
call SetTextTagText(t, text, 0.024)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.04)
call SetTextTagVisibility(t, true)
call SetTextTagFadepoint(t, 1)
call SetTextTagLifespan(t, 3)
call SetTextTagPermanent(t, false)
set t = null
endfunction
private function GetRandomPanicShoutVampire takes nothing returns string
return PanicShouts[GetRandomInt(0, PanicShoutsCount-1)]
endfunction
private function GetRandomPanicShoutBeast takes nothing returns string
return PanicShoutsWolf[GetRandomInt(0, PanicShoutsWolfCount-1)]
endfunction
private function GetRandomWTFShout takes nothing returns string
return WTFShouts[GetRandomInt(0, WTFShoutsCount-1)]
endfunction
private function GetRandomAttackShout takes nothing returns string
return AttackShouts[GetRandomInt(0, AttackShoutsCount-1)]
endfunction
private function GetRandomStopChasingComment takes nothing returns string
return StopChasingComments[GetRandomInt(0, StopChasingCommentsCount-1)]
endfunction
function GetRandomKillComment takes nothing returns string
return GuardKillsComments[GetRandomInt(0, GuardKillsCommentsCount-1)]
endfunction
private function GetRandomLookoutComment takes nothing returns string
return LookoutComments[GetRandomInt(0, LookoutCommentsCount-1)]
endfunction
private function GetRandomGuardLookoutComment takes nothing returns string
return LookoutCommentsGuards[GetRandomInt(0, LookoutCommentsGuardsCount-1)]
endfunction
private function GetRandomRatShout takes nothing returns string
return RatShouts[GetRandomInt(0, RatShoutsCount-1)]
endfunction
function GetRandomInvestigationAreaComment takes nothing returns string
return InvestigationAreaComments[GetRandomInt(0, InvestigationAreaCommentsCount-1)]
endfunction
function GetRandomEscapeComment takes nothing returns string
return EscapeComments[GetRandomInt(0, EscapeCommentsCount-1)]
endfunction
private function GetRandomSmallTalk takes nothing returns string
local integer i = GetRandomInt(1,8)
local string s = "Hello! What's up?"
if i == 1 then
set s = "I'm not feelin' all that well"
elseif i == 2 then
set s = "It's gettin' cold"
elseif i == 3 then
set s = "The winter is near"
elseif i == 4 then
set s = "How are you?"
elseif i == 5 then
set s = "How is your daugther?"
elseif i == 6 then
set s = "I hate those damn vampires!"
elseif i == 7 then
set s = "I cannot sleep this night"
elseif i == 8 then
set s = "Haven't slept well"
endif
return s
endfunction
function StateTester takes nothing returns nothing
local timer t = GetExpiredTimer()
local Villager v = GetTimerData(t)
local Vampire vamp
set t = null
// call CreateTalkingTag(v, StateNames[v.state]+" ("+StateNames[v.lastState]+") ["+OrderId2String(GetUnitCurrentOrder(v.u))+" | "+ I2S(GetUnitCurrentOrder(v.u)))
// Waypoint Tester
call CreateTalkingTag(v, StateNames[v.state]+" ("+StateNames[v.lastState]+") ["+StateNames[v.defaultState]+"] ["+OrderId2String(GetUnitCurrentOrder(v.u))+" | "+ I2S(GetUnitCurrentOrder(v.u))+"] Target: "+GetUnitName(v.target)+" | "+I2S(v.wpNext)+" ("+I2S(v.wpCur)+")")
// Target Tester
// if v.t == 0 then
// call CreateTalkingTag(v.u, StateNames[v.state]+" ("+StateNames[v.lastState]+") ["+OrderId2String(GetUnitCurrentOrder(v.u))+" | NULL")
// else
// set vamp = v.t
// call CreateTalkingTag(v.u, StateNames[v.state]+" ("+StateNames[v.lastState]+") ["+OrderId2String(GetUnitCurrentOrder(v.u))+" | "+ GetUnitName(vamp.u))
// endif
endfunction
private function ReleaseVillager takes integer id returns nothing
local Villager v = id
if v.isGuard then
set GuardCount = GuardCount - 1
if v.defaultState == VILLAGER_STATE_GUARD_PATROL then
set GuardCountPatrol = GuardCountPatrol - 1
endif
else
set CivilianCount = CivilianCount - 1
endif
set VillagerCount = VillagerCount - 1
call UpdateVillagerCount()
call v.destroy()
// call Debug_Message("Villager released "+I2S(id))
endfunction
function RemoveVillager takes integer i returns nothing
local Villager v = i
local unit u = v.u
call ReleaseVillager(v)
call RemoveUnit(u)
set u = null
endfunction
function OnVillagerDead takes nothing returns nothing
local Villager v = GetHandleData(GetTriggeringTrigger())
local real x
local real y
local real facing
local unit spawn = null
local effect e = null
local unit u = null
if v.state == VILLAGER_STATE_TRANSFORMING then
set u = v.u
set x = GetUnitX(v.u)
set y = GetUnitY(v.u)
set facing = GetUnitFacing(v.u)
// Explosion effect
set e = AddSpecialEffect("BloodEx.mdl", x, y)
call RegisterEffect(e, 3)
call ReleaseVillager(v)
call RemoveUnit(u)
// Create heart
call CreateIngredient(ITEM_INGREDIENT_HEART, x, y)
// Create vampire spawn
set spawn = CreateUnit(Player(9), SPAWN, x, y, facing)
call RegisterSpawn(spawn)
set spawn = null
set e = null
set u = null
else
call ReleaseVillager(v)
endif
endfunction
function SetVillagerState takes integer id, integer state returns nothing
local Villager v = id
local Vampire vamp
// Only do something if we have a new state
if state != v.state then
//set v.useWP = false
set v.calming_down_ticks = 0
set v.chasing_ticks = 0
set v.lookoutEnabled = false
set v.investigate = false
if v.shout_timer != null then
call ReleaseTimer(v.shout_timer)
set v.shout_timer = null
endif
// STANDING
if state == VILLAGER_STATE_STAND then
set v.lookoutEnabled = true
call EnableTalking(v)
// WANDERING
elseif state == VILLAGER_STATE_WANDERING then
set v.lookoutEnabled = true
call EnableTalking(v)
// LOOKOUT
elseif state == VILLAGER_STATE_LOOKOUT then
if v.state == VILLAGER_STATE_GUARD_INVESTIGATE then
set v.investigate = true
set v.lookout_max_ticks = GetRandomInt(LOOKOUT_INVESTIGATE_TICKS_MIN, LOOKOUT_INVESTIGATE_TICKS_MAX)
else
set v.lookout_max_ticks = GetRandomInt(LOOKOUT_TICKS_MIN, LOOKOUT_TICKS_MAX)
endif
set v.lookout_ticks = 0
set v.lookout_ticks_small = 0
set v.lookout_time_ticks = GetRandomInt(LOOKOUT_TIME_TICKS_MIN, LOOKOUT_TIME_TICKS_MAX)
// TALKING
elseif state == VILLAGER_STATE_TALKING then
call DisableTalking(v)
// PANIC
elseif state == VILLAGER_STATE_PANIC then
call DisableTalking(v)
// WAYPOINTS
elseif state == VILLAGER_STATE_ON_WAYPOINTS then
set v.lookoutEnabled = true
set v.useWP = true
// Go to next waypoint
call GoNextWaypoint(id)
// PARALYZED
elseif state == VILLAGER_STATE_PARALYZED then
// call Debug_Message("Set villager state paralzyed")
call PauseUnit(v.u, true)
call DisableTalking(v)
call DisableGuardRatSmash(v)
// FEAR
elseif state == VILLAGER_STATE_FEAR then
// call Debug_Message("Set villager state fear")
call DisableTalking(v)
call DisableGuardRatSmash(v)
call SetUnitMoveSpeed(v.u, VILLAGER_MOVE_SPEED_FEAR)
// TRANSFORMING
elseif state == VILLAGER_STATE_TRANSFORMING then
// call Debug_Message("Set villager state transforming")
set v.transformation_ticks = 0
call PauseUnit(v.u, false)
call DisableTalking(v)
call DisableGuardRatSmash(v)
call SetUnitVertexColor(v.u, 175, 255, 175, 255)
//if v.lastState == VILLAGER_STATE_ON_WAYPOINTS then
// set v.useWP = true
//endif
set v.transformationTime = GetRandomInt(TRANSFORMATION_TICKS_MIN, TRANSFORMATION_TICKS_MAX)
call SetUnitMoveSpeed(v.u, CIVILIAN_MOVE_SPEED_NORMAL)
// GUARD HOLD POSITION
elseif state == VILLAGER_STATE_GUARD_HOLDGROUND then
set v.lookoutEnabled = true
call EnableGuardRatSmash(v)
call IssueImmediateOrder(v.u, "holdposition")
call SetUnitMoveSpeed(v.u, GUARD_MOVE_SPEED_NORMAL)
// GUARD PATROL (WAYPOINTS)
elseif state == VILLAGER_STATE_GUARD_PATROL then
set v.useWP = true
call EnableGuardRatSmash(v)
if GetUnitTypeId(v.u) == INQUISITOR then
call SetUnitMoveSpeed(v.u, INQUISITOR_MOVE_SPEED)
else
set v.lookoutEnabled = true
call SetUnitMoveSpeed(v.u, GUARD_MOVE_SPEED_PATROL)
endif
// Go to next waypoint
call GoNextWaypoint(id)
// GUARD ESCORT
elseif state == VILLAGER_STATE_GUARD_ESCORT then
set v.lookoutEnabled = true
call EnableGuardRatSmash(v)
call SetUnitMoveSpeed(v.u, GUARD_MOVE_SPEED_NORMAL)
// GUARD INVESTIGATE (RUN TO)
elseif state == VILLAGER_STATE_GUARD_INVESTIGATE then
set v.investigate = true
call DisableGuardRatSmash(v)
call SetUnitMoveSpeed(v.u, GUARD_MOVE_SPEED_NORMAL)
// GUARD ATTACKS
elseif state == VILLAGER_STATE_GUARD_ATTACK then
call DisableGuardRatSmash(v)
set v.giveUp = false
call SetUnitMoveSpeed(v.u, GUARD_MOVE_SPEED_NORMAL)
endif
set v.lastState = v.state
set v.state = state
endif
endfunction
function SetTarget takes integer id, unit threat returns nothing
local Villager v = id
// Set target unit
set v.target = threat
set v.tUndead = false
if threat != null then
// Set target unit struct data
set v.targetData = GetHandleData(threat)
// Set target unit typeId
set v.tType = GetUnitTypeId(threat)
// Check if vampire or animal
if IsVampirePlayer(threat) then
set v.tUndead = true
endif
// call Debug_Message("Set Target: "+GetUnitName(threat)+" Data: "+I2S(v.targetData)+" Type: "+I2S(v.tType)+")")
else
set v.targetData = 0
set v.tType = 0
// call Debug_Message("Set Target: NULL")
endif
endfunction
private function shout_timerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
local Villager v = id
if v.isGuard then
call CreateShoutTag(v, GetRandomAttackShout())
else
if IsVampiricTypeId(v.seenUnitId) then
call CreateShoutTag(v, GetRandomPanicShoutVampire())
elseif IsBeastTypeId(v.seenUnitId) then
call CreateShoutTag(v, GetRandomPanicShoutBeast())
endif
endif
set t = null
endfunction
function StartPanic takes integer id, unit threat returns nothing
local Villager v = id
// Update villager knowledge on threat
set v.seenOnX = GetUnitX(threat)
set v.seenOnY = GetUnitY(threat)
set v.seenUnitId = GetUnitTypeId(threat)
// Red ping for hunters
call PingMinimapForForceEx(ForceHunters, v.seenOnX, v.seenOnY, 3.0, bj_MINIMAPPINGSTYLE_SIMPLE, 223, 48, 48)
// Set State
call SetVillagerState(id, VILLAGER_STATE_PANIC)
// Set move speed, color and make go
call SetUnitMoveSpeed(v.u, CIVILIAN_MOVE_SPEED_PANIC)
call SetUnitTimeScale(v.u, 1.00)
call SetUnitVertexColor(v.u, 255, 100, 100, 255)
call MoveAroundTown(id)
// Shout timer
if v.shout_timer == null then
set v.shout_timer = NewTimer()
call SetTimerData(v.shout_timer, id)
call TimerStart(v.shout_timer, SHOUT_PERIOD, true, function shout_timerCallback)
else
call Debug_Message("Error: Trying to create shout timer before releasing old one!")
endif
if IsVampiricThreat(threat) then
call CreateShoutTag(v, GetRandomPanicShoutVampire())
elseif IsBeast(threat) then
call CreateShoutTag(v, GetRandomPanicShoutBeast())
endif
endfunction
struct Villager
unit u = null
unit target = null
integer targetData = 0
integer tType = 0
boolean tUndead = false
// integer t = 0
// integer lastT = 0
// integer tType = 0
// States
integer state = 0
integer lastState = 0
integer defaultState = 0
string colorString = "000000"
// Booleans
boolean isGuard = false
boolean onTower = false
boolean stickMainRoad = false
boolean useWP = false
boolean hasTorch = false
boolean talking_time = false
boolean investigate = false
boolean lookoutEnabled = false
boolean giveUp = false
// Ticks
integer calming_down_ticks = 0
integer chasing_ticks = 0
integer investigate_ticks = 0
integer transformation_ticks = 0
integer lookout_ticks = 0
integer lookout_ticks_small = 0
integer lookout_max_ticks = 0
integer lookout_time_ticks = 0
integer handle_id = 0
integer typeId = 0
integer blood = MAX_BLOOD
integer bloodMax = 0
integer wpCur = 0
integer wpNext = 0
integer escortTarget = 0
integer escort1
integer escort2
real defaultFacing = 0
real facingMin = 0
real facingMax = 0
real homeX = 0
real homeY = 0
real homeXmin = 0
real homeXmax = 0
real homeYmin = 0
real homeYmax = 0
integer transformationTime = 0
effect alert = null
region investigateArea = null
// Timers
timer ai_timer = null
timer shout_timer = null
timer state_timer = null
timer lookout_start_timer = null
// Triggers
trigger onDeathTrigger = null
trigger talk_trigger = null
trigger rat_trigger = null // Guard only
trigger investigation_trigger = null
// Villager
integer talking_counter =0
integer talking_finish_count = 0
real seenOnX = 0
real seenOnY = 0
real seenOnXmin = 0
real seenOnYmin = 0
real seenOnXmax = 0
real seenOnYmax = 0
integer seenUnitId = 0
region investigationArea = null
integer masterPlayer = 0
static method create takes unit u, boolean isGuard returns thistype
local thistype this = thistype.allocate()
// Unit and handle
set this.u = u
set this.handle_id = GetHandleId(u)
call SetHandleData(this.u, this)
// is Guard?
set this.isGuard = isGuard
set this.blood = MAX_BLOOD_VILLAGER
set this.bloodMax = MAX_BLOOD_VILLAGER
// AI timer
set this.ai_timer = NewTimer()
call SetTimerData(this.ai_timer, this)
// On death trigger
set this.onDeathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent( this.onDeathTrigger, this.u, EVENT_UNIT_DEATH )
call TriggerAddAction( this.onDeathTrigger, function OnVillagerDead )
call SetHandleData(this.onDeathTrigger, this)
// if Civilian
if not this.isGuard then
// set up talking trigger
set this.talk_trigger = CreateTrigger()
call TriggerRegisterUnitInRange(this.talk_trigger, this.u, START_TALKING_RANGE, null)
call TriggerAddCondition(this.talk_trigger, Condition( function StartTalkingConditions ) )
call SetHandleData(this.talk_trigger, this)
// The up movement speed and timescale
call SetUnitMoveSpeed(this.u, CIVILIAN_MOVE_SPEED_NORMAL)
call SetUnitTimeScale(this.u, 0.5)
set CivilianCount = CivilianCount + 1
// call Debug_Message("Villager registered "+I2S(this)+" (civilian)")
// Guard
else
// Smash Rats
set this.rat_trigger = CreateTrigger()
call TriggerRegisterUnitInRange(this.rat_trigger, this.u, GUARD_RAT_SMASH_RANGE, null)
call TriggerAddCondition(this.rat_trigger, Condition( function GuardSmashRatConditions ) )
call SetHandleData(this.rat_trigger, this)
set GuardCount = GuardCount + 1
endif
if DEBUG_MODE and STATE_TESTER then
set this.state_timer = NewTimer()
call SetTimerData(this.state_timer, this)
call TimerStart(this.state_timer, STATE_TESTER_REFRESH, true, function StateTester)
endif
set VillagerCount = VillagerCount + 1
call UpdateVillagerCount()
// call Debug_Message("Villager successfully registered "+I2S(this)+" (guard)")
return this
endmethod
public method setHome takes real x, real y returns nothing
set this.homeX = x
set this.homeY = y
set this.homeXmin = x - HOME_PUFFER
set this.homeXmax = x + HOME_PUFFER
set this.homeYmin = y - HOME_PUFFER
set this.homeYmax = y + HOME_PUFFER
endmethod
public method setFacing takes real facing returns nothing
set this.defaultFacing = facing
set this.facingMin = facing - FACING_BUFFER
set this.facingMax = facing + FACING_BUFFER
endmethod
public method addTorch takes nothing returns nothing
if not this.hasTorch then
set this.hasTorch = true
call AddSpecialEffectTarget("TinyTorch1.mdl", this.u, "hand,left")
endif
endmethod
public method makeFollowMainRoad takes nothing returns nothing
set this.stickMainRoad = true
endmethod
public method destroy takes nothing returns nothing
// call Debug_Message("Destroying Villager struct data "+I2S(this))
if this.u != null then
call ReleaseHandleData( this.u )
set this.u = null
endif
if this.target != null then
set this.target = null
endif
// Release timers
if this.ai_timer != null then
call ReleaseTimer(this.ai_timer)
set this.ai_timer = null
endif
if this.shout_timer != null then
call ReleaseTimer(this.shout_timer)
set this.shout_timer = null
endif
if this.state_timer != null then
call ReleaseTimer(this.state_timer)
set this.state_timer = null
endif
if this.lookout_start_timer != null then
call ReleaseTimer(this.lookout_start_timer)
set this.lookout_start_timer = null
endif
// Destroy triggers
if this.onDeathTrigger != null then
call ReleaseHandleData( this.onDeathTrigger )
call DestroyTrigger(this.onDeathTrigger)
set this.onDeathTrigger = null
endif
if this.talk_trigger != null then
call ReleaseHandleData( this.talk_trigger )
call DestroyTrigger(this.talk_trigger)
set this.talk_trigger = null
endif
if this.rat_trigger != null then
call ReleaseHandleData( this.rat_trigger )
call DestroyTrigger(this.rat_trigger)
set this.rat_trigger = null
endif
if this.investigation_trigger != null then
call ReleaseHandleData( this.investigation_trigger )
call DestroyTrigger(this.investigation_trigger)
set this.investigation_trigger = null
endif
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
// Core function that determines potential threat targets for NPCs
// 1. UNIT Type ancient is used for aggressive units on map 2. unit needs to be alive, 3. unit need to be visible
private function VillagerAITargetConditions takes nothing returns boolean
// return ( GetUnitTypeId(GetFilterUnit()) == VAMPIRE or GetUnitTypeId(GetFilterUnit()) == WOLF or GetUnitTypeId(GetFilterUnit()) == SPAWN ) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and IsUnitVisible(GetFilterUnit(), Player(11))
return IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0 and IsUnitVisible(GetFilterUnit(), Player(11))
endfunction
// This function checks if a threat is notable by a villager
private function VillagerNoticesThreat takes integer id returns unit
local Villager v = id
local unit t = null
local real x = GetUnitX(v.u)
local real y = GetUnitY(v.u)
// Reset return value
set ThreatUnit = null
// Clear targets and pick possible threat units in sight range
call GroupClear(targetGroup)
call GroupEnumUnitsInRange(targetGroup, x, y, VILLAGER_SIGHT_RANGE, Condition(function VillagerAITargetConditions))
// loop through group and check if a vampire is in sight
loop
set t = FirstOfGroup(targetGroup)
exitwhen t == null or ThreatUnit != null
if IsUnitInSight(v.u, t) and not WallInBetween(GetUnitX(v.u), GetUnitY(v.u), GetUnitX(t), GetUnitY(t)) then
set ThreatUnit = t
// call Debug_Message("Threat noticed by villager!")
endif
call GroupRemoveUnit(targetGroup, t)
endloop
// Cleanup
set t = null
// Return
return ThreatUnit
endfunction
private function GuardNoticePanicConditions takes nothing returns boolean
return GetVillagerState(GetFilterUnit()) == VILLAGER_STATE_PANIC
endfunction
private function GuardNoticePanicCivilian takes integer id returns integer
// local group targets = NewGroup()
local Villager gua = id
local unit t = null
local real x = GetUnitX(gua.u)
local real y = GetUnitY(gua.u)
local integer panicCiv = 0
// Get all panic civs in range
call GroupClear(targetGroup)
call GroupEnumUnitsInRange(targetGroup, x, y, GUARD_ALERT_RANGE, Condition(function GuardNoticePanicConditions))
// Just take first of them
set t = FirstOfGroup(targetGroup)
if t != null and not WallInBetween(GetUnitX(gua.u), GetUnitY(gua.u), GetUnitX(t), GetUnitY(t)) then
set panicCiv = GetHandleData(t)
endif
// Cleanup
// call ReleaseGroup(targets)
// set targets = null
set t = null
// Return
return panicCiv
endfunction
function SetNextWaypoint takes integer id, integer wp_id returns nothing
local Villager v = id
set v.wpCur = v.wpNext
set v.wpNext = wp_id
endfunction
private function TransformationDone takes integer id returns nothing
local Villager v = id
call KillUnit(v.u)
endfunction
private function StopPanic takes integer id returns nothing
local Villager v = id
// Get back to default state
call SetVillagerState(v, v.defaultState)
call SetUnitMoveSpeed(v.u, CIVILIAN_MOVE_SPEED_NORMAL)
call SetUnitTimeScale(v.u, 0.5)
call SetUnitVertexColor(v.u, 255, 255, 255, 255)
// Update villager knowledge on threat
set v.seenOnX = 0
set v.seenOnY = 0
set v.seenUnitId = 0
if v.shout_timer != null then
call ReleaseTimer(v.shout_timer)
set v.shout_timer = null
endif
endfunction
private function VillagerLooksOut takes integer id returns nothing
local Villager v = id
// Set new facing
call SetUnitFacingTimed(v.u, GetRandomReal(0, 360), GetRandomReal(0.6, 1.2))
// If guard
if v.isGuard then
// Is investigatio
if v.investigate then
call CreateTalkingTag(v, GetRandomInvestigationAreaComment())
else
call CreateTalkingTag(v, GetRandomGuardLookoutComment())
endif
else
call CreateTalkingTag(v, GetRandomLookoutComment())
endif
endfunction
private function EnterInvestigateAreaConditions takes nothing returns boolean
return GetHandleId(GetTriggerUnit()) == GetHandleId(GetTriggeringTrigger())
endfunction
private function ClearInvestigationArea takes integer id returns nothing
local Villager gua = id
// Remove trigger
if gua.investigation_trigger != null then
call ReleaseHandleData( gua.investigation_trigger )
call DestroyTrigger(gua.investigation_trigger)
set gua.investigation_trigger = null
endif
// Remove region
if gua.investigationArea != null then
call RemoveRegion(gua.investigationArea)
set gua.investigationArea = null
endif
endfunction
private function GuardEntersInvestigateArea takes integer id returns nothing
local Villager gua = id
// Comment for reaching investigation area
call CreateShoutTag(gua, GetRandomInvestigationAreaComment())
// Remove trigger and region
call ClearInvestigationArea(gua)
// Set state to lookout
call SetVillagerState(gua, VILLAGER_STATE_LOOKOUT)
endfunction
private function GuardReachInvestigateAreaTriggerCallback takes nothing returns nothing
local Villager gua = GetHandleData(GetTriggerUnit())
call GuardEntersInvestigateArea(gua)
endfunction
private function GuardEntersInvestigationAreaConditions takes nothing returns boolean
return GetHandleData(GetTriggerUnit()) == GetHandleData(GetTriggeringTrigger())
endfunction
private function CreateInvestigationRegion takes integer id returns nothing
local Villager gua = id
set gua.investigationArea = CreateRegion()
call RegionAddRect(gua.investigationArea, Rect(gua.seenOnXmin, gua.seenOnYmin, gua.seenOnXmax, gua.seenOnYmax) )
set gua.investigation_trigger = CreateTrigger()
call TriggerRegisterEnterRegion(gua.investigation_trigger, gua.investigationArea, Condition( function GuardEntersInvestigationAreaConditions ))
call TriggerAddAction( gua.investigation_trigger, function GuardReachInvestigateAreaTriggerCallback )
call SetHandleData(gua.investigation_trigger, gua)
endfunction
function GuardStartInvestigation takes integer id, integer id2 returns nothing
local Villager gua = id
local Villager v = id2
// WTF tag
call CreateShoutTag(gua, GetRandomWTFShout())
// Set investigation coordinates
set gua.seenOnX = v.seenOnX
set gua.seenOnY = v.seenOnY
set gua.seenOnXmin = gua.seenOnX - INVESTIGATION_AREA
set gua.seenOnXmax = gua.seenOnX + INVESTIGATION_AREA
set gua.seenOnYmin = gua.seenOnY - INVESTIGATION_AREA
set gua.seenOnYmax = gua.seenOnY + INVESTIGATION_AREA
// move there
call IssuePointOrder(gua.u, "move", gua.seenOnX, gua.seenOnY)
// Set state to investigation
call SetVillagerState(gua, VILLAGER_STATE_GUARD_INVESTIGATE)
// Create temporary investigation region
// call CreateInvestigationRegion(gua)
endfunction
private function GoLookoutIfPossible takes nothing returns nothing
local Villager v = GetTimerData(GetExpiredTimer())
call ReleaseTimer(v.lookout_start_timer)
set v.lookout_start_timer = null
if v.lookoutEnabled then
call SetVillagerState(v, VILLAGER_STATE_LOOKOUT)
endif
endfunction
// Starts a timeout; when finished, got to lookout state if still enabled
private function StartLookoutTimer takes integer id returns nothing
local Villager v = id
set v.lookout_start_timer = NewTimer()
call SetTimerData(v.lookout_start_timer, v)
call TimerStart(v.lookout_start_timer, GetRandomReal(LOOKOUT_START_TICKS_MIN, LOOKOUT_START_TICKS_MAX), false, function GoLookoutIfPossible)
endfunction
function GuardAttacks takes integer id, unit threat returns nothing
local Villager gua = id
// call Debug_Message("Guard attacks!")
// Red ping for hunters
call PingMinimapForForceEx(ForceHunters, GetUnitX(threat), GetUnitY(threat), 5.0, bj_MINIMAPPINGSTYLE_SIMPLE, 223, 48, 48)
// Display Guard attack comment
call CreateShoutTag(gua, GetRandomWTFShout())
// Set the target of the guard
call SetTarget(gua, threat)
// Order guard to attack
call IssueTargetOrder(gua.u, "attack", threat)
// Set his state to attack state
call SetVillagerState(gua, VILLAGER_STATE_GUARD_ATTACK)
endfunction
// Basic AI Timer for villagers (guards and civilians)
private function VillagerAITimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
local unit threat = null
local integer threatId = 0
local Villager v = id
local Villager v2
local real x = GetUnitX(v.u)
local real y = GetUnitY(v.u)
local Vampire vamp
local integer panicCiv = 0
// If villager is dead
if GetUnitState(v.u, UNIT_STATE_LIFE) <= 0 then
call Debug_Message("|cffFF0000Error:|r Villager AI timer callback for dead villager?!")
// Villager alive
else
// We do not need checks for tower guards
if not v.onTower then
// Check for threat (do so only if villager is seen by Shadow Player or already in attacking state)
if IsUnitVisible(v.u, Player(SHADOW_PLAYER_ID)) or v.state == VILLAGER_STATE_GUARD_ATTACK then
set threat = VillagerNoticesThreat(id)
set threatId = GetHandleData(threat)
// set HEAVY_CALC_COUNT = HEAVY_CALC_COUNT + 1
endif
// Check if guard notices panic civ
if v.isGuard then
set panicCiv = GuardNoticePanicCivilian(v)
endif
endif
// =====================================================
// STANDING
// =====================================================
if v.state == VILLAGER_STATE_STAND then
// If vampire in sight - PANIC!
if threat != null and v.blood > 0 then
call StartPanic(v, threat)
else
// Enable lookout
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
endif
// =====================================================
// LOOKOUT
// =====================================================
elseif v.state == VILLAGER_STATE_LOOKOUT then
call IssueImmediateOrder(v.u, "holdposition")
// Guard
if v.isGuard then
set panicCiv = GuardNoticePanicCivilian(v)
// If vampire in sight - go to attack state
if threat != null then
call GuardAttacks(v, threat)
// If alerted by panic civilian, go investigate
elseif panicCiv != 0 then
call GuardStartInvestigation(v, panicCiv)
// End of lookout
elseif v.lookout_ticks >= v.lookout_max_ticks then
call SetVillagerState(v, v.defaultState)
// Lookout
else
set v.lookout_ticks = v.lookout_ticks + 1
set v.lookout_ticks_small = v.lookout_ticks_small + 1
if v.lookout_ticks_small >= v.lookout_time_ticks then
set v.lookout_time_ticks = GetRandomInt(LOOKOUT_TIME_TICKS_MIN, LOOKOUT_TIME_TICKS_MAX)
set v.lookout_ticks_small = 0
call VillagerLooksOut(v)
endif
endif
// Civilian
else
// If vampire in sight - PANIC!
if threat != null and v.blood > 0 then
call StartPanic(v, threat)
// End of lookout
elseif v.lookout_ticks >= v.lookout_max_ticks then
call SetVillagerState(v, v.defaultState)
// Lookout
else
set v.lookout_ticks = v.lookout_ticks + 1
set v.lookout_ticks_small = v.lookout_ticks_small + 1
if v.lookout_ticks_small >= v.lookout_time_ticks then
set v.lookout_time_ticks = GetRandomInt(LOOKOUT_TIME_TICKS_MIN,LOOKOUT_TIME_TICKS_MAX)
set v.lookout_ticks_small = 0
call VillagerLooksOut(v)
endif
endif
endif
// =====================================================
// TRAVELLING AND WANDERING
// =====================================================
elseif v.state == VILLAGER_STATE_WANDERING then
// If vampire in sight - PANIC!
if threat != null and v.blood > 0 then
call StartPanic(v, threat)
else
// Enable lookout
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
// If staying, keep on moving
if GetUnitCurrentOrder(v.u) == 0 and GetRandomReal(0,100) >= 30 then
call MoveAroundTown(id)
endif
endif
// =====================================================
// CONVERSATION
// =====================================================
elseif v.state == VILLAGER_STATE_TALKING then
// If vampire in sight - PANIC!
if threat != null and v.blood > 0 then
call StartPanic(v, threat)
// else
else
// inc talking counter
set v.talking_counter = v.talking_counter + 1
// Time to say something?
if v.talking_time then
set v.talking_time = false
call CreateTalkingTag(v, GetRandomSmallTalk())
else
set v.talking_time = true
endif
// If conversation is over
if v.talking_counter >= v.talking_finish_count then
call SetVillagerState(id, v.defaultState )
endif
endif
// =====================================================
// WAYPOINTS
// =====================================================
elseif v.state == VILLAGER_STATE_ON_WAYPOINTS then
// If vampire in sight - PANIC!
if threat != null then
call StartPanic(v, threat)
else
// Enable lookout
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
if GetUnitCurrentOrder(v.u) == 0 and v.wpNext != 0 then
// call Debug_Message("ÖHm die Message will ich sehen")
// Go to next waypoint
call GoNextWaypoint(v)
endif
endif
// =====================================================
// PANIC!
// =====================================================
elseif v.state == VILLAGER_STATE_PANIC then
// Run around
if GetUnitCurrentOrder(v.u) == 0 then
call MoveAroundTown(id)
endif
// Only calm down if no vampires around
if threat != null then
set v.calming_down_ticks = 0
else
set v.calming_down_ticks = v.calming_down_ticks + 1
endif
// OK, that should be enough to calm down
if v.calming_down_ticks >= CALMING_DOWN_TICKS then
call StopPanic(id)
endif
// =====================================================
// PARALYZED
// =====================================================
elseif v.state == VILLAGER_STATE_PARALYZED then
// Do nothing
// =====================================================
// FEAR
// =====================================================
elseif v.state == VILLAGER_STATE_FEAR then
// Do nothing
// =====================================================
// TRANSFORMING
// =====================================================
elseif v.state == VILLAGER_STATE_TRANSFORMING then
// Inc. transformation
set v.transformation_ticks = v.transformation_ticks + 1
// If staying, keep on moving
if GetRandomReal(0,100) <= 20 then
call MoveAroundMap(id)
endif
if v.transformation_ticks >= v.transformationTime then
call TransformationDone(v)
endif
// =====================================================
// GUARD HOLD GROUND
// =====================================================
elseif v.state == VILLAGER_STATE_GUARD_HOLDGROUND then
// If vampire in sight - go to attack state
if threat != null then
call GuardAttacks(v, threat)
// If alerted by panic civilian, go investigate
elseif panicCiv != 0 then
call GuardStartInvestigation(v, panicCiv)
// else
else
// Enable lookout
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
// If far away from home
// if (x<v.homeXmin) or (x>v.homeXmax) or (y<v.homeYmin) or (y>v.homeYmax) then
if not IsUnitInRangeXY(v.u, v.homeX, v.homeY, 16 ) then
// if not already moving, go for it
if GetUnitCurrentOrder(v.u) == 0 then
call IssuePointOrder(v.u, "move", v.homeX, v.homeY)
// call Debug_Message("moving guard back to home")
endif
// if home
else
// Facing right direction?
if GetUnitFacing(v.u) < v.facingMin or GetUnitFacing(v.u) > v.facingMax then
call SetUnitFacing(v.u, v.defaultFacing)
// call Debug_Message("Guard readjusting facing "+R2S(GetUnitFacing(v.u))+" | default: "+R2S(v.defaultFacing))
endif
endif
endif
// =====================================================
// GUARD PATROL (WAYPOINTS)
// =====================================================
elseif v.state == VILLAGER_STATE_GUARD_PATROL then
// If vampire in sight - go to attack state
if threat != null then
call GuardAttacks(v, threat)
// If alerted by panic civilian, go investigate
elseif panicCiv != 0 then
call GuardStartInvestigation(v, panicCiv)
else
// Enable lookout
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
if GetUnitCurrentOrder(v.u) == 0 and v.wpNext != 0 then
// Go to next waypoint
call GoNextWaypoint(v)
endif
endif
// =====================================================
// GUARD ESCORT
// =====================================================
elseif v.state == VILLAGER_STATE_GUARD_ESCORT then
// Fetch villager script for escort target
set v2 = v.escortTarget
// If vampire in sight - go to attack state
if threat != null then
call GuardAttacks(v, threat)
// If alerted by panic civilian, go investigate
elseif panicCiv != 0 then
call GuardStartInvestigation(v, panicCiv)
// If escort target dead?
elseif (v2 == 0) or (GetUnitState(v2.u, UNIT_STATE_LIFE)<=0) then
set v.defaultState = VILLAGER_STATE_GUARD_PATROL
set v.wpCur = 0
set v.wpNext = GetRandomInt(1, WP_COUNT)
call SetVillagerState(v, VILLAGER_STATE_GUARD_PATROL)
set GuardCountPatrol = GuardCountPatrol + 1
else
// Start lookout timer if not already running
if v.lookout_start_timer == null then
call StartLookoutTimer(v)
endif
// Move escorting unit to target unit
if GetUnitCurrentOrder(v.u) == 0 then
call IssueTargetOrder(v.u, "move", v2.u)
endif
endif
// =====================================================
// GUARD RUN TO INVESTIGATION
// =====================================================
elseif v.state == VILLAGER_STATE_GUARD_INVESTIGATE then
// If vampire in sight - go to attack state
if threat != null then
call ClearInvestigationArea(v) // This is no longer needed, guard has new interest
call GuardAttacks(v, threat)
// else
elseif IsUnitInRangeXY(v.u, v.seenOnX, v.seenOnY, 128 ) then
// Guard is in investigation area --> change to lookout state
call GuardEntersInvestigateArea(v)
else
// if not already moving, go for it
if GetUnitCurrentOrder(v.u) == 0 then
call IssuePointOrder(v.u, "move", v.seenOnX, v.seenOnY)
endif
endif
// =====================================================
// GUARD ATTACKS
// =====================================================
elseif v.state == VILLAGER_STATE_GUARD_ATTACK then
// if threat != null then
// call Debug_Message("GUARD ATTACK STATE | threat: "+GetUnitName(threat))
// else
// call Debug_Message("GUARD ATTACK STATE | threat: NULL")
// endif
// Inc. chasing ticks
set v.chasing_ticks = v.chasing_ticks + 1
// Start shout timer if not already done
if v.shout_timer == null then
call CreateShoutTag(v, GetRandomAttackShout())
set v.shout_timer = NewTimer()
call SetTimerData(v.shout_timer, v)
call TimerStart(v.shout_timer, SHOUT_PERIOD*3.0, true, function shout_timerCallback)
endif
// If target is any vampire form, make sure to update target in case of recent transformation
if v.tUndead then
// Get struct data of target
set vamp = v.targetData
// If unit type is different
if v.tType != GetUnitTypeId(vamp.u) and vamp.u != null then
// Guard won't be able to chase bats
if (GetUnitTypeId(v.u) == GUARD and GetUnitTypeId(vamp.u) == BAT) then
set v.giveUp = true
call CreateTalkingTag(v, GetRandomEscapeComment())
// Else..
else
call SetTarget(v, vamp.u)
// call Debug_Message("Attack target has changed! (Reordering attack)")
call IssueTargetOrder(v.u, "attack", vamp.u)
endif
endif
endif
// (A) threat in range
// -----------------
if threat != null then
set v.calming_down_ticks = 0
// Target is dead
if GetUnitState(v.target, UNIT_STATE_LIFE) <= 0 then
call Debug_Message("Old Attack target dead! (Reordering attack)")
call GuardAttacks(v, threat)
// Target out of range
elseif not IsUnitInRange(v.u, v.target, GUARD_GIVEUP_CHASING_RANGE) then
call Debug_Message("Old Attack target out of range! (Reordering attack)")
call GuardAttacks(v, threat)
endif
// (B) No threat in range
// -------------------
else
set v.calming_down_ticks = v.calming_down_ticks + 1
// Guard gives up chasing conditions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// (1) Target dead
if GetUnitState(v.target, UNIT_STATE_LIFE) <= 0 then
set v.giveUp = true
// call Debug_Message("Guard gives up (target dead)")
// (2) Target out of range
elseif not IsUnitInRange(v.u, v.target, GUARD_GIVEUP_CHASING_RANGE) then
set v.giveUp = true
call CreateTalkingTag(v, GetRandomStopChasingComment())
// call Debug_Message("Guard gives up (target out of range)")
elseif v.chasing_ticks > MAX_CHASING_TICKS then
set v.giveUp = true
call CreateTalkingTag(v, GetRandomStopChasingComment())
// call Debug_Message("Guard gives up (out of stamina)")
endif
endif
if v.giveUp then
if v.shout_timer != null then
call ReleaseTimer(v.shout_timer)
set v.shout_timer = null
endif
call SetTarget(v, null)
call SetVillagerState(v, v.defaultState)
endif
endif
endif
set t = null
set threat = null
endfunction
private function StartTalking takes nothing returns nothing
local integer id = GetHandleData( GetTriggeringTrigger() )
local integer id2 = GetHandleData( GetTriggerUnit() )
local integer talk_count = GetRandomInt(TALKING_COUNT_MIN, TALKING_COUNT_MAX)
local Villager vil1 = id
local Villager vil2 = id2
local real x1 = GetUnitX(vil1.u)
local real y1 = GetUnitY(vil1.u)
local real x2 = GetUnitX(vil2.u)
local real y2 = GetUnitY(vil2.u)
set vil1.talking_counter = 0
set vil2.talking_counter = 0
set vil1.talking_finish_count = talk_count
set vil2.talking_finish_count = talk_count
call SetVillagerState(id, VILLAGER_STATE_TALKING)
call SetVillagerState(id2, VILLAGER_STATE_TALKING)
call IssueImmediateOrder( vil1.u, "holdposition" )
call IssueImmediateOrder( vil2.u, "holdposition" )
call SetUnitFacingTimed(vil1.u, bj_RADTODEG * Atan2(y2-y1, x2-x1), 1.0)
call SetUnitFacingTimed(vil2.u, bj_RADTODEG * Atan2(y1-y2, x1-x2), 1.0)
set vil1.talking_time = true
set vil2.talking_time = false
endfunction
private function GuardSmashRat takes nothing returns nothing
local integer id = GetHandleData( GetTriggeringTrigger() )
local Villager gua = id
if IsUnitInSight(gua.u, GetTriggerUnit()) then
call IssueTargetOrder(gua.u, "attack", GetTriggerUnit())
call CreateTalkingTag(gua, GetRandomRatShout())
endif
endfunction
function RegisterVillager takes unit villager, integer defaultState, boolean onTower, integer wpId returns integer
local Villager v
// Throw double registration warning
if GetHandleData(villager) != 0 then
call Debug_Message("|cffFF0000Error:|r Double registration of villager!")
endif
// Normal civilian
if IsCivilian(villager) then
set v = Villager.create(villager, false)
call TriggerAddAction(v.talk_trigger, function StartTalking )
// Guard
elseif IsGuard(villager) then
set v = Villager.create(villager, true)
// Smash Rats trigger
call TriggerAddAction(v.rat_trigger, function GuardSmashRat )
// Set home coordinates
call v.setHome( GetUnitX(v.u), GetUnitY(v.u) )
call v.setFacing( GetUnitFacing(v.u) )
// Inc Patrol Guard Count
if defaultState == VILLAGER_STATE_GUARD_PATROL and GetUnitTypeId(villager) != INQUISITOR then
set GuardCountPatrol = GuardCountPatrol + 1
endif
// Inc Stayput Guard Count
if defaultState == VILLAGER_STATE_GUARD_HOLDGROUND and GetUnitTypeId(villager) != INQUISITOR then
set GuardCountStayput = GuardCountStayput + 1
endif
else
call Debug_Message("|cffFF0000Error:|r Trying to register unit not supported by system!")
return 0
endif
// On waypoints?
if (defaultState == VILLAGER_STATE_ON_WAYPOINTS) or (defaultState == VILLAGER_STATE_GUARD_PATROL) then
set v.wpCur = 0
set v.wpNext = wpId
endif
// Set default state
// call IssueImmediateOrder(v.u, "stop")
set v.defaultState = defaultState
call SetVillagerState(v, defaultState)
// Color
set v.colorString = VillagerColors[GetRandomInt(0, VillagerColorCount-1)]
set v.onTower = onTower
// Start AI timer
if not onTower then
call TimerStart(v.ai_timer, AI_REFRESH_INTERVAL, true, function VillagerAITimerCallback)
endif
// Damage Detection
call StructuredDD.add(v.u)
return v
endfunction
private function VillagerDamagedEvent takes nothing returns nothing
local Villager v = GetHandleData(GetTriggerUnit())
local unit attacker = GetEventDamageSource()
// call Debug_Message("Villager takes damage | "+GetUnitName(GetEventDamageSource())+" dealt "+R2S(GetEventDamage())+" to: "+GetUnitName(GetTriggerUnit()))
if IsThreat(attacker) and v.state != VILLAGER_STATE_TRANSFORMING then
// Guard
if v.isGuard then
// if not already attacking something, do now!
if GetUnitCurrentOrder(v.u) != ORDER_ATTACK then
call GuardAttacks(v, attacker)
endif
// Civilian
else
// If not already in panic, then it's time now
if v.state != VILLAGER_STATE_PANIC then
call StartPanic(v, attacker)
endif
endif
endif
set attacker = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local integer id
set VillageArea1 = gg_rct_VillageArea1
set VillageArea2 = gg_rct_VillageArea2
set VillagerTypes[0] = VILLAGER1
set VillagerTypes[1] = VILLAGER2
set VillagerTypes[2] = VILLAGER3
call StructuredDD.addHandler(function VillagerDamagedEvent)
endfunction
endlibrary
//TESH.scrollpos=135
//TESH.alwaysfold=0
library WaypointSystem initializer Init requires BasicFunctions, VillagerSystem, Gates
globals
integer WP_COUNT = 0
private constant integer MAX_WP = 512
private intpool Teleports
endglobals
// Prefer main route?
struct Waypoint
integer id = 0
integer options = 0
boolean deadEnd = false
boolean isTeleport = false
boolean isGate = false
boolean preGate = false
integer b1 = 0
integer b2 = 0
integer b3 = 0
integer b4 = 0
integer b5 = 0
real x = 0
real y = 0
integer array paths[6]
trigger trg = null
static method getRandom takes nothing returns thistype
return Waypoints[GetRandomInt(1, WP_COUNT)]
endmethod
static method getRandomCity takes nothing returns thistype
return Waypoints[GetRandomInt(1, 129)]
endmethod
static method getRandomForestNorth takes nothing returns thistype
return Waypoints[GetRandomInt(300, 427)]
endmethod
static method getRandomForestSouth takes nothing returns thistype
return Waypoints[GetRandomInt(200, 261)]
endmethod
static method getRandomForestWest takes nothing returns thistype
return Waypoints[GetRandomInt(500, 566)]
endmethod
static method getRandomBorderPoint takes nothing returns thistype
return Waypoints[Teleports.getRandomInt()]
endmethod
static method GetX takes integer id returns real
local thistype this = id
return this.x
endmethod
static method GetY takes integer id returns real
local thistype this = id
return this.y
endmethod
endstruct
// OK, Unit enters waypoint
// 1. Check for dead end
// If dead end, switch direction of unit
// set next = previous
// 2. OK, count options in front direction
// Maybe there is a slight chance for going back? Probably not..
// Decide on option;
// if stick to main route, always follow main, else random
// Decide which one
private function GetGateIdForWp takes integer i returns integer
// South
if i == 1 or i == 226 then
return 1
endif
// East
if i == 38 or i == 331 then
return 2
endif
// North (right)
if i == 25 or i == 384 then
return 3
endif
// North (left)
if i == 129 or i == 427 then
return 4
endif
// West (left)
if i == 527 or i == 568 then
return 5
endif
return 0
endfunction
private function GetRandomTeleportPoint takes integer i returns integer
local integer tele = 0
call Teleports.removeInt(i)
set tele = Teleports.getRandomInt()
call Teleports.addInt(i, 1.0)
return tele
endfunction
private function UnitEntersWP takes nothing returns nothing
local integer wp_id = GetHandleData(GetTriggeringTrigger())
local Villager v = GetHandleData(GetTriggerUnit())
local Villager v2
local Waypoint wp = Waypoints[wp_id]
local Waypoint wp_cur = Waypoints[v.wpCur]
local Waypoint wp_next
local integer temp = 0
local integer newTarget = 0
local integer i
// Is this the right waypoint?
if wp_id == v.wpNext then
// No current waypoint? Set default one
if v.wpCur == 0 then
set v.wpCur = wp.paths[GetRandomInt(1,wp.options)]
endif
// is teleport? and current WP is not teleport? then beam
if wp.isTeleport and not wp_cur.isTeleport then
if ( GetUnitTypeId(v.u) == INQUISITOR ) then
// call Debug_Message("Unit enters teleport WP..")
// Get new random teleport WP, different to this teleport point
set newTarget = GetRandomTeleportPoint(wp_id)
// Get new waypoint
set wp_next = Waypoints[newTarget]
set v.wpNext = newTarget
set v.wpCur = wp_id
call SetUnitPosition(v.u, wp_next.x, wp_next.y)
else
// if entering unit has escort, make set escort waypoint
if ( v.escort1 != 0) then
set v2 = v.escort1
set v2.defaultState = VILLAGER_STATE_GUARD_PATROL
set v2.escortTarget = 0
set v2.wpCur = v.wpCur
set v2.wpNext = v.wpNext
call SetVillagerState(v2, VILLAGER_STATE_GUARD_PATROL)
set GuardCountPatrol = GuardCountPatrol + 1
endif
call RemoveVillager(v)
endif
// If usual waypoint
else
// Go back, when deadend or gate and no torch
if wp.deadEnd or ( wp.isGate and not v.hasTorch ) then
set temp = v.wpNext // save current villager next WP
set v.wpNext = v.wpCur // set next WP of villager as current
set v.wpCur = temp
// Else we need to detect the direction
else
loop
exitwhen newTarget != v.wpCur and newTarget != 0 // new WP must be different to current one and shall not be zero
if ( wp.preGate and not v.hasTorch ) then // limit the possibilities if one option is gate and no torch is equipped
set newTarget = wp.paths[GetRandomInt(1,(wp.options-1))] // In WP definition, make sure that the last option is always the gate
else
set newTarget = wp.paths[GetRandomInt(1,wp.options)]
endif
endloop
// update WP data
set v.wpNext = newTarget
set v.wpCur = wp_id
set wp_next = Waypoints[newTarget]
// Open Gate
if wp_next.isGate then
call OpenGate(GetGateIdForWp(newTarget))
set v.lookoutEnabled = false
endif
endif
// Move on only if state is WP
if v.state == VILLAGER_STATE_ON_WAYPOINTS or v.state == VILLAGER_STATE_GUARD_PATROL then
call GoNextWaypoint(v)
endif
endif
endif
endfunction
private function UnitUsesWaypoints takes nothing returns boolean
local Villager v = GetHandleData(GetTriggerUnit())
return v.useWP
endfunction
private function RegWP takes integer thisId, rect square, integer b1, integer b2, integer b3, integer b4, integer b5, boolean IsSecondary, boolean deadEnd, boolean isGate, boolean isTeleport, boolean preGate returns nothing
local Waypoint wp = Waypoint.create()
local region rectRegion = CreateRegion()
call RegionAddRect(rectRegion, square)
set wp.x = GetRectCenterX(square)
set wp.y = GetRectCenterY(square)
set wp.options = 0
set wp.deadEnd = deadEnd
set wp.isTeleport = isTeleport
set wp.isGate = isGate
set wp.preGate = preGate
set wp.id = thisId
set wp.paths[1] = b1
set wp.paths[2] = b2
set wp.paths[3] = b3
set wp.paths[4] = b4
set wp.paths[5] = b5
if wp.paths[1] != 0 then
set wp.options = wp.options + 1
endif
if wp.paths[2] != 0 then
set wp.options = wp.options + 1
endif
if wp.paths[3] != 0 then
set wp.options = wp.options + 1
endif
if wp.paths[4] != 0 then
set wp.options = wp.options + 1
endif
if wp.paths[5] != 0 then
set wp.options = wp.options + 1
endif
set wp.trg = CreateTrigger( )
call TriggerRegisterEnterRegion(wp.trg, rectRegion, null)
call TriggerAddCondition(wp.trg, function UnitUsesWaypoints)
call TriggerAddAction( wp.trg, function UnitEntersWP )
call SetHandleData(wp.trg, thisId)
if DEBUG_MODE and SHOW_WAYPOINTS then
call AddSpecialEffect("Abilities\\Spells\\Orc\\TrollBerserk\\HeadhunterWEAPONSLeft.mdl", wp.x, wp.y)
endif
set rectRegion = null
set Waypoints[thisId] = wp
set WP_COUNT = WP_COUNT + 1
endfunction
private function InitWaypointsCity takes nothing returns nothing
//IsSecondary, deadEnd, isGate, isTeleport
// City
call RegWP( 1, gg_rct_WPc1, 2,226, 0, 0, 0, false, false, true, false, false ) // City Gate (south)
call RegWP( 2, gg_rct_WPc2, 3, 60, 1, 0, 0, false, false, false, false, true ) // Pre-Gate crossing (south)
call RegWP( 3, gg_rct_WPc3, 2, 4, 0, 0, 0, false, false, false, false, false )
call RegWP( 4, gg_rct_WPc4, 3, 5, 0, 0, 0, false, false, false, false, false )
call RegWP( 5, gg_rct_WPc5, 4, 6, 61, 0, 0, false, false, false, false, false )
call RegWP( 6, gg_rct_WPc6, 5, 7, 0, 0, 0, false, false, false, false, false )
call RegWP( 7, gg_rct_WPc7, 6, 8, 0, 0, 0, false, false, false, false, false )
call RegWP( 8, gg_rct_WPc8, 7, 9, 0, 0, 0, false, false, false, false, false )
call RegWP( 9, gg_rct_WPc9, 8, 10, 0, 0, 0, false, false, false, false, false )
call RegWP( 10, gg_rct_WPc10, 9, 11, 0, 0, 0, false, false, false, false, false )
call RegWP( 11, gg_rct_WPc11, 10, 12, 13, 0, 0, false, false, false, false, false )
call RegWP( 12, gg_rct_WPc12, 11, 14, 0, 0, 0, false, false, false, false, false )
call RegWP( 13, gg_rct_WPc13, 11, 14, 0, 0, 0, false, false, false, false, false )
call RegWP( 14, gg_rct_WPc14, 12, 13, 15, 0, 0, false, false, false, false, false )
call RegWP( 15, gg_rct_WPc15, 14, 16, 0, 0, 0, false, false, false, false, false )
call RegWP( 16, gg_rct_WPc16, 15, 17, 128,0, 0, false, false, false, false, false ) // Upper crossing near baron
call RegWP( 17, gg_rct_WPc17, 16, 18, 0, 0, 0, false, false, false, false, false )
call RegWP( 18, gg_rct_WPc18, 17, 19, 0, 0, 0, false, false, false, false, false )
call RegWP( 19, gg_rct_WPc19, 18, 20, 0, 0, 0, false, false, false, false, false )
call RegWP( 20, gg_rct_WPc20, 19, 21, 48, 0, 0, false, false, false, false, false )
call RegWP( 21, gg_rct_WPc21, 20, 22, 0, 0, 0, false, false, false, false, false )
call RegWP( 22, gg_rct_WPc22, 21, 23, 0, 0, 0, false, false, false, false, false )
call RegWP( 23, gg_rct_WPc23, 22, 24, 0, 0, 0, false, false, false, false, false )
call RegWP( 24, gg_rct_WPc24, 23, 26,25, 0, 0, false, false, false, false, true ) // Pre-Gate crossing (north-east)
call RegWP( 25, gg_rct_WPc25, 24,384, 0, 0, 0, false, false, true, false, false ) // Gate (north)
call RegWP( 26, gg_rct_WPc26, 24, 27, 0, 0, 0, false, false, false, false, false )
call RegWP( 27, gg_rct_WPc27, 26, 28, 0, 0, 0, false, false, false, false, false )
call RegWP( 28, gg_rct_WPc28, 27, 29, 0, 0, 0, false, false, false, false, false )
call RegWP( 29, gg_rct_WPc29, 28, 30, 0, 0, 0, false, false, false, false, false )
call RegWP( 30, gg_rct_WPc30, 29, 31, 0, 0, 0, false, false, false, false, false )
call RegWP( 31, gg_rct_WPc31, 30, 32, 0, 0, 0, false, false, false, false, false )
call RegWP( 32, gg_rct_WPc32, 31, 33, 0, 0, 0, false, false, false, false, false )
call RegWP( 33, gg_rct_WPc33, 32, 34, 0, 0, 0, false, false, false, false, false )
call RegWP( 34, gg_rct_WPc34, 33, 35, 0, 0, 0, false, false, false, false, false )
call RegWP( 35, gg_rct_WPc35, 34, 36, 0, 0, 0, false, false, false, false, false )
call RegWP( 36, gg_rct_WPc36, 35, 37, 0, 0, 0, false, false, false, false, false )
call RegWP( 37, gg_rct_WPc37, 36, 39, 38, 0, 0, false, false, false, false, true ) // Pre-Gate crossing (east)
call RegWP( 38, gg_rct_WPc38, 37, 331, 0, 0, 0,false, false, true, false, false ) // Gate (east)
call RegWP( 39, gg_rct_WPc39, 37, 40, 0, 0, 0, false, false, false, false, false )
call RegWP( 40, gg_rct_WPc40, 39, 41, 0, 0, 0, false, false, false, false, false )
call RegWP( 41, gg_rct_WPc41, 40, 42, 0, 0, 0, false, false, false, false, false )
call RegWP( 42, gg_rct_WPc42, 41, 43, 0, 0, 0, false, false, false, false, false )
call RegWP( 43, gg_rct_WPc43, 42, 44, 49, 0, 0, false, false, false, false, false )
call RegWP( 44, gg_rct_WPc44, 43, 45, 0, 0, 0, false, false, false, false, false )
call RegWP( 45, gg_rct_WPc45, 44, 46, 0, 0, 0, false, false, false, false, false )
call RegWP( 46, gg_rct_WPc46, 45, 47, 0, 0, 0, false, false, false, false, false )
call RegWP( 47, gg_rct_WPc47, 46, 48, 0, 0, 0, false, false, false, false, false )
call RegWP( 48, gg_rct_WPc48, 47, 20, 0, 0, 0, false, false, false, false, false )
call RegWP( 49, gg_rct_WPc49, 43, 50, 0, 0, 0, false, false, false, false, false )
call RegWP( 50, gg_rct_WPc50, 49, 51, 0, 0, 0, false, false, false, false, false )
call RegWP( 51, gg_rct_WPc51, 50, 52, 55, 0, 0, false, false, false, false, false )
call RegWP( 52, gg_rct_WPc52, 51, 53, 0, 0, 0, false, false, false, false, false )
call RegWP( 53, gg_rct_WPc53, 52, 54, 0, 0, 0, false, false, false, false, false )
call RegWP( 54, gg_rct_WPc54, 53, 7, 0, 0, 0, false, false, false, false, false )
call RegWP( 55, gg_rct_WPc55, 51, 56, 0, 0, 0, false, false, false, false, false )
call RegWP( 56, gg_rct_WPc56, 55, 57, 0, 0, 0, false, false, false, false, false )
call RegWP( 57, gg_rct_WPc57, 56, 58, 0, 0, 0, false, false, false, false, false )
call RegWP( 58, gg_rct_WPc58, 57, 59, 0, 0, 0, false, false, false, false, false )
call RegWP( 59, gg_rct_WPc59, 58, 60, 0, 0, 0, false, false, false, false, false )
call RegWP( 60, gg_rct_WPc60, 59, 2, 0, 0, 0, false, false, false, false, false )
call RegWP( 61, gg_rct_WPc61, 5, 62, 0, 0, 0, false, false, false, false, false )
call RegWP( 62, gg_rct_WPc62, 61, 63, 0, 0, 0, false, false, false, false, false )
call RegWP( 63, gg_rct_WPc63, 62, 64, 0, 0, 0, false, false, false, false, false )
call RegWP( 64, gg_rct_WPc64, 63, 65, 120, 0, 0, false, false, false, false, false )
call RegWP( 65, gg_rct_WPc65, 64, 66, 0, 0, 0, false, false, false, false, false )
call RegWP( 66, gg_rct_WPc66, 65, 67, 0, 0, 0, false, false, false, false, false )
call RegWP( 67, gg_rct_WPc67, 66, 68, 0, 0, 0, false, false, false, false, false )
call RegWP( 68, gg_rct_WPc68, 67, 69, 0, 0, 0, false, false, false, false, false )
call RegWP( 69, gg_rct_WPc69, 68, 70, 0, 0, 0, false, false, false, false, false )
call RegWP( 70, gg_rct_WPc70, 69, 71, 0, 0, 0, false, false, false, false, false )
call RegWP( 71, gg_rct_WPc71, 70, 72, 0, 0, 0, false, false, false, false, false )
call RegWP( 72, gg_rct_WPc72, 71, 73, 0, 0, 0, false, false, false, false, false )
call RegWP( 73, gg_rct_WPc73, 72, 74, 0, 0, 0, false, false, false, false, false )
call RegWP( 74, gg_rct_WPc74, 73, 75, 0, 0, 0, false, false, false, false, false )
call RegWP( 75, gg_rct_WPc75, 74, 76, 0, 0, 0, false, false, false, false, false )
call RegWP( 76, gg_rct_WPc76, 75, 77, 0, 0, 0, false, false, false, false, false )
call RegWP( 77, gg_rct_WPc77, 76, 78, 0, 0, 0, false, false, false, false, false )
call RegWP( 78, gg_rct_WPc78, 77, 79, 0, 0, 0, false, false, false, false, false )
call RegWP( 79, gg_rct_WPc79, 78, 80, 0, 0, 0, false, false, false, false, false )
call RegWP( 80, gg_rct_WPc80, 79, 81, 0, 0, 0, false, false, false, false, false )
call RegWP( 81, gg_rct_WPc81, 80, 82, 0, 0, 0, false, false, false, false, false )
call RegWP( 82, gg_rct_WPc82, 81, 83, 0, 0, 0, false, false, false, false, false )
call RegWP( 83, gg_rct_WPc83, 82, 84, 0, 0, 0, false, false, false, false, false )
call RegWP( 84, gg_rct_WPc84, 83, 85, 0, 0, 0, false, false, false, false, false )
call RegWP( 85, gg_rct_WPc85, 84, 86, 0, 0, 0, false, false, false, false, false )
call RegWP( 86, gg_rct_WPc86, 85, 87, 0, 0, 0, false, false, false, false, false )
call RegWP( 87, gg_rct_WPc87, 86, 88, 0, 0, 0, false, false, false, false, false )
call RegWP( 88, gg_rct_WPc88, 87, 89, 0, 0, 0, false, false, false, false, false )
call RegWP( 89, gg_rct_WPc89, 88, 90, 0, 0, 0, false, false, false, false, false )
call RegWP( 90, gg_rct_WPc90, 89, 91, 567, 0, 0, false, false, false, false, false )
call RegWP( 91, gg_rct_WPc91, 90, 92, 93, 0, 0, false, false, false, false, false )
call RegWP( 92, gg_rct_WPc92, 91, 0, 0, 0, 0, false, true, false, false, false ) // dead end Tower
call RegWP( 93, gg_rct_WPc93, 91, 94, 0, 0, 0, false, false, false, false, false )
call RegWP( 94, gg_rct_WPc94, 93, 95, 0, 0, 0, false, false, false, false, false )
call RegWP( 95, gg_rct_WPc95, 94, 96, 0, 0, 0, false, false, false, false, false )
call RegWP( 96, gg_rct_WPc96, 95, 97, 0, 0, 0, false, false, false, false, false )
call RegWP( 97, gg_rct_WPc97, 96, 98, 0, 0, 0, false, false, false, false, false )
call RegWP( 98, gg_rct_WPc98, 97, 99, 0, 0, 0, false, false, false, false, false )
call RegWP( 99, gg_rct_WPc99, 98, 100, 0, 0, 0, false, false, false, false, false )
call RegWP(100, gg_rct_WPc100, 99, 101, 0, 0, 0, false, false, false, false, false )
call RegWP(101, gg_rct_WPc101, 100, 102, 0, 0, 0, false, false, false, false, false )
call RegWP(102, gg_rct_WPc102, 101, 103, 0, 0, 0, false, false, false, false, false )
call RegWP(103, gg_rct_WPc103, 102, 104, 0, 0, 0, false, false, false, false, false )
call RegWP(104, gg_rct_WPc104, 103, 105, 108, 0, 0, false, false, false, false, false )
call RegWP(105, gg_rct_WPc105, 104, 106, 0, 0, 0, false, false, false, false, false )
call RegWP(106, gg_rct_WPc106, 105, 107, 0, 0, 0, false, false, false, false, false )
call RegWP(107, gg_rct_WPc107, 107, 0, 0, 0, 0, false, true, false, false, false )
call RegWP(108, gg_rct_WPc108, 104, 109, 0, 0, 0, false, false, false, false, false )
call RegWP(109, gg_rct_WPc109, 108, 110, 121, 0, 0, false, false, false, false, false )
call RegWP(110, gg_rct_WPc110, 109, 111, 0, 0, 0, false, false, false, false, false )
call RegWP(111, gg_rct_WPc111, 110, 112, 0, 0, 0, false, false, false, false, false )
call RegWP(112, gg_rct_WPc112, 111, 113, 0, 0, 0, false, false, false, false, false )
call RegWP(113, gg_rct_WPc113, 112, 114, 0, 0, 0, false, false, false, false, false )
call RegWP(114, gg_rct_WPc114, 113, 115, 0, 0, 0, false, false, false, false, false )
call RegWP(115, gg_rct_WPc115, 114, 116, 0, 0, 0, false, false, false, false, false )
call RegWP(116, gg_rct_WPc116, 115, 117, 0, 0, 0, false, false, false, false, false )
call RegWP(117, gg_rct_WPc117, 116, 118, 0, 0, 0, false, false, false, false, false )
call RegWP(118, gg_rct_WPc118, 117, 119, 0, 0, 0, false, false, false, false, false )
call RegWP(119, gg_rct_WPc119, 118, 120, 0, 0, 0, false, false, false, false, false )
call RegWP(120, gg_rct_WPc120, 119, 64, 0, 0, 0, false, false, false, false, false )
call RegWP(121, gg_rct_WPc121, 109, 122, 0, 0, 0, false, false, false, false, false )
call RegWP(122, gg_rct_WPc122, 121, 123, 0, 0, 0, false, false, false, false, false )
call RegWP(123, gg_rct_WPc123, 122, 124, 0, 0, 0, false, false, false, false, false )
call RegWP(124, gg_rct_WPc124, 123, 125,129, 0, 0, false, false, false, false, true ) // Pre-Gate crossing (north-west)
call RegWP(125, gg_rct_WPc125, 124, 126, 0, 0, 0, false, false, false, false, false )
call RegWP(126, gg_rct_WPc126, 125, 127, 0, 0, 0, false, false, false, false, false )
call RegWP(127, gg_rct_WPc127, 126, 128, 0, 0, 0, false, false, false, false, false )
call RegWP(128, gg_rct_WPc128, 127, 16, 0, 0, 0, false, false, false, false, false )
call RegWP(129, gg_rct_WPc129, 124, 427, 0, 0, 0, false, false, true, false, false ) // Gate (north, left)
call Debug_Message("Town waypoint initialization successfull! ("+I2S(WP_COUNT)+")")
endfunction
private function InitWaypointsForestSouth takes nothing returns nothing
//IsSecondary, deadEnd, isGate, isTeleport, isPreGate
call RegWP( 200, gg_rct_Wp200, 201, 500, 0, 0, 0, false, false, false, false, false )
call RegWP( 201, gg_rct_Wp201, 200, 202, 0, 0, 0, false, false, false, false, false )
call RegWP( 202, gg_rct_Wp202, 201, 203, 0, 0, 0, false, false, false, false, false )
call RegWP( 203, gg_rct_Wp203, 202, 204, 0, 0, 0, false, false, false, false, false )
call RegWP( 204, gg_rct_Wp204, 203, 205, 0, 0, 0, false, false, false, false, false )
call RegWP( 205, gg_rct_Wp205, 204, 206, 0, 0, 0, false, false, false, false, false )
call RegWP( 206, gg_rct_Wp206, 205, 207, 0, 0, 0, false, false, false, false, false )
call RegWP( 207, gg_rct_Wp207, 206, 208, 0, 0, 0, false, false, false, false, false )
call RegWP( 208, gg_rct_Wp208, 207, 209, 0, 0, 0, false, false, false, false, false )
call RegWP( 209, gg_rct_Wp209, 208, 210, 0, 0, 0, false, false, false, false, false )
call RegWP( 210, gg_rct_Wp210, 209, 211, 0, 0, 0, false, false, false, false, false )
call RegWP( 211, gg_rct_Wp211, 210, 212, 0, 0, 0, false, false, false, false, false )
call RegWP( 212, gg_rct_Wp212, 211, 213, 0, 0, 0, false, false, false, false, false )
call RegWP( 213, gg_rct_Wp213, 212, 214, 0, 0, 0, false, false, false, false, false )
call RegWP( 214, gg_rct_Wp214, 213, 215, 0, 0, 0, false, false, false, false, false )
call RegWP( 215, gg_rct_Wp215, 214, 216, 0, 0, 0, false, false, false, false, false )
call RegWP( 216, gg_rct_Wp216, 215, 217, 0, 0, 0, false, false, false, false, false )
call RegWP( 217, gg_rct_Wp217, 216, 218, 0, 0, 0, false, false, false, false, false )
call RegWP( 218, gg_rct_Wp218, 217, 219, 0, 0, 0, false, false, false, false, false )
call RegWP( 219, gg_rct_Wp219, 218, 220, 0, 0, 0, false, false, false, false, false )
call RegWP( 220, gg_rct_Wp220, 219, 221, 227, 0, 0, false, false, false, false, false )
call RegWP( 221, gg_rct_Wp221, 220, 222, 0, 0, 0, false, false, false, false, false )
call RegWP( 222, gg_rct_Wp222, 221, 223, 0, 0, 0, false, false, false, false, false )
call RegWP( 223, gg_rct_Wp223, 222, 224, 0, 0, 0, false, false, false, false, false )
call RegWP( 224, gg_rct_Wp224, 223, 225, 0, 0, 0, false, false, false, false, false )
call RegWP( 225, gg_rct_Wp225, 224, 226, 0, 0, 0, false, false, false, false, false )
call RegWP( 226, gg_rct_Wp226, 225, 1, 0, 0, 0, false, false, true, false, false ) // City Gate (south)
call RegWP( 227, gg_rct_Wp227, 220, 228, 0, 0, 0, false, false, false, false, false )
call RegWP( 228, gg_rct_Wp228, 227, 229, 0, 0, 0, false, false, false, false, false )
call RegWP( 229, gg_rct_Wp229, 228, 230, 0, 0, 0, false, false, false, false, false )
call RegWP( 230, gg_rct_Wp230, 229, 231,252, 0, 0, false, false, false, false, false )
call RegWP( 231, gg_rct_Wp231, 230, 232, 0, 0, 0, false, false, false, false, false )
call RegWP( 232, gg_rct_Wp232, 231, 233, 0, 0, 0, false, false, false, false, false )
call RegWP( 233, gg_rct_Wp233, 232, 234, 0, 0, 0, false, false, false, false, false )
call RegWP( 234, gg_rct_Wp234, 233, 235, 0, 0, 0, false, false, false, false, false )
call RegWP( 235, gg_rct_Wp235, 234, 236, 0, 0, 0, false, false, false, false, false )
call RegWP( 236, gg_rct_Wp236, 235, 237, 0, 0, 0, false, false, false, false, false )
call RegWP( 237, gg_rct_Wp237, 236, 238, 0, 0, 0, false, false, false, false, false )
call RegWP( 238, gg_rct_Wp238, 237, 239, 0, 0, 0, false, false, false, false, false )
call RegWP( 239, gg_rct_Wp239, 238, 240,241, 0, 0, false, false, false, false, false )
call RegWP( 240, gg_rct_Wp240, 239, 319, 0, 0, 0, false, false, false, false, false ) // Bridge 1 South Forest --> East Forest TODO
call RegWP( 241, gg_rct_Wp241, 239,242, 0, 0, 0, false, false, false, false, false )
call RegWP( 242, gg_rct_Wp242, 241,243, 0, 0, 0, false, false, false, false, false )
call RegWP( 243, gg_rct_Wp243, 242,244, 0, 0, 0, false, false, false, false, false )
call RegWP( 244, gg_rct_Wp244, 243,245,253, 0, 0, false, false, false, false, false )
call RegWP( 245, gg_rct_Wp245, 244,246, 0, 0, 0, false, false, false, false, false )
call RegWP( 246, gg_rct_Wp246, 245,247, 0, 0, 0, false, false, false, false, false )
call RegWP( 247, gg_rct_Wp247, 246,248, 0, 0, 0, false, false, false, false, false )
call RegWP( 248, gg_rct_Wp248, 247,249, 0, 0, 0, false, false, false, false, false )
call RegWP( 249, gg_rct_Wp249, 248,250, 0, 0, 0, false, false, false, false, false )
call RegWP( 250, gg_rct_Wp250, 249,251, 0, 0, 0, false, false, false, false, false )
call RegWP( 251, gg_rct_Wp251, 250,252, 0, 0, 0, false, false, false, false, false )
call RegWP( 252, gg_rct_Wp252, 251,230, 0, 0, 0, false, false, false, false, false )
call RegWP( 253, gg_rct_Wp253, 244,254, 0, 0, 0, false, false, false, false, false )
call RegWP( 254, gg_rct_Wp254, 253,255, 0, 0, 0, false, false, false, false, false )
call RegWP( 255, gg_rct_Wp255, 254,256, 0, 0, 0, false, false, false, false, false )
call RegWP( 256, gg_rct_Wp256, 255,257,259, 0, 0, false, false, false, false, false )
call RegWP( 257, gg_rct_Wp257, 256,258, 0, 0, 0, false, false, false, false, false )
call RegWP( 258, gg_rct_Wp258, 257, 0, 0, 0, 0, false, false, false, true, false ) // Map bounds (South East)
call RegWP( 259, gg_rct_Wp259, 256,260, 0, 0, 0, false, false, false, false, false )
call RegWP( 260, gg_rct_Wp260, 259,261, 0, 0, 0, false, false, false, false, false )
call RegWP( 261, gg_rct_Wp261, 260,300, 0, 0, 0, false, false, false, false, false ) // Bridge 2 South Forest --> East Forest TODO
call Debug_Message("Southern forest waypoint initialization successfull! ("+I2S(WP_COUNT)+")")
endfunction
private function InitWaypointsForestNorth takes nothing returns nothing
//IsSecondary, deadEnd, isGate, isTeleport
call RegWP( 300, gg_rct_Wp300, 261, 301, 0, 0, 0, false, false, false, false, false ) // Transition South - North (right)
call RegWP( 301, gg_rct_Wp301, 300, 302, 0, 0, 0, false, false, false, false, false )
call RegWP( 302, gg_rct_Wp302, 301, 303, 0, 0, 0, false, false, false, false, false )
call RegWP( 303, gg_rct_Wp303, 302, 304, 0, 0, 0, false, false, false, false, false )
call RegWP( 304, gg_rct_Wp304, 303, 305, 0, 0, 0, false, false, false, false, false )
call RegWP( 305, gg_rct_Wp305, 304, 306, 0, 0, 0, false, false, false, false, false )
call RegWP( 306, gg_rct_Wp306, 305, 307, 0, 0, 0, false, false, false, false, false )
call RegWP( 307, gg_rct_Wp307, 306, 308, 0, 0, 0, false, false, false, false, false )
call RegWP( 308, gg_rct_Wp308, 307, 309,320, 0, 0, false, false, false, false, false )
call RegWP( 309, gg_rct_Wp309, 308, 310, 0, 0, 0, false, false, false, false, false )
call RegWP( 310, gg_rct_Wp310, 309, 311, 0, 0, 0, false, false, false, false, false )
call RegWP( 311, gg_rct_Wp311, 310, 312, 0, 0, 0, false, false, false, false, false )
call RegWP( 312, gg_rct_Wp312, 311, 313, 0, 0, 0, false, false, false, false, false )
call RegWP( 313, gg_rct_Wp313, 312, 314, 0, 0, 0, false, false, false, false, false )
call RegWP( 314, gg_rct_Wp314, 313, 315, 0, 0, 0, false, false, false, false, false )
call RegWP( 315, gg_rct_Wp315, 314, 316, 0, 0, 0, false, false, false, false, false )
call RegWP( 316, gg_rct_Wp316, 315, 317, 0, 0, 0, false, false, false, false, false )
call RegWP( 317, gg_rct_Wp317, 316, 318, 0, 0, 0, false, false, false, false, false )
call RegWP( 318, gg_rct_Wp318, 317, 319, 0, 0, 0, false, false, false, false, false )
call RegWP( 319, gg_rct_Wp319, 318, 240, 0, 0, 0, false, false, false, false, false )
call RegWP( 320, gg_rct_Wp320, 308, 321, 0, 0, 0, false, false, false, false, false )
call RegWP( 321, gg_rct_Wp321, 320, 322, 566, 0, 0, false, false, false, false, false )
call RegWP( 322, gg_rct_Wp322, 321, 323, 0, 0, 0, false, false, false, false, false )
call RegWP( 323, gg_rct_Wp323, 322, 324, 0, 0, 0, false, false, false, false, false )
call RegWP( 324, gg_rct_Wp324, 323, 325, 0, 0, 0, false, false, false, false, false )
call RegWP( 325, gg_rct_Wp325, 324, 326, 0, 0, 0, false, false, false, false, false )
call RegWP( 326, gg_rct_Wp326, 325, 327, 0, 0, 0, false, false, false, false, false )
call RegWP( 327, gg_rct_Wp327, 326, 328, 0, 0, 0, false, false, false, false, false )
call RegWP( 328, gg_rct_Wp328, 327, 329,332, 0, 0, false, false, false, false, false )
call RegWP( 329, gg_rct_Wp329, 328, 330, 0, 0, 0, false, false, false, false, false )
call RegWP( 330, gg_rct_Wp330, 329, 331, 0, 0, 0, false, false, false, false, false )
call RegWP( 331, gg_rct_Wp331, 330, 38, 0, 0, 0, false, false, true, false, false ) // Gate (east)
call RegWP( 332, gg_rct_Wp332, 328, 333, 0, 0, 0, false, false, false, false, false )
call RegWP( 333, gg_rct_Wp333, 332, 334, 0, 0, 0, false, false, false, false, false )
call RegWP( 334, gg_rct_Wp334, 333, 335, 0, 0, 0, false, false, false, false, false )
call RegWP( 335, gg_rct_Wp335, 334, 336, 0, 0, 0, false, false, false, false, false )
call RegWP( 336, gg_rct_Wp336, 335, 337, 0, 0, 0, false, false, false, false, false )
call RegWP( 337, gg_rct_Wp337, 336, 338, 0, 0, 0, false, false, false, false, false )
call RegWP( 338, gg_rct_Wp338, 337, 339, 0, 0, 0, false, false, false, false, false )
call RegWP( 339, gg_rct_Wp339, 338, 340, 0, 0, 0, false, false, false, false, false )
call RegWP( 340, gg_rct_Wp340, 339, 341, 0, 0, 0, false, false, false, false, false )
call RegWP( 341, gg_rct_Wp341, 340, 342, 0, 0, 0, false, false, false, false, false )
call RegWP( 342, gg_rct_Wp342, 341, 343, 0, 0, 0, false, false, false, false, false )
call RegWP( 343, gg_rct_Wp343, 342, 344, 0, 0, 0, false, false, false, false, false )
call RegWP( 344, gg_rct_Wp344, 343, 345, 0, 0, 0, false, false, false, false, false )
call RegWP( 345, gg_rct_Wp345, 344, 346, 0, 0, 0, false, false, false, false, false )
call RegWP( 346, gg_rct_Wp346, 345, 347, 0, 0, 0, false, false, false, false, false )
call RegWP( 347, gg_rct_Wp347, 346, 348, 0, 0, 0, false, false, false, false, false )
call RegWP( 348, gg_rct_Wp348, 347, 349, 0, 0, 0, false, false, false, false, false )
call RegWP( 349, gg_rct_Wp349, 348, 350,358, 0, 0, false, false, false, false, false )
call RegWP( 350, gg_rct_Wp350, 349, 351, 0, 0, 0, false, false, false, false, false )
call RegWP( 351, gg_rct_Wp351, 350, 352, 0, 0, 0, false, false, false, false, false )
call RegWP( 352, gg_rct_Wp352, 351, 353, 0, 0, 0, false, false, false, false, false )
call RegWP( 353, gg_rct_Wp353, 352, 354, 0, 0, 0, false, false, false, false, false )
call RegWP( 354, gg_rct_Wp354, 353, 355, 0, 0, 0, false, false, false, false, false )
call RegWP( 355, gg_rct_Wp355, 354, 356, 0, 0, 0, false, false, false, false, false )
call RegWP( 356, gg_rct_Wp356, 355, 357, 0, 0, 0, false, false, false, false, false )
call RegWP( 357, gg_rct_Wp357, 356, 0, 0, 0, 0, false, false, false, true, false ) // North-East Map Bounds
call RegWP( 358, gg_rct_Wp358, 349, 359, 0, 0, 0, false, false, false, false, false )
call RegWP( 359, gg_rct_Wp359, 358, 360, 0, 0, 0, false, false, false, false, false )
call RegWP( 360, gg_rct_Wp360, 359, 361, 0, 0, 0, false, false, false, false, false )
call RegWP( 361, gg_rct_Wp361, 360, 362, 0, 0, 0, false, false, false, false, false )
call RegWP( 362, gg_rct_Wp362, 361, 363, 0, 0, 0, false, false, false, false, false )
call RegWP( 363, gg_rct_Wp363, 362, 364, 0, 0, 0, false, false, false, false, false )
call RegWP( 364, gg_rct_Wp364, 363, 365, 0, 0, 0, false, false, false, false, false )
call RegWP( 365, gg_rct_Wp365, 364, 366, 0, 0, 0, false, false, false, false, false )
call RegWP( 366, gg_rct_Wp366, 365, 367, 0, 0, 0, false, false, false, false, false )
call RegWP( 367, gg_rct_Wp367, 366, 368, 0, 0, 0, false, false, false, false, false )
call RegWP( 368, gg_rct_Wp368, 367, 369, 0, 0, 0, false, false, false, false, false )
call RegWP( 369, gg_rct_Wp369, 368, 370, 0, 0, 0, false, false, false, false, false )
call RegWP( 370, gg_rct_Wp370, 369, 371, 0, 0, 0, false, false, false, false, false )
call RegWP( 371, gg_rct_Wp371, 370, 372, 0, 0, 0, false, false, false, false, false )
call RegWP( 372, gg_rct_Wp372, 371, 373, 0, 0, 0, false, false, false, false, false )
call RegWP( 373, gg_rct_Wp373, 372, 374, 0, 0, 0, false, false, false, false, false )
call RegWP( 374, gg_rct_Wp374, 373, 375, 0, 0, 0, false, false, false, false, false )
call RegWP( 375, gg_rct_Wp375, 374, 376, 0, 0, 0, false, false, false, false, false )
call RegWP( 376, gg_rct_Wp376, 375, 377, 0, 0, 0, false, false, false, false, false )
call RegWP( 377, gg_rct_Wp377, 376, 378, 0, 0, 0, false, false, false, false, false )
call RegWP( 378, gg_rct_Wp378, 377, 379, 0, 0, 0, false, false, false, false, false )
call RegWP( 379, gg_rct_Wp379, 378, 380, 0, 0, 0, false, false, false, false, false )
call RegWP( 380, gg_rct_Wp380, 379, 381, 0, 0, 0, false, false, false, false, false )
call RegWP( 381, gg_rct_Wp381, 380, 382,385, 0, 0, false, false, false, false, false )
call RegWP( 382, gg_rct_Wp382, 381, 383, 0, 0, 0, false, false, false, false, false )
call RegWP( 383, gg_rct_Wp383, 382, 384, 0, 0, 0, false, false, false, false, false )
call RegWP( 384, gg_rct_Wp384, 383, 25, 0, 0, 0, false, false, true, false, false ) // Gate (North right)
call RegWP( 385, gg_rct_Wp385, 381, 386, 0, 0, 0, false, false, false, false, false )
call RegWP( 386, gg_rct_Wp386, 385, 387, 0, 0, 0, false, false, false, false, false )
call RegWP( 387, gg_rct_Wp387, 386, 388, 0, 0, 0, false, false, false, false, false )
call RegWP( 388, gg_rct_Wp388, 387, 389,403, 0, 0, false, false, false, false, false )
call RegWP( 389, gg_rct_Wp389, 388, 390, 0, 0, 0, false, false, false, false, false )
call RegWP( 390, gg_rct_Wp390, 389, 391, 0, 0, 0, false, false, false, false, false )
call RegWP( 391, gg_rct_Wp391, 390, 392, 0, 0, 0, false, false, false, false, false )
call RegWP( 392, gg_rct_Wp392, 391, 393,422, 0, 0, false, false, false, false, false )
call RegWP( 393, gg_rct_Wp393, 392, 394, 0, 0, 0, false, false, false, false, false )
call RegWP( 394, gg_rct_Wp394, 393, 395,404, 0, 0, false, false, false, false, false )
call RegWP( 395, gg_rct_Wp395, 394, 396, 0, 0, 0, false, false, false, false, false )
call RegWP( 396, gg_rct_Wp396, 395, 397, 0, 0, 0, false, false, false, false, false )
call RegWP( 397, gg_rct_Wp397, 396, 398, 0, 0, 0, false, false, false, false, false )
call RegWP( 398, gg_rct_Wp398, 397, 399, 0, 0, 0, false, false, false, false, false )
call RegWP( 399, gg_rct_Wp399, 398, 400, 0, 0, 0, false, false, false, false, false )
call RegWP( 400, gg_rct_Wp400, 399, 401, 0, 0, 0, false, false, false, false, false )
call RegWP( 401, gg_rct_Wp401, 400, 402, 0, 0, 0, false, false, false, false, false )
call RegWP( 402, gg_rct_Wp402, 401, 403, 0, 0, 0, false, false, false, false, false )
call RegWP( 403, gg_rct_Wp403, 402, 388, 0, 0, 0, false, false, false, false, false )
call RegWP( 404, gg_rct_Wp404, 394, 405, 0, 0, 0, false, false, false, false, false )
call RegWP( 405, gg_rct_Wp405, 404, 406, 0, 0, 0, false, false, false, false, false )
call RegWP( 406, gg_rct_Wp406, 405, 407, 0, 0, 0, false, false, false, false, false )
call RegWP( 407, gg_rct_Wp407, 406, 408, 0, 0, 0, false, false, false, false, false )
call RegWP( 408, gg_rct_Wp408, 407, 409, 0, 0, 0, false, false, false, false, false )
call RegWP( 409, gg_rct_Wp409, 408, 410, 0, 0, 0, false, false, false, false, false )
call RegWP( 410, gg_rct_Wp410, 409, 411, 0, 0, 0, false, false, false, false, false )
call RegWP( 411, gg_rct_Wp411, 410, 412, 0, 0, 0, false, false, false, false, false )
call RegWP( 412, gg_rct_Wp412, 411, 413, 0, 0, 0, false, false, false, false, false )
call RegWP( 413, gg_rct_Wp413, 412, 414, 0, 0, 0, false, false, false, false, false )
call RegWP( 414, gg_rct_Wp414, 413, 415, 0, 0, 0, false, false, false, false, false )
call RegWP( 415, gg_rct_Wp415, 414, 416, 0, 0, 0, false, false, false, false, false )
call RegWP( 416, gg_rct_Wp416, 415, 417, 0, 0, 0, false, false, false, false, false )
call RegWP( 417, gg_rct_Wp417, 416, 418, 545, 0, 0, false, false, false, false, false )
call RegWP( 418, gg_rct_Wp418, 417, 419, 0, 0, 0, false, false, false, false, false )
call RegWP( 419, gg_rct_Wp419, 418, 420, 0, 0, 0, false, false, false, false, false )
call RegWP( 420, gg_rct_Wp420, 419, 421, 0, 0, 0, false, false, false, false, false )
call RegWP( 421, gg_rct_Wp421, 420, 0, 0, 0, 0, false, false, false, true, false )
call RegWP( 422, gg_rct_Wp422, 392, 423, 0, 0, 0, false, false, false, false, false )
call RegWP( 423, gg_rct_Wp423, 422, 424, 0, 0, 0, false, false, false, false, false )
call RegWP( 424, gg_rct_Wp424, 423, 425, 0, 0, 0, false, false, false, false, false )
call RegWP( 425, gg_rct_Wp425, 424, 426, 0, 0, 0, false, false, false, false, false )
call RegWP( 426, gg_rct_Wp426, 425, 427, 556, 0, 0, false, false, false, false, false )
call RegWP( 427, gg_rct_Wp427, 426, 129, 0, 0, 0, false, false, true, false, false ) // Gate (north, left)
call Debug_Message("Northern forest waypoint initialization successfull! ("+I2S(WP_COUNT)+")")
endfunction
private function InitWaypointsForestWest takes nothing returns nothing
//IsSecondary, deadEnd, isGate, isTeleport, preGate
call RegWP( 500, gg_rct_Wp500, 200, 501, 516, 0, 0, false, false, false, false, false ) // Transition to west forest area
call RegWP( 501, gg_rct_Wp501, 500, 502, 0, 0, 0, false, false, false, false, false )
call RegWP( 502, gg_rct_Wp502, 501, 303, 0, 0, 0, false, false, false, false, false )
call RegWP( 503, gg_rct_Wp503, 502, 504, 0, 0, 0, false, false, false, false, false )
call RegWP( 504, gg_rct_Wp504, 503, 505, 0, 0, 0, false, false, false, false, false )
call RegWP( 505, gg_rct_Wp505, 504, 506, 0, 0, 0, false, false, false, false, false )
call RegWP( 506, gg_rct_Wp506, 505, 507, 0, 0, 0, false, false, false, false, false )
call RegWP( 507, gg_rct_Wp507, 506, 508, 0, 0, 0, false, false, false, false, false )
call RegWP( 508, gg_rct_Wp508, 507, 509, 0, 0, 0, false, false, false, false, false )
call RegWP( 509, gg_rct_Wp509, 508, 510, 0, 0, 0, false, false, false, false, false )
call RegWP( 510, gg_rct_Wp510, 509, 511, 0, 0, 0, false, false, false, false, false )
call RegWP( 511, gg_rct_Wp511, 510, 512, 0, 0, 0, false, false, false, false, false )
call RegWP( 512, gg_rct_Wp512, 511, 513, 0, 0, 0, false, false, false, false, false )
call RegWP( 513, gg_rct_Wp513, 512, 514, 517, 0, 0, false, false, false, false, false )
call RegWP( 514, gg_rct_Wp514, 513, 515, 0, 0, 0, false, false, false, false, false )
call RegWP( 515, gg_rct_Wp515, 514, 516, 0, 0, 0, false, false, false, false, false )
call RegWP( 516, gg_rct_Wp516, 500, 515, 0, 0, 0, false, false, false, false, false )
call RegWP( 517, gg_rct_Wp517, 513, 518, 0, 0, 0, false, false, false, false, false )
call RegWP( 518, gg_rct_Wp518, 517, 519, 0, 0, 0, false, false, false, false, false )
call RegWP( 519, gg_rct_Wp519, 518, 520, 0, 0, 0, false, false, false, false, false )
call RegWP( 520, gg_rct_Wp520, 519, 521, 0, 0, 0, false, false, false, false, false )
call RegWP( 521, gg_rct_Wp521, 520, 522, 0, 0, 0, false, false, false, false, false )
call RegWP( 522, gg_rct_Wp522, 521, 523, 0, 0, 0, false, false, false, false, false )
call RegWP( 523, gg_rct_Wp523, 522, 524, 0, 0, 0, false, false, false, false, false )
call RegWP( 524, gg_rct_Wp524, 523, 525, 0, 0, 0, false, false, false, false, false )
call RegWP( 525, gg_rct_Wp525, 524, 526, 0, 0, 0, false, false, false, false, false )
call RegWP( 526, gg_rct_Wp526, 525, 527, 528, 557, 0,false, false, false, false, false )
call RegWP( 527, gg_rct_Wp527, 526, 569, 0, 0, 0, false, false, false, false, false ) // West Gate
call RegWP( 528, gg_rct_Wp528, 526, 529, 0, 0, 0, false, false, false, false, false )
call RegWP( 529, gg_rct_Wp529, 528, 530, 546, 0, 0, false, false, false, false, false )
call RegWP( 530, gg_rct_Wp530, 529, 531, 0, 0, 0, false, false, false, false, false )
call RegWP( 531, gg_rct_Wp531, 530, 532, 0, 0, 0, false, false, false, false, false )
call RegWP( 532, gg_rct_Wp532, 531, 533, 0, 0, 0, false, false, false, false, false )
call RegWP( 533, gg_rct_Wp533, 532, 534, 0, 0, 0, false, false, false, false, false )
call RegWP( 534, gg_rct_Wp534, 533, 535, 0, 0, 0, false, false, false, false, false )
call RegWP( 535, gg_rct_Wp535, 534, 536, 0, 0, 0, false, false, false, false, false )
call RegWP( 536, gg_rct_Wp536, 535, 537, 0, 0, 0, false, false, false, false, false )
call RegWP( 537, gg_rct_Wp537, 536, 538, 0, 0, 0, false, false, false, false, false )
call RegWP( 538, gg_rct_Wp538, 537, 539, 0, 0, 0, false, false, false, false, false )
call RegWP( 539, gg_rct_Wp539, 538, 540, 0, 0, 0, false, false, false, false, false )
call RegWP( 540, gg_rct_Wp540, 539, 541, 0, 0, 0, false, false, false, false, false )
call RegWP( 541, gg_rct_Wp541, 540, 542, 0, 0, 0, false, false, false, false, false )
call RegWP( 542, gg_rct_Wp542, 541, 543, 0, 0, 0, false, false, false, false, false )
call RegWP( 543, gg_rct_Wp543, 542, 544, 0, 0, 0, false, false, false, false, false )
call RegWP( 544, gg_rct_Wp544, 543, 545, 0, 0, 0, false, false, false, false, false )
call RegWP( 545, gg_rct_Wp545, 544, 417, 0, 0, 0, false, false, false, false, false )
call RegWP( 546, gg_rct_Wp546, 529, 547, 0, 0, 0, false, false, false, false, false )
call RegWP( 547, gg_rct_Wp547, 546, 548, 0, 0, 0, false, false, false, false, false )
call RegWP( 548, gg_rct_Wp548, 547, 549, 0, 0, 0, false, false, false, false, false )
call RegWP( 549, gg_rct_Wp549, 548, 550, 0, 0, 0, false, false, false, false, false )
call RegWP( 550, gg_rct_Wp550, 549, 551, 0, 0, 0, false, false, false, false, false )
call RegWP( 551, gg_rct_Wp551, 550, 552, 0, 0, 0, false, false, false, false, false )
call RegWP( 552, gg_rct_Wp552, 551, 553, 0, 0, 0, false, false, false, false, false )
call RegWP( 553, gg_rct_Wp553, 552, 554, 0, 0, 0, false, false, false, false, false )
call RegWP( 554, gg_rct_Wp554, 553, 556, 0, 0, 0, false, false, false, false, false )
call RegWP( 555, gg_rct_Wp555, 554, 557, 0, 0, 0, false, false, false, false, false )
call RegWP( 556, gg_rct_Wp556, 555, 426, 0, 0, 0, false, false, false, false, false )
call RegWP( 557, gg_rct_Wp557, 526, 558, 0, 0, 0, false, false, false, false, false )
call RegWP( 558, gg_rct_Wp558, 557, 559, 0, 0, 0, false, false, false, false, false )
call RegWP( 559, gg_rct_Wp559, 558, 560, 0, 0, 0, false, false, false, false, false )
call RegWP( 560, gg_rct_Wp560, 559, 561, 0, 0, 0, false, false, false, false, false )
call RegWP( 561, gg_rct_Wp561, 560, 562, 0, 0, 0, false, false, false, false, false )
call RegWP( 562, gg_rct_Wp562, 561, 0, 0, 0, 0, false, false, false, true, false ) // Teleport West Side
call RegWP( 563, gg_rct_Wp563, 564, 0, 0, 0, 0, false, false, false, true, false )
call RegWP( 564, gg_rct_Wp564, 563, 565, 0, 0, 0, false, false, false, false, false )
call RegWP( 565, gg_rct_Wp565, 564, 566, 0, 0, 0, false, false, false, false, false )
call RegWP( 566, gg_rct_Wp566, 565, 321, 0, 0, 0, false, false, false, false, false )
call RegWP( 567, gg_rct_Wp567, 90, 568, 0, 0, 0, false, false, false, false, false )
call RegWP( 568, gg_rct_Wp568, 567, 569, 0, 0, 0, false, false, true, false, false )
call RegWP( 569, gg_rct_Wp569, 527, 568, 0, 0, 0, false, false, true, false, false )
call Debug_Message("West forest waypoint initialization successfull! ("+I2S(WP_COUNT)+")")
endfunction
private function InitWPArray takes nothing returns nothing
local integer i = 0
loop
exitwhen i > (MAX_WP-1)
set Waypoints[i] = 0
set i = i + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
local trigger trg2 = CreateTrigger( )
local trigger trg3 = CreateTrigger( )
local trigger trg4 = CreateTrigger( )
local trigger trg5 = CreateTrigger( )
set Teleports = intpool.create()
call Teleports.addInt(562, 1.0)
call Teleports.addInt(258, 1.0)
call Teleports.addInt(357, 1.0)
call Teleports.addInt(421, 1.0)
call Teleports.addInt(563, 1.0)
call TriggerAddAction( trg, function InitWPArray )
call TriggerExecute(trg)
call TriggerAddAction( trg2, function InitWaypointsCity )
call TriggerExecute(trg2)
call TriggerAddAction( trg3, function InitWaypointsForestSouth )
call TriggerExecute(trg3)
call TriggerAddAction( trg4, function InitWaypointsForestNorth )
call TriggerExecute(trg4)
call TriggerAddAction( trg5, function InitWaypointsForestWest )
call TriggerExecute(trg5)
set trg = null
endfunction
endlibrary
//TESH.scrollpos=99
//TESH.alwaysfold=0
scope InitHomes initializer Init
globals
integer array HomeWPs[1]
endglobals
private function RespawnCiviliansConditions takes nothing returns boolean
return CivilianCount < MAX_CIVILIANS
endfunction
private function RespawnCivilians takes nothing returns nothing
local integer i = GetRandomInt(1, HOME_COUNT)
local unit u
local Villager v
// Get random home area
local rect area = Homes[i]
// Set coordinates
local real x = GetRectCenterX(area)
local real y = GetRectCenterY(area)
// Get wp id of this area
local integer wpId = HomeWPs[i]
// call PanCameraToTimed(x, y, 0.5)
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], x, y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, wpId)
call v.addTorch()
set u = null
set area = null
endfunction
private function InitHomeWPs takes nothing returns nothing
set HomeWPs[1] = 3
set HomeWPs[2] = 67
set HomeWPs[3] = 68
set HomeWPs[4] = 98
set HomeWPs[5] = 107
set HomeWPs[6] = 115
set HomeWPs[7] = 117
set HomeWPs[8] = 118
set HomeWPs[9] = 74
set HomeWPs[10] = 60
set HomeWPs[11] = 6
set HomeWPs[12] = 8
set HomeWPs[13] = 10
set HomeWPs[14] = 118
set HomeWPs[15] = 127
set HomeWPs[16] = 18
set HomeWPs[17] = 19
set HomeWPs[18] = 46
set HomeWPs[19] = 40
set HomeWPs[20] = 52
set HomeWPs[21] = 13
set HomeWPs[22] = 47
set HomeWPs[23] = 31
set HomeWPs[24] = 29
set HomeWPs[25] = 42
set HomeWPs[26] = 83
set HomeWPs[27] = 45
set HomeWPs[28] = 42
set HomeWPs[29] = 94
set HomeWPs[30] = 201
set HomeWPs[31] = 404
set HomeWPs[32] = 370
set HomeWPs[33] = 332
set HomeWPs[34] = 249
set HomeWPs[35] = 314
set HomeWPs[36] = 534
endfunction
private function Action takes nothing returns nothing
set Homes[0] = null
set Homes[1] = gg_rct_h1
set Homes[2] = gg_rct_h2
set Homes[3] = gg_rct_h3
set Homes[4] = gg_rct_h4
set Homes[5] = gg_rct_h5
set Homes[6] = gg_rct_h6
set Homes[7] = gg_rct_h7
set Homes[8] = gg_rct_h8
set Homes[9] = gg_rct_h9
set Homes[10] = gg_rct_h10
set Homes[11] = gg_rct_h11
set Homes[12] = gg_rct_h12
set Homes[13] = gg_rct_h13
set Homes[14] = gg_rct_h14
set Homes[15] = gg_rct_h15
set Homes[16] = gg_rct_h16
set Homes[17] = gg_rct_h17
set Homes[18] = gg_rct_h18
set Homes[19] = gg_rct_h19
set Homes[20] = gg_rct_h20
set Homes[21] = gg_rct_h21
set Homes[22] = gg_rct_h22
set Homes[23] = gg_rct_h23
set Homes[24] = gg_rct_h24
set Homes[25] = gg_rct_h25
set Homes[26] = gg_rct_h26
set Homes[27] = gg_rct_h27
set Homes[28] = gg_rct_h28
set Homes[29] = gg_rct_h29
set Homes[30] = gg_rct_h30
set Homes[31] = gg_rct_h31
set Homes[32] = gg_rct_h32
set Homes[33] = gg_rct_h33
set Homes[34] = gg_rct_h34
set Homes[35] = gg_rct_h35
set Homes[36] = gg_rct_h36
set HOME_COUNT = 36
call InitHomeWPs()
call Debug_Message("Homes successfully initialized!")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerAddAction( trg, function Action )
call TriggerExecute(trg)
call DestroyTrigger(trg)
set trg = CreateTrigger( )
call TriggerAddCondition( trg, Condition( function RespawnCiviliansConditions ) )
call TriggerAddAction( trg, function RespawnCivilians )
call TriggerRegisterTimerEvent(trg, 60, true)
set trg = null
endfunction
endscope
//TESH.scrollpos=13
//TESH.alwaysfold=0
//******************************************************************************
//*
//*
scope CreateCivilians initializer Init
// Run at game start
private function Actions takes nothing returns nothing
local integer i = 0
local real x
local real y
local unit u
local Villager v
local integer j
local integer m
// Create pool for possible spawning areas
local intpool vSpawn = intpool.create()
local Waypoint wp
call vSpawn.addInt(1, SPAWN_WEIGHT_CITY) // City
call vSpawn.addInt(2, SPAWN_WEIGHT_FOREST_NORTH) // Forest North
call vSpawn.addInt(3, SPAWN_WEIGHT_FOREST_SOUTH) // Forest South
call vSpawn.addInt(4, SPAWN_WEIGHT_FOREST_WEST) // Forest West
// Create villagers
loop
exitwhen i > (START_CIVILIANS-1)
// Determine spawning area (city, forest north, forest south)
set j = vSpawn.getRandomInt()
// 1: Spawn in city
if j == 1 then
// Waypoints
if GetRandomReal(0, 100) <= CITY_VILLAGER_USES_WP_CHANCE then
set wp = Waypoint.getRandomCity()
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], wp.x, wp.y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, wp.id)
// Some villagers have a torch
if GetRandomReal(0,100) <= TORCH_CHANCE then
call v.addTorch()
endif
// Wandering
else
if GetRandomReal(0, 100) <= PARK_VISIT_CHANCE then
set x = GetRandomReal(GetRectMinX(VillageArea2), GetRectMaxX(VillageArea2))
set y = GetRandomReal(GetRectMinY(VillageArea2), GetRectMaxY(VillageArea2))
else
set x = GetRandomReal(GetRectMinX(VillageArea1), GetRectMaxX(VillageArea1))
set y = GetRandomReal(GetRectMinY(VillageArea1), GetRectMaxY(VillageArea1))
endif
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], x, y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_WANDERING, false, 0)
endif
// 2: Spawn Forest North
elseif j == 2 then
set wp = Waypoint.getRandomForestNorth()
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], wp.x, wp.y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, wp.id)
call v.addTorch()
// 3: Spawn Forest South
elseif j == 3 then
set wp = Waypoint.getRandomForestSouth()
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], wp.x, wp.y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, wp.id)
call v.addTorch()
// 4: Spawn Forest West
elseif j == 4 then
set wp = Waypoint.getRandomForestWest()
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], wp.x, wp.y, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, wp.id)
call v.addTorch()
endif
set i = i + 1
endloop
// Create Villager that approaches town
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], -1780, -4760, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, 222)
call v.addTorch()
// Create Villager that approaches teleport
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), VillagerTypes[GetRandomInt(0,2)], -6679, -3935, bj_UNIT_FACING)
set v = RegisterVillager(u, VILLAGER_STATE_ON_WAYPOINTS, false, 201)
set v.wpCur = 202
call v.addTorch()
call Debug_Message("Civilians created: "+I2S(CivilianCount))
set u = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger()
call TriggerAddAction(trg, function Actions)
call TriggerExecute(trg)
set trg = null
// call Actions ()
endfunction
endscope
//TESH.scrollpos=103
//TESH.alwaysfold=0
scope CreateGuardsStayput initializer Init
globals
private constant integer TOWER_SPOT_COUNT = 11
private rect array TowerSpots[1]
private real array TowerSpotFacing[1]
private integer GUARD_COUNT = 0
private integer GUARD_MAX = 0
private unit array AllGuards[1]
endglobals
private function CreateGuardOnTower takes integer id returns nothing
local unit u
local real x = GetRectCenterX(TowerSpots[id])
local real y = GetRectCenterY(TowerSpots[id])
set u = CreateUnit(Player(11), ARCHER_TOWER, x, y, TowerSpotFacing[id])
call RegisterVillager(u, VILLAGER_STATE_GUARD_HOLDGROUND, true, 0)
set u = null
endfunction
private function RegisterGuardConditions takes nothing returns boolean
return IsGuard(GetFilterUnit())
endfunction
private function InitTowerSpots takes nothing returns nothing
local integer i = 0
// Tower spots
set TowerSpots[1] = gg_rct_TowerSpot1
set TowerSpotFacing[1] = 270
set TowerSpots[2] = gg_rct_TowerSpot2
set TowerSpotFacing[2] = 270
set TowerSpots[3] = gg_rct_TowerSpot3
set TowerSpotFacing[3] = 180
set TowerSpots[4] = gg_rct_TowerSpot4
set TowerSpotFacing[4] = 270
set TowerSpots[5] = gg_rct_TowerSpot5
set TowerSpotFacing[5] = 0
set TowerSpots[6] = gg_rct_TowerSpot6
set TowerSpotFacing[6] = 315
set TowerSpots[7] = gg_rct_TowerSpot7
set TowerSpotFacing[7] = 0
set TowerSpots[8] = gg_rct_TowerSpot8
set TowerSpotFacing[8] = 45
set TowerSpots[9] = gg_rct_TowerSpot9
set TowerSpotFacing[9] = 90
set TowerSpots[10] = gg_rct_TowerSpot10
set TowerSpotFacing[10] = 90
set TowerSpots[11] = gg_rct_TowerSpot11
set TowerSpotFacing[11] = 270
endfunction
// Register all guards which are pre-placed on map
private function RegisterGuardsOnMap takes nothing returns nothing
local group targets = NewGroup()
local unit t = null
local integer i = 0
local integer j = 0
local integer count
// pick all preplaced vampires
call GroupEnumUnitsInRect(targets, bj_mapInitialPlayableArea, Condition(function RegisterGuardConditions))
// Build up an array with all guards
set i = 0
loop
set t = FirstOfGroup(targets)
exitwhen t == null
set AllGuards[i] = t
set GUARD_COUNT = GUARD_COUNT + 1
call GroupRemoveUnit(targets, t)
set i = i + 1
endloop
// How much guards do we need to remove from total pool?
if DEBUG_MODE and MAX_GUARDS then
set GUARD_MAX = GUARD_COUNT
else
set GUARD_MAX = R2I(GUARD_COUNT * GUARD_STAYPUT_COUNT_FACTOR)
endif
// call Debug_Message("Guards usage: "+I2S(GUARD_MAX)+" / "+I2S(GUARD_COUNT) )
// Now remove some guards
set count = GUARD_COUNT
set i = 0
loop
exitwhen i >= (GUARD_COUNT-GUARD_MAX)
set j = GetRandomInt(0,count-1) // Get random guard in array
call RemoveUnit(AllGuards[j]) // and remove him
set AllGuards[j] = AllGuards[count-1] // Now replace him with last aray position
set AllGuards[count-1] = null // Set last position to null
set count = count - 1 // And decrease count
set i = i + 1 // repeat..
endloop
// call Debug_Message("Guard count after cleanup: "+I2S(count))
// Now register everything left
set i = 0
loop
exitwhen i >= count
call RegisterVillager(AllGuards[i], VILLAGER_STATE_GUARD_HOLDGROUND, false, 0)
set AllGuards[i] = null
set i = i + 1
endloop
call ReleaseGroup(targets)
set targets = null
set t = null
// call Debug_Message("VillagerCount: "+I2S(VillagerCount))
// call Debug_Message("Guards on ground successfully registered!")
call Debug_Message("Stayput guards registered. Guards count: "+I2S(GuardCount) )
call InitTowerSpots()
// Create Guard on Towers
set i = 1
loop
exitwhen i > TOWER_SPOT_COUNT
call CreateGuardOnTower(i)
set i = i + 1
endloop
call Debug_Message("Tower guards registered. Guards count: "+I2S(GuardCount) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerAddAction( trg, function RegisterGuardsOnMap )
call TriggerExecute(trg)
call DestroyTrigger(trg)
// set trg = CreateTrigger( )
// call TriggerAddAction( trg, function InitTowerSpots )
// call TriggerExecute(trg)
// call DestroyTrigger(trg)
set trg = null
endfunction
endscope
//TESH.scrollpos=96
//TESH.alwaysfold=0
scope CreateGuardsPatrol initializer Init
globals
private intpool PatrolGuardPool1
private intpool PatrolGuardPool2
private intpool vSpawn
endglobals
private function CreatePatrolGuard takes real x, real y, integer wpId, boolean hasTorch returns nothing
local unit u
local Villager v1
local Villager v2
set u = CreateUnit(Player(11), PatrolGuardPool1.getRandomInt(), x, y, bj_UNIT_FACING)
set v1 = RegisterVillager(u, VILLAGER_STATE_GUARD_PATROL, false, wpId)
if hasTorch then
call v1.addTorch()
endif
// Second unit (optional, escorting)
if GetRandomReal(0, 100) <= ESCORT_CHANCE then
set u = CreateUnit(Player(11), PatrolGuardPool2.getRandomInt(), x, y, bj_UNIT_FACING)
set v2 = RegisterVillager(u, VILLAGER_STATE_GUARD_ESCORT, false, wpId)
set v2.escortTarget = v1
set v1.escort1 = v2
if hasTorch then
call v2.addTorch()
endif
endif
set u = null
endfunction
private function CreatePatrolGuards takes nothing returns nothing
local Waypoint wp
local integer i = 0
local unit u
local Villager v1
local Villager v2
local integer j
local boolean hasTorch = false
loop
exitwhen i > (MAX_PATROL_GUARDS_COUNT-1)
// Determine spawning area
set j = vSpawn.getRandomInt()
// 1: Spawn in city
if j == 1 then
set wp = Waypoint.getRandomCity()
set hasTorch = false
// 2: Forest North
elseif j == 2 then
set wp = Waypoint.getRandomForestNorth()
set hasTorch = true
// 3: Forest South
elseif j == 3 then
set wp = Waypoint.getRandomForestSouth()
set hasTorch = true
// 4: Forest West
elseif j == 4 then
set wp = Waypoint.getRandomForestWest()
set hasTorch = true
endif
// First unit (patrol)
call CreatePatrolGuard(wp.x, wp.y, wp.id, hasTorch)
set i = i + 1
endloop
// High Inquisitor
set wp = Waypoints[16]
set u = CreateUnit(Player(11), INQUISITOR, wp.x, wp.y, bj_UNIT_FACING)
set v1 = RegisterVillager(u, VILLAGER_STATE_GUARD_PATROL, false, wp.id)
set v1.hasTorch = true
call AddSpecialEffectTarget("TinyTorch1.mdl", v1.u, "hand,right")
set u = null
call Debug_Message("Patrolling Guards created. Guards count: "+I2S(GuardCount))
// call Debug_Message("VillagerCount: "+I2S(VillagerCount)+ "("+I2S(CivilianCount)+" Civs, "+I2S(GuardCount)+" Guards)" )
call vSpawn.destroy()
endfunction
private function RespawnPatrolGuardCondition takes nothing returns boolean
return true // PatrolGuardCount < MAX_PATROL_GUARDS_COUNT
endfunction
private function SpawnPatrolGuard takes nothing returns nothing
local Waypoint wp
call Debug_Message("patrol guard count: "+I2S(GuardCountPatrol))
if GuardCountPatrol < MAX_PATROL_GUARDS_COUNT then
set wp = Waypoint.getRandomBorderPoint()
// First unit (patrol)
call CreatePatrolGuard(wp.x, wp.y, wp.id, true)
// call PanCameraToTimed(wp.x, wp.y, 1.0)
call Debug_Message("Patrol Guard respawned!")
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
set PatrolGuardPool1 = intpool.create()
set PatrolGuardPool2 = intpool.create()
// First patrolling guard pool
call PatrolGuardPool1.addInt(GUARD, 1.0) // Forest South
call PatrolGuardPool1.addInt(ARCHER, 0.50) // Forest South
call PatrolGuardPool1.addInt(PRIEST, 0.25) // Forest South
call PatrolGuardPool2.addInt(GUARD, 0.25) // Forest South
call PatrolGuardPool2.addInt(ARCHER, 1.00) // Forest South
call PatrolGuardPool2.addInt(PRIEST, 0.75) // Forest South
set vSpawn = intpool.create()
call vSpawn.addInt(1, SPAWN_WEIGHT_CITY) // City
call vSpawn.addInt(2, SPAWN_WEIGHT_FOREST_NORTH) // Forest North
call vSpawn.addInt(3, SPAWN_WEIGHT_FOREST_SOUTH) // Forest South
call vSpawn.addInt(4, SPAWN_WEIGHT_FOREST_WEST) // Forest West
call TriggerAddAction( trg, function CreatePatrolGuards )
call TriggerExecute(trg)
call DestroyTrigger(trg)
set trg = CreateTrigger( )
call TriggerRegisterTimerEvent(trg, 10.0, true)
call TriggerAddCondition( trg, Condition( function RespawnPatrolGuardCondition ) )
call TriggerAddAction( trg, function SpawnPatrolGuard )
set trg = null
endfunction
endscope
//TESH.scrollpos=206
//TESH.alwaysfold=0
library VampireSystem initializer Init requires HandleTable, BasicFunctions, VillagerSystem, ItemFunctions, VampireSpellSystem, CraftingRecipes
globals
rect array VampireSpawns[1]
private intpool VampSpawnPool
private string array TransformationBar[1]
private constant integer BAR_COUNT = 20
private constant integer VAMPIRE_LEVEL1_STRENGTH = 4
private constant integer VAMPIRE_STRENGTH_PER_LEVEL = 1
private destructable array VampireSpawnCoffins[1]
endglobals
private function RespawnVampire takes integer id returns nothing
local Vampire vamp = id
endfunction
private function Death_Message takes integer playerId, integer playerIdKiller, boolean killerIsHunter returns nothing
if killerIsHunter then
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, PlayerNames[playerId] + " has been killed by "+PlayerNames[playerIdKiller]+" but will arise again soon enough!")
else
call DisplayTimedTextToPlayer( GetLocalPlayer(), 0, 0, 15.00, PlayerNames[playerId] + " has been killed but will arise again soon enough!")
endif
endfunction
private function VampireRevives takes nothing returns nothing
local timer t = GetExpiredTimer()
local Vampire vamp = GetTimerData(t)
call TimerDialogDisplay(ReviveTimerWindows[vamp.playerId], false)
call vamp.revive()
set t = null
endfunction
private function DisplayStrengthBoostTag takes unit u, string s returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.024) // 0184
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1.5)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function DisplayRandomDeathMessage takes integer playerId returns nothing
local integer i = GetRandomInt(0,ShadowDeathMessageCount-1)
call Shadow_Message(playerId, ShadowDeathMessages[i], false)
endfunction
private function DisplayRandomReviveMessage takes integer playerId returns nothing
local integer i = GetRandomInt(0,ShadowReviveMessageCount-1)
call Shadow_Message(playerId, ShadowReviveMessages[i], false)
endfunction
private function VampireDies takes nothing returns nothing
local Vampire vamp = GetHandleData(GetTriggeringTrigger())
local unit killer = GetKillingUnit()
local Villager gua
local effect e = null
// If killer is a guard, let him yell
if IsGuard(killer) then
set gua = GetHandleData(killer)
call CreateShoutTag(gua, GetRandomKillComment())
endif
// Spawn
if vamp.isSpawn then
set e = AddSpecialEffectTarget("BloodExSmall.mdl", vamp.u, "origin")
call RegisterEffect(e,3)
call vamp.destroy()
// Vampire
else
set vamp.isDead = true // Set dead flag
// call Debug_Message("On Vampire Dead event")
// Death Message
call DisplayRandomDeathMessage(vamp.playerId)
// Inc death count
set vamp.deaths = vamp.deaths + 1
// Not near cauldron if dead
set vamp.nearCauldron = false
// Save inventory
call SaveInventory( vamp.u )
// Update score
call IncScoreDeaths(vamp.playerId)
// Disable death trigger
call DisableTrigger(vamp.onDeathTrigger)
if IsHunter(killer) then
call Death_Message(vamp.playerId, GetPlayerId(GetOwningPlayer(killer)), true)
else
call Death_Message(vamp.playerId, GetPlayerId(GetOwningPlayer(killer)), false)
endif
// If transformation in progress, chancel it
if vamp.transformationEnd_timer != null then
call ReleaseTimer(vamp.transformationEnd_timer)
set vamp.transformationEnd_timer = null
endif
// Create timer for first time
if ReviveTimers[vamp.playerId] == null then
set ReviveTimers[vamp.playerId] = NewTimer()
endif
// Create window for first time
if ReviveTimerWindows[vamp.playerId] == null then
set ReviveTimerWindows[vamp.playerId] = CreateTimerDialog(ReviveTimers[vamp.playerId])
call TimerDialogSetTitle(ReviveTimerWindows[vamp.playerId], "|cffFF0000Respawn in:|r")
endif
// Make window visible to player
if (GetLocalPlayer() == Player(vamp.playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call TimerDialogDisplay(ReviveTimerWindows[vamp.playerId], true)
endif
// Start timer to revival
call SetTimerData(ReviveTimers[vamp.playerId], vamp)
call TimerStart(ReviveTimers[vamp.playerId], VAMPIRE_RESPAWN_TIME, false, function VampireRevives )
endif
set e = null
set killer = null
endfunction
private function SixthSense takes nothing returns nothing
local Vampire vamp = GetTimerData(GetExpiredTimer())
local integer i
local unit u
local real uX
local real uY
local real dx
local real dy
local real distance
if not vamp.isDead then
// Loop through hunter players
set i = PLAYER_HUNTERS_START_ID
loop
exitwhen i > PLAYER_HUNTERS_END_ID
if HeroByPlayer[i] != null and GetUnitState(HeroByPlayer[i], UNIT_STATE_LIFE ) > 0 and not (GetUnitAbilityLevel(HeroByPlayer[i], 'Binv') > 0 ) then
// current enemy unit
set u = HeroByPlayer[i]
set uX = GetUnitX(u)
set uY = GetUnitY(u)
// calculate distance
set dx = uX - GetUnitX(vamp.u)
set dy = uY - GetUnitY(vamp.u)
set distance = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == Player(vamp.playerId)) and distance <= SIXTH_SENSE_DISTANCE then
call Shadow_Message(vamp.playerId, "|cffF32F2FBeware!|r A vampire hunter is near by", false)
endif
endif
set i = i + 1
endloop
endif
set u = null
endfunction
private function SpawnAICallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Vampire vamp = GetTimerData(t)
local real x
local real y
set t = null
// If staying, keep on moving
if GetUnitCurrentOrder(vamp.u) == 0 then
if GetRandomReal(0, 100) <= PARK_VISIT_CHANCE then
set x = GetRandomReal(GetRectMinX(VillageArea2), GetRectMaxX(VillageArea2))
set y = GetRandomReal(GetRectMinY(VillageArea2), GetRectMaxY(VillageArea2))
else
set x = GetRandomReal(GetRectMinX(VillageArea1), GetRectMaxX(VillageArea1))
set y = GetRandomReal(GetRectMinY(VillageArea1), GetRectMaxY(VillageArea1))
endif
call IssuePointOrder(vamp.u, "attack", x, y)
endif
endfunction
private function ReactivateSpawn takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer i = GetTimerData(t)
call ReleaseTimer(t)
set t = null
call VampSpawnPool.addInt(i, 1.0)
// Play Coffin morph animation
call QueueDestructableAnimation(VampireSpawnCoffins[i], "Morph Alternate")
call QueueDestructableAnimation(VampireSpawnCoffins[i], "Stand")
endfunction
function CheckOutVampireRespawn takes nothing returns integer
local integer i
local timer t = NewTimer()
if DEBUG_MODE and FORCE_TEST_SPAWN then
set i = TEST_SPAWN
else
set i = VampSpawnPool.getRandomInt()
endif
// Play Coffin morph animation
call QueueDestructableAnimation(VampireSpawnCoffins[i], "Morph")
call QueueDestructableAnimation(VampireSpawnCoffins[i], "Stand, Alternate")
call VampSpawnPool.removeInt(i)
call SetTimerData(t, i)
call TimerStart(t, 8, false, function ReactivateSpawn)
set t = null
return i
endfunction
private function UIChancelPlayer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer playerId = GetTimerData(t)
call ReleaseTimer(t)
set t = null
if (GetLocalPlayer() == Player(playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ForceUICancel()
endif
endfunction
private function UpdateTransformationBar takes integer v returns nothing
local Vampire vamp = v
local texttag t = CreateTextTag()
local integer i
local real x = GetUnitX(vamp.u)
local real y = GetUnitY(vamp.u)
call Debug_Message("transTicks: "+I2S(vamp.transTicks)+" | "+ "transTickMax: "+I2S(vamp.transTicksMax))
set i = R2I( ( I2R(vamp.transTicks)/I2R(vamp.transTicksMax) ) * I2R(BAR_COUNT) )
call Debug_Message("i: "+I2S(i))
call SetTextTagText(t, TransformationBar[i], 0.0184)
call SetTextTagPosUnit(t, vamp.u, 0)
// call SetTextTagPos(t, x, y-64, 0.00)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1)
call SetTextTagPermanent(t, false)
if Player(vamp.playerId) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function TimedTransformationCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Vampire vamp = GetTimerData(t)
local effect e = null
if ( GetUnitTypeId(vamp.u) != BAT and GetUnitTypeId(vamp.u) != VAMPIRE_VILLAGER ) or vamp.inTransformation then
call ReleaseTimer(t)
set vamp.transformationEnd_timer = null
else
set vamp.transTicks = vamp.transTicks - 1
call UpdateTransformationBar(vamp)
if vamp.transTicks <= 0 then
call ReleaseTimer(t)
set vamp.transformationEnd_timer = null
set vamp.newForm = VAMPIRE
call vamp.changeForm(vamp.newForm)
call SetUnitAnimation(vamp.u, "slam")
call QueueUnitAnimation(vamp.u, "stand")
set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", vamp.u, "origin")
call DestroyEffect(e)
endif
endif
set e = null
set t = null
endfunction
struct Vampire
unit u = null
boolean inTransformation = false
boolean isDead = false
boolean isSpawn = false
integer newForm = 0
timer transformation_timer = null
timer transformationEnd_timer = null
timer ai_timer = null
trigger onDeathTrigger = null
integer castBar = 0
integer playerId = 0
integer deaths = 0
integer transTicks = 0
integer transTicksMax = 0
boolean nearCauldron = false
integer array ingredients[INGREDIENTS_MAX_PLUS_ONE]
boolean array spells[VAMPIRE_SPELL_COUNT_PLUS_ONE]
boolean overlord = false
timer senseTimer = null
boolean hasSense = false
integer levelupPoints = 0
integer level = 1
integer strengthBonus = 0
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
local CastBar bar
local integer i
set this.u = u // Save unit in struct
call SetHandleData(this.u, this) // Save struct id in Table for unit handle
set this.playerId = GetPlayerId(GetOwningPlayer(u)) // Save owning player in struct
call UnitShareVision(this.u, Player(SHADOW_PLAYER_ID), true) // Share vision with Shadow
set this.level = 1
// Check if spawn
if GetUnitTypeId(this.u) == SPAWN then
set this.isSpawn = true
endif
// Cast bar
if not this.isSpawn then
set bar = CastBar.create()
set bar.zOffset = BAR_Z_OFFSET
set bar.color = PLAYER_COLOR_PURPLE
set bar.target = this.u
call bar.show(false)
set this.castBar = bar
endif
// On death trigger
// =====================================
set this.onDeathTrigger = CreateTrigger() // Create death trigger
call TriggerRegisterUnitEvent( this.onDeathTrigger, this.u, EVENT_UNIT_DEATH ) // Register death event
call SetHandleData(this.onDeathTrigger, this) // Register struct id for trigger handle
call TriggerAddAction( this.onDeathTrigger, function VampireDies) // Add action
// If spawn
if this.isSpawn then
set this.isSpawn = true
set this.ai_timer = NewTimer()
call SetTimerData(this.ai_timer, this)
// Start AI timer
call TimerStart(this.ai_timer, AI_REFRESH_INTERVAL, true, function SpawnAICallback)
// If Vampire
else
call UnitAddType(this.u, UNIT_TYPE_PEON)
set this.levelupPoints = this.levelupPoints + 1
endif
//if this.playerId == 0 then
// call Debug_Message("Vampire registered; id: |cffFF0000"+I2S(this)+"|r"+ "("+PlayerNames[playerId]+")")
//else
// call Debug_Message("Vampire registered; id: "+I2S(this)+ "("+PlayerNames[playerId]+")")
//endif
// init ingredient array
set i = 1
loop
exitwhen i > INGREDIENTS_MAX
set this.ingredients[i] = 0
set i = i + 1
endloop
// init spell array
set i = 2
loop
exitwhen i > VAMPIRE_SPELL_COUNT
set this.spells[i] = false
set i = i + 1
endloop
set HeroStructIdByPlayer[this.playerId] = this
set HeroByPlayer[this.playerId] = this.u
return this
endmethod
public method SetIngredientAbilities takes nothing returns nothing
local integer i
// Update ingredients information
set i = 1
loop
exitwhen i > INGREDIENTS_MAX
call SetUnitAbilityLevel( this.u, IngredientInfoAbilities[i], this.ingredients[i]+1)
set i = i + 1
endloop
// Update alchemy spells
set i = 1
loop
exitwhen i > CRAFTING_RECIPES_MAX
if GetUnitAbilityLevel( this.u, CraftAbilities[i] ) >= 1 then
if CheckIngredientsAvailable(this, i) then
call SetUnitAbilityLevel( this.u, CraftAbilities[i], 2)
else
call SetUnitAbilityLevel( this.u, CraftAbilities[i], 1)
endif
endif
set i = i + 1
endloop
endmethod
public method getIngredientCount takes integer i returns integer
return this.ingredients[i]
endmethod
public method incIngredient takes integer id returns nothing
local string s
local integer i
set this.ingredients[id] = this.ingredients[id] + 1
call Debug_Message("ingredient incremented "+IngrediantNames[id]+ " new count: "+I2S(this.ingredients[id]))
call this.SetIngredientAbilities()
set i = 1
set s = " "
loop
exitwhen i > INGREDIENTS_MAX
set s = s + " " + I2S(this.ingredients[i])
set i = i + 1
endloop
call Debug_Message(s)
endmethod
public method decIngredient takes integer id returns nothing
set this.ingredients[id] = this.ingredients[id] - 1
call this.SetIngredientAbilities()
endmethod
public method addStrengthBonus takes integer i returns nothing
set this.strengthBonus = this.strengthBonus + i
call SetHeroStr(this.u, GetHeroStr(this.u, false)+i, true)
call DisplayStrengthBoostTag(this.u, "|cffF95252+1 hero strength!|r")
endmethod
public method setHeroStrength takes nothing returns nothing
call SetHeroStr(this.u, GetHeroStr(this.u, false)+this.strengthBonus, true)
endmethod
public method toggleSixthSense takes boolean activate returns nothing
// Activate tracker
if not this.hasSense and activate then
call Debug_Message("activating 6th sense")
set this.hasSense = activate
set this.senseTimer = NewTimer()
call SetTimerData(this.senseTimer, this)
call TimerStart(this.senseTimer, SIXTH_SENSE_INTERVAL, true, function SixthSense)
// Deactivate
elseif this.hasSense and activate == false then
set this.hasSense = activate
call ReleaseTimer(this.senseTimer)
set this.senseTimer = null
endif
endmethod
public method clearLearnPool takes nothing returns nothing
local integer i
local integer wrapperAbility
set i = 1
loop
exitwhen i > VAMPIRE_SPELL_COUNT
set wrapperAbility = GetSpellLearnWrapper(i)
// if spell can be learned and ability level of wrapper > 0
if wrapperAbility != 0 and GetUnitAbilityLevel(this.u, wrapperAbility) > 0 then
call UnitRemoveAbility(this.u, wrapperAbility)
endif
set i = i + 1
endloop
endmethod
private method AddAbilityWrapper takes integer abilityId returns nothing
call UnitAddAbility(this.u, abilityId)
call SetPlayerAbilityAvailable(Player(this.playerId), abilityId, false)
endmethod
public method addSpell takes integer id, boolean skillPointsLeft returns nothing
// If spell is learned
if this.spells[id] then
// Add it to the spellbook if in vampire or overlord form
if GetUnitTypeId(this.u) == VAMPIRE or GetUnitTypeId(this.u) == OVERLORD then
call this.AddAbilityWrapper( GetSpellWrapper(id) )
endif
// If not already learned if not learned
else
// If skill points left and hero level is sufficient
if skillPointsLeft and GetHeroLevel(this.u) >= GetSpellMinLevel(id) and SpellCanBeLearned(id) then
call this.AddAbilityWrapper( GetSpellLearnWrapper(id) )
endif
endif
endmethod
// Set proper abilities for unit
public method addAbilities takes nothing returns nothing
local boolean skillPointsLeft = false
local integer i = 0
// Always Add transformation container
call UnitAddAbility(this.u, SPELL_CONTAINER_TRANSFORMATION)
// If level points are available
if this.levelupPoints > 0 then
// set flag
set skillPointsLeft = true
// Add learn container
call UnitAddAbility(this.u, SPELL_CONTAINER_LEARN_ABILITIES)
// Set container level
call SetUnitAbilityLevel(this.u, SPELL_CONTAINER_LEARN_ABILITIES, this.levelupPoints)
// clear pool (to make it ready ot be build up again)
call this.clearLearnPool()
// No level up points available
else
// set flag
set skillPointsLeft = false
// if learn ability pool is there, remove now
if GetUnitAbilityLevel(this.u, SPELL_CONTAINER_LEARN_ABILITIES) > 0 then
call UnitRemoveAbility(this.u, SPELL_CONTAINER_LEARN_ABILITIES)
endif
endif
// Add Ingredients, Spells and Passive Abilities for Vampire, Overlord and Villager form
// =============================================================
// Container abilities
if GetUnitTypeId(this.u) == VAMPIRE or GetUnitTypeId(this.u) == OVERLORD or GetUnitTypeId(this.u) == VAMPIRE_VILLAGER then
// Add ingredient abilities
call this.SetIngredientAbilities()
// Add spell container
call UnitAddAbility(this.u, SPELL_CONTAINER_VAMP_SPELLS)
// Add passive abilty container
call UnitAddAbility(this.u, SPELL_CONTAINER_PASSIVE)
endif
// Form specific stuff
// =============================================================
// Vampire Form
if GetUnitTypeId(this.u) == VAMPIRE then
// Add suck blood ability
call UnitAddAbility(this.u, SPELL_ID_SUCK_BLOOD)
// Add vampire form info
call this.AddAbilityWrapper(SPELL_WRAPPER_VAMPIRE_FORM_INFO)
// All other forms
else
// Add vampire form abilitiy
call this.AddAbilityWrapper(SPELL_WRAPPER_VAMPIRE_FORM)
if GetUnitTypeId(this.u) == OVERLORD then
call this.AddAbilityWrapper(SPELL_WRAPPER_CLEAVING_ATTACK)
endif
endif
// Rat Form learned
// =============================================================
if this.spells[SPELL_RAT_FORM] then
// If player is currently in rat form add info
if GetUnitTypeId(this.u) == RAT then
call this.AddAbilityWrapper(SPELL_WRAPPER_RAT_FORM_INFO)
// Improved rat form?
if this.spells[SPELL_RAT_FORM_LV2] then
call UnitAddAbility(this.u, 'A02E') // Rat evasion
call SetUnitMoveSpeed(this.u, 168) // 140 is normal rat speed
endif
// Add rat form ability
else
call this.AddAbilityWrapper(SPELL_WRAPPER_RAT_FORM)
endif
if skillPointsLeft and not this.spells[SPELL_RAT_FORM_LV2] then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_RAT_FORM_LV2)
endif
// Rat form not yet learned
else
// Still points available and min level reached?
if skillPointsLeft and GetHeroLevel(this.u) >= SPELL_MIN_LEVEL_RAT_FORM then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_RAT_FORM)
endif
endif
// Wolf Form
// =============================================================
if this.spells[SPELL_WOLF_FORM] then
// If player is currently in wolf form add info
if GetUnitTypeId(this.u) == WOLF then
call this.AddAbilityWrapper(SPELL_WRAPPER_WOLF_FORM_INFO)
// Improved rat form?
if this.spells[SPELL_WOLF_FORM_LV2] then
call UnitAddAbility(this.u, 'A02I')
endif
// Add wolf form ability
else
call this.AddAbilityWrapper(SPELL_WRAPPER_WOLF_FORM)
endif
if skillPointsLeft and not this.spells[SPELL_WOLF_FORM_LV2] then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_WOLF_FORM_LV2)
endif
// Wolf form not yet learned
else
// Still points available and min level reached?
if skillPointsLeft and GetHeroLevel(this.u) >= SPELL_MIN_LEVEL_WOLF_FORM then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_WOLF_FORM)
endif
endif
// Bat Form
// =============================================================
if this.spells[SPELL_BAT_FORM] then
// If player is currently in rat form add info
if GetUnitTypeId(this.u) == BAT then
call this.AddAbilityWrapper(SPELL_WRAPPER_BAT_FORM_INFO)
// Improved rat form?
if this.spells[SPELL_BAT_FORM_LV2] then
// add evasion here
endif
// Add bat form ability
else
call this.AddAbilityWrapper(SPELL_WRAPPER_BAT_FORM)
endif
if skillPointsLeft and not this.spells[SPELL_BAT_FORM_LV2] then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_BAT_FORM_LV2)
endif
// Rat form not yet learned
else
// Still points available and min level reached?
if skillPointsLeft and GetHeroLevel(this.u) >= SPELL_MIN_LEVEL_BAT_FORM then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_BAT_FORM)
endif
endif
// Overlord Form
// =============================================================
if this.spells[SPELL_OVERLORD_FORM] then
// If player is currently in rat form add info
if GetUnitTypeId(this.u) == OVERLORD then
call this.AddAbilityWrapper(SPELL_WRAPPER_OVERLORD_FORM_INFO)
// Add demon form ability
else
call this.AddAbilityWrapper(SPELL_WRAPPER_OVERLORD_FORM)
endif
// Demon form not yet learned
else
// Still points available and min level reached?
if skillPointsLeft and GetHeroLevel(this.u) >= SPELL_MIN_LEVEL_OVERLORD_FORM then // if not learned
call this.AddAbilityWrapper(LEARN_WRAPPER_OVERLORD_FORM)
endif
endif
// Activate 6th sense
if spells[SPELL_6TH_SENSE] and hasSense == false then
call this.toggleSixthSense(true)
endif
// Add active spells and passive abilitites
// =============================================================
set i = SPELL_SENTRY_WARD // Use ID of first non-transformation spell here!
loop
exitwhen i > VAMPIRE_SPELL_COUNT
call this.addSpell(i, skillPointsLeft)
set i = i + 1
endloop
endmethod
private method setSize takes nothing returns nothing
call SetUnitScale(this.u, 1.0+(this.level*VAMPIRE_LEVEL_SIZE_SCALE_INC), 1.0+(this.level*VAMPIRE_LEVEL_SIZE_SCALE_INC), 1.0+(this.level*VAMPIRE_LEVEL_SIZE_SCALE_INC))
endmethod
public method incLevel takes nothing returns nothing
set this.level = this.level + 1
set this.levelupPoints = this.levelupPoints + 1
call this.setSize()
call this.addAbilities()
endmethod
public method toggleOverlord takes boolean switch returns nothing
local integer i = 0
if switch then
set this.overlord = true
set this.spells[SPELL_OVERLORD_FORM] = true
set OverlordPlayer = this.playerId
call ShareVision(u, 0, 5, true)
else
set this.overlord = false
set this.spells[SPELL_OVERLORD_FORM] = false
endif
call this.addAbilities()
endmethod
public method changeForm takes integer newForm returns nothing
local real health_percent = GetUnitState(this.u, UNIT_STATE_LIFE)/GetUnitState(this.u, UNIT_STATE_MAX_LIFE)
local real mana_percent = GetUnitState(this.u, UNIT_STATE_MANA)/GetUnitState(this.u, UNIT_STATE_MAX_MANA)
local real x = GetUnitX(this.u)
local real y = GetUnitY(this.u)
local real facing = GetUnitFacing(this.u)
local integer level = GetHeroLevel(this.u)
local integer XP = GetHeroXP(this.u)
local integer playerId = this.playerId
local CastBar bar = this.castBar
local timer t
// Save inventory
call SaveInventory( this.u )
// Remove old form
call ReleaseHandleData( this.u )
call RemoveUnit(this.u)
// Remove old death trigger
call ReleaseHandleData( this.onDeathTrigger )
call DestroyTrigger(this.onDeathTrigger)
// CreateNewForm
set this.u = CreateUnit(Player(playerId), newForm, x, y, facing)
call SetHandleData(this.u, this)
call SetHeroLevelBJ(this.u, level, false)
call SetHeroXP(this.u, XP, false)
set HeroByPlayer[this.playerId] = this.u
call SetUnitTimeScale(this.u, 1.0)
// Register for damage detection
call StructuredDD.add(this.u)
// Load inventory
call LoadInventory( this.u )
if newForm == VAMPIRE then
call UnitAddType(this.u, UNIT_TYPE_PEON)
endif
// call IssueImmediateOrder(this.u, "holdposition")
call PauseUnit(this.u, true) // this is necessary to prevent the morphed unit from attacking nearby enemies
call PauseUnit(this.u, false)
if newForm != GHOST then
call SetUnitState(this.u, UNIT_STATE_LIFE, GetUnitState(this.u, UNIT_STATE_MAX_LIFE)*health_percent )
call SetUnitState(this.u, UNIT_STATE_MANA, GetUnitState(this.u, UNIT_STATE_MAX_MANA)*mana_percent )
endif
call UnitShareVision(this.u, Player(SHADOW_PLAYER_ID), true)
// Create new onDeath trigger
set this.onDeathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent( this.onDeathTrigger, this.u, EVENT_UNIT_DEATH )
call SetHandleData(this.onDeathTrigger, this)
call TriggerAddAction( this.onDeathTrigger, function VampireDies)
set bar.target = this.u
if newForm == RAT or newForm == VAMPIRE_VILLAGER then
call SetPlayerAllianceStateBJ( Player(11), Player(playerId), bj_ALLIANCE_NEUTRAL )
else
call SetPlayerAllianceStateBJ( Player(11), Player(playerId), bj_ALLIANCE_UNALLIED )
endif
if newForm == VAMPIRE or newForm == WOLF or newForm == OVERLORD or newForm == VAMPIRE_VILLAGER then
call this.setHeroStrength()
endif
if newForm == VAMPIRE or newForm == WOLF then
call this.setSize()
endif
call this.addAbilities()
if (GetLocalPlayer() == Player(playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ClearSelection()
call SelectUnit(this.u, true)
endif
set t = NewTimer()
call SetTimerData(t, playerId)
call TimerStart(t, 0.1, false, function UIChancelPlayer)
set t = null
// Bat Form
if newForm == BAT then
if this.spells[SPELL_BAT_FORM_LV2] then
set this.transTicksMax = 40
else
set this.transTicksMax = 20
endif
set this.transTicks = this.transTicksMax
set this.transformationEnd_timer = NewTimer()
call SetTimerData(this.transformationEnd_timer, this)
call TimerStart(this.transformationEnd_timer, 1.0, true, function TimedTransformationCallback )
endif
// Villager Form
if newForm == VAMPIRE_VILLAGER then
call AddSpecialEffectTarget("TinyTorch1.mdl", this.u, "hand,left")
call SetUnitMoveSpeed(this.u, CIVILIAN_MOVE_SPEED_NORMAL)
call SetUnitTimeScale(this.u, 3.0)
call UnitAddAbility(this.u, 'Abun')
set this.transTicksMax = 180
set this.transTicks = this.transTicksMax
set this.transformationEnd_timer = NewTimer()
call SetTimerData(this.transformationEnd_timer, this)
call TimerStart(this.transformationEnd_timer, 1.0, true, function TimedTransformationCallback )
endif
if OverlordPlayer == this.playerId then
call ShareVision(u, 0, 5, true)
endif
call Debug_Message("Form changed!")
endmethod
public method revive takes nothing returns nothing
local integer i = CheckOutVampireRespawn()
local real x = GetRectCenterX(VampireSpawns[i])
local real y = GetRectCenterY(VampireSpawns[i])
local effect e
set this.isDead = false
set this.nearCauldron = false
call ReviveHero(this.u, x, y, false)
if (GetLocalPlayer() == Player(this.playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ClearSelection()
call SelectUnit(this.u, true)
endif
set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", this.u, "origin")
call DestroyEffect(e)
set e = null
call PanCameraToTimedForPlayer(Player(this.playerId), x, y, 0.5)
// Revive Message
call DisplayRandomReviveMessage(this.playerId)
// Reload inventory
call LoadInventory(this.u)
// Enable onDeath trigger
call EnableTrigger(this.onDeathTrigger)
// Vampire form
if GetUnitTypeId(this.u) != VAMPIRE then
call this.changeForm(VAMPIRE)
endif
endmethod
public method destroy takes nothing returns nothing
// Remove unit handle id from table
if this.u != null then
call ReleaseHandleData( this.u )
set this.u = null
endif
// Destroy death trigger
if this.onDeathTrigger != null then
call ReleaseHandleData( this.onDeathTrigger )
call DestroyTrigger(this.onDeathTrigger)
set this.onDeathTrigger = null
endif
// Release timers
if this.transformation_timer != null then
call ReleaseTimer(this.transformation_timer)
set this.transformation_timer = null
endif
// Release timers
if this.transformationEnd_timer != null then
call ReleaseTimer(this.transformationEnd_timer)
set this.transformationEnd_timer = null
endif
if this.ai_timer != null then
call ReleaseTimer(this.ai_timer)
set this.ai_timer = null
endif
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
private function VampireDamagedEvent takes nothing returns nothing
local Vampire vamp = GetHandleData(GetTriggerUnit())
local integer i
// call Debug_Message("Vampire takes damage event |"+ GetUnitName(GetTriggerUnit()) )
endfunction
function RegisterVampire takes unit u returns integer
local Vampire vamp
// Throw double registration warning
if GetHandleData(u) != 0 then
call Debug_Message("|cffFF0000Error:|r Double registration of vampire!")
endif
// Create struct data
set vamp = Vampire.create(u)
set vamp.spells[SPELL_SENTRY_WARD] = true
set vamp.spells[SPELL_6TH_SENSE] = true
// Add abilitites
call vamp.addAbilities()
if DEBUG_MODE then
set vamp.levelupPoints = START_SKILL_POINTS
endif
// Damage Detection
call StructuredDD.add(u)
return vamp
endfunction
// This creates all possible blood bar positions
private function InitTransformationBar takes nothing returns nothing
local integer i = 0
local integer j = 0
// Create empty string array
set i = 0
loop
exitwhen i > BAR_COUNT
set TransformationBar[i] = ""
set i = i + 1
endloop
// Now loop through positions 0 .. BAR_COUNT
set i = 0
loop
exitwhen i > BAR_COUNT
// Red fiels (as much as i)
set j = 1
loop
exitwhen j > i
set TransformationBar[i] = TransformationBar[i] + "|cff"+BAR_COLOR_BLUE+"|"+"|"
set j = j + 1
endloop
// grey (BAR_COUNT - i)
set j = 1
loop
exitwhen j > BAR_COUNT-i
set TransformationBar[i] = TransformationBar[i] + "|cff"+BAR_COLOR_DARK+"|"+"|"
set j = j + 1
endloop
set TransformationBar[i] = TransformationBar[i] + "|r"
set i = i + 1
endloop
endfunction
private function InitVampireSystem takes nothing returns nothing
local integer i
set VampSpawnPool = intpool.create()
set VampireSpawns[0] = null
set VampireSpawns[1] = gg_rct_VampireSpawn1
set VampireSpawns[2] = gg_rct_VampireSpawn2
set VampireSpawns[3] = gg_rct_VampireSpawn3
set VampireSpawns[4] = gg_rct_VampireSpawn4
set VampireSpawns[5] = gg_rct_VampireSpawn5
set VampireSpawns[6] = gg_rct_VampireSpawn6
set VampireSpawns[7] = gg_rct_VampireSpawn7
set VampireSpawns[8] = gg_rct_VampireSpawn8
set VampireSpawns[9] = gg_rct_VampireSpawn9
set VampireSpawns[10] = gg_rct_VampireSpawn10
set VampireSpawns[11] = gg_rct_VampireSpawn11
set VampireSpawns[12] = gg_rct_VampireSpawn12
set VampireSpawns[13] = gg_rct_VampireSpawn13
call VampSpawnPool.addInt(1, 1.0)
call VampSpawnPool.addInt(2, 1.0)
call VampSpawnPool.addInt(3, 1.0)
call VampSpawnPool.addInt(4, 1.0)
call VampSpawnPool.addInt(5, 1.0)
call VampSpawnPool.addInt(6, 1.0)
call VampSpawnPool.addInt(7, 1.0)
call VampSpawnPool.addInt(8, 1.0)
call VampSpawnPool.addInt(9, 1.0)
call VampSpawnPool.addInt(10, 1.0)
call VampSpawnPool.addInt(11, 1.0)
call VampSpawnPool.addInt(12, 1.0)
call VampSpawnPool.addInt(13, 1.0)
set VampireSpawnCoffins[1] = gg_dest_B009_3096
set VampireSpawnCoffins[2] = gg_dest_B009_3097
set VampireSpawnCoffins[3] = gg_dest_B009_3098
set VampireSpawnCoffins[4] = gg_dest_B009_3099
set VampireSpawnCoffins[5] = gg_dest_B009_3100
set VampireSpawnCoffins[6] = gg_dest_B009_3101
set VampireSpawnCoffins[7] = gg_dest_B009_2038
set VampireSpawnCoffins[8] = gg_dest_B009_3103
set VampireSpawnCoffins[9] = gg_dest_B009_3102
set VampireSpawnCoffins[10] = gg_dest_B009_5293
set VampireSpawnCoffins[11] = gg_dest_B009_5301
set VampireSpawnCoffins[12] = gg_dest_B009_5299
set VampireSpawnCoffins[13] = gg_dest_B009_5297
set i = 0
loop
exitwhen i > 12
set ReviveTimers[i] = null
set ReviveTimerWindows[i] = null
set i = i + 1
endloop
call InitTransformationBar()
call StructuredDD.addHandler(function VampireDamagedEvent)
call Debug_Message("Vampire stuff initialization successful!")
endfunction
private function VampireKillsConditions takes nothing returns boolean
return IsPlayerInForce( GetOwningPlayer(GetKillingUnit()), ForceVampires )
endfunction
private function VampireKills takes nothing returns nothing
local unit u = GetKillingUnit()
local unit t = GetDyingUnit()
local integer playerId = GetPlayerId( GetOwningPlayer(u) )
local Vampire vampKiller = GetHandleData(u)
local Vampire vampTarget
local Hunter hunterTarget
call IncScoreKills(playerId)
// Vampires kills hunter
if IsHunter(t) then
// Inc pvp score
call IncScorePvP(playerId)
// Inc strength
call vampKiller.addStrengthBonus(1)
// Get target object
set hunterTarget = GetHandleData(t)
// Message
// call Game_Message(PlayerNames[vampKiller.playerId]+" has killed "+PlayerNames[hunterTarget.playerId] )
endif
// Vampire kills another vampire
if IsPlayerVampiric(t) then
// Inc pvp score
call IncScorePvP(playerId)
// Inc strength
call vampKiller.addStrengthBonus(1)
// Get target object
set vampTarget = GetHandleData(t)
// Message
// call Game_Message(PlayerNames[vampKiller.playerId]+" has killed "+PlayerNames[vampTarget.playerId] )
// If killed vamp was overlord
if vampTarget.overlord then
// Deactivte overlord for killed unit
call vampTarget.toggleOverlord(false)
// Activte overlord for killer
call vampKiller.toggleOverlord(true)
// Show message
call Game_Message("Beware! "+PlayerNames[vampKiller.playerId]+" has become the new Overlord!")
endif
endif
set u = null
set t = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( trg, Condition( function VampireKillsConditions ) )
call TriggerAddAction( trg, function VampireKills )
set trg = CreateTrigger()
call TriggerAddAction(trg, function InitVampireSystem)
call TriggerExecute(trg)
call DestroyTrigger(trg)
set trg = null
endfunction
endlibrary
//TESH.scrollpos=24
//TESH.alwaysfold=0
library VampireSpellSystem initializer Init requires BasicFunctions
globals
private integer array Spells[1]
private integer array SpellWrappers[1]
private integer array LearnAbilities[1]
private integer array LearnWrappers[1]
private integer array MinLevels[1]
private boolean array IsLearnWrapper[1]
// integer VampireSpellCount = 0
Table VampireLearnSpells
Table VampireLearnSpellsIdLink
// All Spells
constant integer SPELL_VAMPIRE_FORM = 1 // Transformation stuff
constant integer SPELL_RAT_FORM = 2
constant integer SPELL_WOLF_FORM = 3
constant integer SPELL_BAT_FORM = 4
constant integer SPELL_OVERLORD_FORM = 5
constant integer SPELL_RAT_FORM_LV2 = 6
constant integer SPELL_WOLF_FORM_LV2 = 7
constant integer SPELL_BAT_FORM_LV2 = 8
constant integer SPELL_SENTRY_WARD = 9 // Active spells (Make sure Sentry Ward is always the first!)
constant integer SPELL_BAT_SWARM = 10
constant integer SPELL_FEAR = 11
constant integer SPELL_LIGHTNING = 12
constant integer SPELL_VAMPIRIC_AURA = 13 // Passive spells
constant integer SPELL_EVASION = 14
constant integer SPELL_SHADOW_MELD = 15
constant integer SPELL_FAST_TRANSFORM = 16
constant integer SPELL_6TH_SENSE = 17
constant integer SPELL_CLEAVING_ATTACK = 18 // (Overlord form only)
constant integer SPELL_MANA_SHIELD = 19
constant integer VAMPIRE_SPELL_COUNT = 19
constant integer VAMPIRE_SPELL_COUNT_PLUS_ONE = 20
// Min levels
constant integer SPELL_MIN_LEVEL_VAMPIRE_FORM = 0
constant integer SPELL_MIN_LEVEL_RAT_FORM = 1
constant integer SPELL_MIN_LEVEL_WOLF_FORM = 1
constant integer SPELL_MIN_LEVEL_BAT_FORM = 4
constant integer SPELL_MIN_LEVEL_OVERLORD_FORM = 99
constant integer SPELL_MIN_LEVEL_RAT_FORM_LV2 = 2
constant integer SPELL_MIN_LEVEL_WOLF_FORM_LV2 = 2
constant integer SPELL_MIN_LEVEL_BAT_FORM_LV2 = 5
constant integer SPELL_MIN_LEVEL_SENTRY_WARD = 1 // Active spells
constant integer SPELL_MIN_LEVEL_BAT_SWARM = 7
constant integer SPELL_MIN_LEVEL_FEAR = 5
constant integer SPELL_MIN_LEVEL_LIGHTNING = 5
constant integer SPELL_MIN_LEVEL_MANA_SHIELD = 5
constant integer SPELL_MIN_LEVEL_VAMPIRIC_AURA = 3 // Passive spells
constant integer SPELL_MIN_LEVEL_EVASION = 4
constant integer SPELL_MIN_LEVEL_FAST_TRANSFORM = 3
constant integer SPELL_MIN_LEVEL_SHADOW_MELD = 8
constant integer SPELL_MIN_LEVEL_6TH_SENSE = 5
// Spells
// ==================================================================
constant integer SPELL_ID_SUCK_BLOOD = 'A00E' // Ability
constant integer SPELL_ID_VAMPIRE_FORM = 'A028' // Transformations
constant integer SPELL_ID_RAT_FORM = 'A013'
constant integer SPELL_ID_WOLF_FORM = 'A02B'
constant integer SPELL_ID_BAT_FORM = 'A029'
constant integer SPELL_ID_OVERLORD_FORM = 'A02C'
constant integer SPELL_ID_SENTRY_WARD = 'A02F' // Active Spells [W]
constant integer SPELL_ID_BAT_SWARM = 'A02J' // [B]
constant integer SPELL_ID_FEAR = 'A001' // [F]
constant integer SPELL_ID_LIGHTNING = 'A00Q' // [Q]
constant integer SPELL_ID_MANA_SHIELD = 'A04L' // [N]
constant integer SPELL_ID_VAMPIRIC_AURA = 'A00P' // Passive Spells
constant integer SPELL_ID_EVASION = 'A00S'
constant integer SPELL_ID_SHADOW_MELD = 'A008'
constant integer SPELL_ID_FAST_TRANSFORM = 'A048'
constant integer SPELL_ID_6TH_SENSE = 'A04B'
// Wrappers
constant integer SPELL_CONTAINER_VAMP_SPELLS = 'A03P' // Containers
constant integer SPELL_CONTAINER_PASSIVE = 'A03O'
constant integer SPELL_CONTAINER_TRANSFORMATION = 'A014'
constant integer SPELL_CONTAINER_LEARN_ABILITIES = 'A00H'
constant integer SPELL_WRAPPER_VAMPIRE_FORM = 'A016' // Transformations
constant integer SPELL_WRAPPER_VAMPIRE_FORM_INFO = 'A015'
constant integer SPELL_WRAPPER_RAT_FORM = 'A00Z'
constant integer SPELL_WRAPPER_RAT_FORM_INFO = 'A00T'
constant integer SPELL_WRAPPER_WOLF_FORM = 'A011'
constant integer SPELL_WRAPPER_WOLF_FORM_INFO = 'A010'
constant integer SPELL_WRAPPER_BAT_FORM = 'A02A'
constant integer SPELL_WRAPPER_BAT_FORM_INFO = 'A012'
constant integer SPELL_WRAPPER_OVERLORD_FORM = 'A026'
constant integer SPELL_WRAPPER_OVERLORD_FORM_INFO = 'A027'
constant integer SPELL_WRAPPER_SENTRY_WARD = 'A03Q' // Active Spells
constant integer SPELL_WRAPPER_BAT_SWARM = 'A040'
constant integer SPELL_WRAPPER_FEAR = 'A03R'
constant integer SPELL_WRAPPER_LIGHTNING = 'A045'
constant integer SPELL_WRAPPER_MANA_SHIELD = 'A04M'
constant integer SPELL_WRAPPER_VAMPIRIC_AURA = 'A03S' // Passive Spells
constant integer SPELL_WRAPPER_EVASION = 'A03X'
constant integer SPELL_WRAPPER_SHADOW_MELD = 'A03W'
constant integer SPELL_WRAPPER_FAST_TRANSFORM = 'A049'
constant integer SPELL_WRAPPER_6TH_SENSE = 'A04C'
constant integer SPELL_WRAPPER_CLEAVING_ATTACK = 'A044'
// Learn abilities
// ==================================================================
constant integer LEARN_RAT_FORM = 'A018' // Transformations
constant integer LEARN_WOLF_FORM = 'A00I'
constant integer LEARN_BAT_FORM = 'A019'
constant integer LEARN_OVERLORD_FORM = 'A017'
constant integer LEARN_RAT_FORM_LV2 = 'A009'
constant integer LEARN_WOLF_FORM_LV2 = 'A00A'
constant integer LEARN_BAT_FORM_LV2 = 'A02D'
constant integer LEARN_SENTRY_WARD = 'A02H' // Active spells
constant integer LEARN_BAT_SWARM = 'A041'
constant integer LEARN_FEAR = 'A01A'
constant integer LEARN_LIGHTNING = 'A01C'
constant integer LEARN_MANA_SHIELD = 'A04N'
//constant integer LEARN_SLEEP = 'A00O'
constant integer LEARN_VAMPIRIC_AURA = 'A03V' // Passive abilities
constant integer LEARN_EVASION = 'A03Y'
constant integer LEARN_SHADOW_MELD = 'A00J'
constant integer LEARN_FAST_TRANSFORM = 'A046'
constant integer LEARN_6TH_SENSE = 'A04D'
// Wrappers
constant integer LEARN_WRAPPER_RAT_FORM = 'A00L' // Transformations
constant integer LEARN_WRAPPER_WOLF_FORM = 'A00M'
constant integer LEARN_WRAPPER_BAT_FORM = 'A00N'
constant integer LEARN_WRAPPER_OVERLORD_FORM = 'A00V'
constant integer LEARN_WRAPPER_RAT_FORM_LV2 = 'A002'
constant integer LEARN_WRAPPER_WOLF_FORM_LV2 = 'A004'
constant integer LEARN_WRAPPER_BAT_FORM_LV2 = 'A003'
constant integer LEARN_WRAPPER_SENTRY_WARD = 'A02G' // Active spells
constant integer LEARN_WRAPPER_BAT_SWARM = 'A042'
constant integer LEARN_WRAPPER_FEAR = 'A00X'
constant integer LEARN_WRAPPER_LIGHTNING = 'A00W'
constant integer LEARN_WRAPPER_MANA_SHIELD = 'A04O'
//constant integer LEARN_WRAPPER_SLEEP = 'A00Y'
constant integer LEARN_WRAPPER_VAMPIRIC_AURA = 'A03U' // Passive abilities
constant integer LEARN_WRAPPER_EVASION = 'A03Z'
constant integer LEARN_WRAPPER_SHADOW_MELD = 'A00U'
constant integer LEARN_WRAPPER_FAST_TRANSFORM = 'A047'
constant integer LEARN_WRAPPER_6TH_SENSE = 'A04E'
endglobals
function VampSpellGetSpell takes integer i returns integer
return Spells[i]
endfunction
function GetSpellLearnWrapper takes integer i returns integer
return LearnWrappers[i]
endfunction
function GetSpellIdForLearnAbility takes integer i returns integer
return VampireLearnSpellsIdLink[i]
endfunction
function GetSpellWrapper takes integer i returns integer
return SpellWrappers[i]
endfunction
function GetSpellMinLevel takes integer i returns integer
return MinLevels[i]
endfunction
function SpellCanBeLearned takes integer i returns boolean
return LearnWrappers[i] != 0
endfunction
private function RegisterVampireSpell takes integer id, integer spellId, integer spellWrapper, integer learnId, integer learnWrapper, integer minLevel returns nothing
set Spells[id] = spellId
set SpellWrappers[id] = spellWrapper
set LearnAbilities[id] = learnId
set LearnWrappers[id] = learnWrapper
set MinLevels[id] = minLevel
if learnId != 0 then
set VampireLearnSpells[learnId] = 1
set VampireLearnSpellsIdLink[learnId] = id
endif
endfunction
private function DefineSpells takes nothing returns nothing
// Transformations
// =========================================================
// Vampire form
call RegisterVampireSpell( SPELL_VAMPIRE_FORM, SPELL_ID_VAMPIRE_FORM, SPELL_WRAPPER_VAMPIRE_FORM, 0, 0, SPELL_MIN_LEVEL_VAMPIRE_FORM )
// Rat form
call RegisterVampireSpell( SPELL_RAT_FORM, SPELL_ID_RAT_FORM, SPELL_WRAPPER_RAT_FORM, LEARN_RAT_FORM, LEARN_WRAPPER_RAT_FORM, SPELL_MIN_LEVEL_RAT_FORM )
// Rat form (lv2)
call RegisterVampireSpell( SPELL_RAT_FORM_LV2, 0, 0, LEARN_RAT_FORM_LV2, LEARN_WRAPPER_RAT_FORM_LV2, SPELL_MIN_LEVEL_RAT_FORM_LV2 )
// Wolf form
call RegisterVampireSpell( SPELL_WOLF_FORM, SPELL_ID_WOLF_FORM, SPELL_WRAPPER_WOLF_FORM, LEARN_WOLF_FORM, LEARN_WRAPPER_WOLF_FORM, SPELL_MIN_LEVEL_WOLF_FORM )
// Wolf form (lv2)
call RegisterVampireSpell( SPELL_WOLF_FORM_LV2, 0, 0, LEARN_WOLF_FORM_LV2, LEARN_WRAPPER_WOLF_FORM_LV2, SPELL_MIN_LEVEL_WOLF_FORM_LV2 )
// Bat form
call RegisterVampireSpell( SPELL_BAT_FORM, SPELL_ID_BAT_FORM, SPELL_WRAPPER_BAT_FORM, LEARN_BAT_FORM, LEARN_WRAPPER_BAT_FORM, SPELL_MIN_LEVEL_BAT_FORM )
// Bat form (lv2)
call RegisterVampireSpell( SPELL_BAT_FORM_LV2, 0, 0, LEARN_BAT_FORM_LV2, LEARN_WRAPPER_BAT_FORM_LV2, SPELL_MIN_LEVEL_BAT_FORM_LV2 )
// Overlord form
call RegisterVampireSpell( SPELL_OVERLORD_FORM, SPELL_ID_OVERLORD_FORM, SPELL_WRAPPER_OVERLORD_FORM, 0, 0, SPELL_MIN_LEVEL_OVERLORD_FORM )
// Spells (active)
// =========================================================
// Sentry Ward
call RegisterVampireSpell( SPELL_SENTRY_WARD, SPELL_ID_SENTRY_WARD, SPELL_WRAPPER_SENTRY_WARD, LEARN_SENTRY_WARD, LEARN_WRAPPER_SENTRY_WARD, SPELL_MIN_LEVEL_SENTRY_WARD )
// call RegisterVampireSpell( SPELL_SENTRY_WARD, SPELL_ID_SENTRY_WARD, SPELL_WRAPPER_SENTRY_WARD, 0, 0, SPELL_MIN_LEVEL_SENTRY_WARD )
// Bat Swarm
call RegisterVampireSpell( SPELL_BAT_SWARM, SPELL_ID_BAT_SWARM, SPELL_WRAPPER_BAT_SWARM, LEARN_BAT_SWARM, LEARN_WRAPPER_BAT_SWARM, SPELL_MIN_LEVEL_BAT_SWARM )
// Fear
call RegisterVampireSpell( SPELL_FEAR, SPELL_ID_FEAR, SPELL_WRAPPER_FEAR, LEARN_FEAR, LEARN_WRAPPER_FEAR, SPELL_MIN_LEVEL_FEAR )
// Lightning
call RegisterVampireSpell( SPELL_LIGHTNING, SPELL_ID_LIGHTNING, SPELL_WRAPPER_LIGHTNING, LEARN_LIGHTNING, LEARN_WRAPPER_LIGHTNING, SPELL_MIN_LEVEL_LIGHTNING )
// Mana Shield
call RegisterVampireSpell( SPELL_MANA_SHIELD, SPELL_ID_MANA_SHIELD, SPELL_WRAPPER_MANA_SHIELD, LEARN_MANA_SHIELD, LEARN_WRAPPER_MANA_SHIELD, SPELL_MIN_LEVEL_MANA_SHIELD )
// Passive Abilitites
// =========================================================
// Vampiric Aura
call RegisterVampireSpell( SPELL_VAMPIRIC_AURA, SPELL_ID_VAMPIRIC_AURA, SPELL_WRAPPER_VAMPIRIC_AURA, LEARN_VAMPIRIC_AURA, LEARN_WRAPPER_VAMPIRIC_AURA, SPELL_MIN_LEVEL_VAMPIRIC_AURA )
// Evasion
call RegisterVampireSpell( SPELL_EVASION, SPELL_ID_EVASION, SPELL_WRAPPER_EVASION, LEARN_EVASION, LEARN_WRAPPER_EVASION, SPELL_MIN_LEVEL_EVASION )
// Shadow Meld
call RegisterVampireSpell( SPELL_SHADOW_MELD, SPELL_ID_SHADOW_MELD, SPELL_WRAPPER_SHADOW_MELD, LEARN_SHADOW_MELD, LEARN_WRAPPER_SHADOW_MELD, SPELL_MIN_LEVEL_SHADOW_MELD )
// Fast Transformation
call RegisterVampireSpell( SPELL_FAST_TRANSFORM, SPELL_ID_FAST_TRANSFORM, SPELL_WRAPPER_FAST_TRANSFORM, LEARN_FAST_TRANSFORM, LEARN_WRAPPER_FAST_TRANSFORM, SPELL_MIN_LEVEL_FAST_TRANSFORM )
// 6th Sense
call RegisterVampireSpell( SPELL_6TH_SENSE, SPELL_ID_6TH_SENSE, SPELL_WRAPPER_6TH_SENSE, LEARN_6TH_SENSE, LEARN_WRAPPER_6TH_SENSE, SPELL_MIN_LEVEL_6TH_SENSE )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set VampireLearnSpells = Table.create()
set VampireLearnSpellsIdLink = Table.create()
call DefineSpells()
call Debug_Message("Vampire spells succesfully defined! (" + I2S(VAMPIRE_SPELL_COUNT)+")")
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope LearnSkills initializer Init
globals
endglobals
private function ConditionsLevelUp takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == VAMPIRE or GetUnitTypeId(GetTriggerUnit()) == RAT or GetUnitTypeId(GetTriggerUnit()) == WOLF or GetUnitTypeId(GetTriggerUnit()) == BAT or GetUnitTypeId(GetTriggerUnit()) == OVERLORD
endfunction
private function OnLevelUp takes nothing returns nothing
local Vampire vamp = GetHandleData(GetTriggerUnit())
if GetHeroLevel(vamp.u) > vamp.level then
call Debug_Message("on vampire level up")
call vamp.incLevel()
call Shadow_Message(vamp.playerId, "Great! You've become more powerful!",false)
endif
if GetHeroLevel(vamp.u) >= VAMPIRE_OVERLORD_LEVEL and not OverlordOnMap then
set OverlordOnMap = true
call Game_Message("Beware! "+PlayerNames[vamp.playerId]+" has reached level 8 and is now able to transform to Overlord Form!")
call vamp.toggleOverlord(true)
endif
endfunction
private function LearnSpellConditions takes nothing returns boolean
return VampireLearnSpells.has( GetSpellAbilityId() )
endfunction
private function LearnSpell takes nothing returns nothing
local integer learnId = GetSpellAbilityId()
local integer spellId = GetSpellIdForLearnAbility(learnId)
local unit u = GetSpellAbilityUnit()
local Vampire vamp = GetHandleData(u)
local effect e
set u = null
call Debug_Message("Learning spell "+I2S(spellId))
set vamp.spells[spellId] = true
set vamp.levelupPoints = vamp.levelupPoints - 1
set e = AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIre\\AIreTarget.mdl", vamp.u, "origin")
call DestroyEffect(e)
set e = null
call vamp.addAbilities()
if (GetLocalPlayer() == Player(vamp.playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ForceUICancel()
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_HERO_LEVEL )
call TriggerAddCondition(trg, Condition(function ConditionsLevelUp))
call TriggerAddAction( trg, function OnLevelUp )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function LearnSpellConditions))
call TriggerAddAction(trg, function LearnSpell)
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope VampireRegister initializer Init
private function RegisterVampireConditions takes nothing returns boolean
return IsVampire(GetFilterUnit())
endfunction
private function Actions takes nothing returns nothing
local group targets = null
local unit t = null
local integer i = 0
if DEBUG_MODE then
set targets = NewGroup()
// pick all preplaced vampires
call GroupEnumUnitsInRect(targets, bj_mapInitialPlayableArea, Condition(function RegisterVampireConditions))
// loop through group and check if a vampire is in sight
loop
set t = FirstOfGroup(targets)
exitwhen t == null
// Throw double registration warning
if GetHandleData(t) == 0 then
set i = i + 1
call RegisterVampire(t)
endif
call GroupRemoveUnit(targets, t)
endloop
call ReleaseGroup(targets)
endif
call Debug_Message("Preplaced vampires on map registered: "+I2S(i))
set targets = null
set t = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call Actions()
endfunction
endscope
//TESH.scrollpos=173
//TESH.alwaysfold=0
scope SuckBlood initializer Init
globals
private constant real SUCKING_INTERVAL = 0.5
private constant integer SUCKING_COMPLETE_COUNT = 20
private constant string BAR_COLOR_DARK = "2B2B2B"
private constant string BAR_COLOR_RED = "FF0000"
private constant integer BAR_COUNT = 20
private integer SUCK_DRAIN_AMOUNT = 0
// private constant real BAG_AREA = 64
private string array BloodBar[1]
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_SUCK_BLOOD
endfunction
private function DisplayIngredientsTag takes unit u, string s, integer id returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1.5)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function harvestSoul takes unit u, integer playerId returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, SOUL_STRING, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1.5)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
call SetPlayerState(Player(playerId), PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(Player(playerId), PLAYER_STATE_RESOURCE_LUMBER) + 1)
set t = null
endfunction
private function CreateBloodBarTagAnimal takes integer playerId, real x, real y, real life_percent returns nothing
local texttag t = CreateTextTag()
local real r
local integer i = 0// R2I((bloodAmount/BloodMax) * BAR_COUNT) // Convert percentage to value between 0 and 20
set r = life_percent * I2R(BAR_COUNT)
set i = R2I(r) - 1
if i < 0 then
set i = 0
endif
// call Debug_Message("Blood Bar | Life Percent "+R2S(life_percent)+ " value: "+I2S(i))
call SetTextTagText(t, BloodBar[i], 0.0184)
call SetTextTagPos(t, x-64, y+64, 0.00)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1)
call SetTextTagPermanent(t, false)
if Player(playerId) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function CreateBloodBarTagVillager takes integer playerId, real x, real y, integer bloodAmount, integer BloodMax returns nothing
local texttag t = CreateTextTag()
local real r = (I2R(bloodAmount)/I2R(BloodMax)) * I2R(BAR_COUNT)
local integer i = 0// R2I((bloodAmount/BloodMax) * BAR_COUNT) // Convert percentage to value between 0 and 20
set i = R2I(r)
// call Debug_Message("blood bar, blood: "+I2S(bloodAmount)+ " max: "+I2S(BloodMax)+" i: "+I2S(i))
call SetTextTagText(t, BloodBar[i], 0.0184)
call SetTextTagPos(t, x-64, y+64, 0.00)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1)
call SetTextTagPermanent(t, false)
if Player(playerId) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function StopSucking takes integer spell_id returns nothing
local Spell spell = spell_id
call PauseUnit(spell.target, false)
call SetUnitInvulnerable(spell.target, false)
if IsCivilian(spell.target) then
call SetUnitTimeScale(spell.target, 0.5)
else
call SetUnitTimeScale(spell.target, 1.0)
endif
// call Debug_Message("Releasing spell "+I2S(spell_id))
call ReleaseHandleData( spell.trg )
call ReleaseEffect(spell.effect_id)
call ReleaseSpell(spell_id)
endfunction
private function SuckedToDeath takes integer spell_id returns nothing
local Spell spell = spell_id
local effect e
local real x = GetUnitX(spell.target)
local real y = GetUnitY(spell.target)
local boolean isVillager = IsVillager(spell.target)
call CreateVampireTag(spell.target, "SUCKED TO DEATH!")
set e = AddSpecialEffect("BloodExSmall.mdl", GetUnitX(spell.target), GetUnitY(spell.target))
call RegisterEffect(e, 3)
set e = null
if GetUnitState(spell.target, UNIT_STATE_LIFE) > 0 then
call KillUnit(spell.target)
endif
call IncScoreKills(spell.playerId)
if isVillager then
call harvestSoul(spell.caster, spell.playerId)
call CreateIngredient(ITEM_INGREDIENT_HEART, x, y)
endif
call StopSucking(spell_id)
endfunction
private function SuckingTimerCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer spell_id = GetTimerData(t)
local Spell spell = spell_id
local real life_percent
local effect e
local Villager v
local Animal ani
local real life_drain
set t = null
// Inc ticks
set spell.ticks = spell.ticks - 1
// Get life percent of victim
set life_percent = GetUnitState(spell.target, UNIT_STATE_LIFE) / GetUnitState(spell.target, UNIT_STATE_MAX_LIFE)
// Blood and drain effect
set e = AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl", spell.target, "chest")
call RegisterEffect(e, 2)
set e = AddSpecialEffectTarget("VampiricAuraTarget.mdl", spell.caster, "origin")
call RegisterEffect(e,1.0)
// Vampire shall hold position with spell animation
call IssueImmediateOrder(spell.caster, "holdposition" )
call SetUnitAnimation(spell.caster, "spell")
call SetUnitAnimation( spell.target, "death")
// Villager
if IsVillager(spell.target) then
// Get struct data
set v = GetHandleData(spell.target)
// Decrease victim blood and update bar
set v.blood = v.blood - SUCK_DRAIN_AMOUNT
// Blood Bar
call CreateBloodBarTagVillager(spell.playerId, spell.x, spell.y, v.blood, v.bloodMax)
// Calculate life drain amount (about 3% per suck)
set life_drain = GetUnitState(spell.target, UNIT_STATE_MAX_LIFE)*BLOOD_SUCK_LIFE_FACTOR
// Reduce victim life
call SetUnitState(spell.target, UNIT_STATE_LIFE, GetUnitState(spell.target, UNIT_STATE_LIFE) - life_drain )
// Increase vampire life
call SetUnitState(spell.caster, UNIT_STATE_LIFE, GetUnitState(spell.caster, UNIT_STATE_LIFE) + life_drain )
// Increase vampire XP
call GiveXP(spell.caster, SUCK_BLOOD_XP_GAIN)
// call Debug_Message("Victim blood: "+I2S(v.blood))
if v.blood <= 0 or GetUnitState(v.u, UNIT_STATE_LIFE) <= 0 then
call SuckedToDeath(spell_id)
endif
// Animal
else
set ani = GetHandleData(spell.target)
// Decrease victim blood and update bar
set ani.blood = ani.blood - SUCK_DRAIN_AMOUNT
// Blood Bar
//call CreateBloodBarTag(spell.playerId, spell.x, spell.y, ani.blood, ani.bloodMax)
call CreateBloodBarTagAnimal(spell.playerId, spell.x, spell.y, life_percent)
// Calculate life drain amount (about 3% per suck)
set life_drain = GetUnitState(spell.target, UNIT_STATE_MAX_LIFE)*BLOOD_SUCK_LIFE_FACTOR
if life_drain < 5 then
set life_drain = 5
endif
// Reduce victim life
call SetUnitState(spell.target, UNIT_STATE_LIFE, GetUnitState(spell.target, UNIT_STATE_LIFE) - life_drain )
// Increase vampire life
call SetUnitState(spell.caster, UNIT_STATE_LIFE, GetUnitState(spell.caster, UNIT_STATE_LIFE) + life_drain )
// Increase vampire XP
call GiveXP(spell.caster, SUCK_BLOOD_XP_GAIN)
// call Debug_Message("Victim blood: "+I2S(ani.blood)+ "life drain: "+R2S(life_drain))
if ani.blood <= 0 or GetUnitState(ani.u, UNIT_STATE_LIFE) <= 0 then
call SuckedToDeath(spell_id)
endif
endif
set e = null
endfunction
private function InterruptSucking takes nothing returns nothing
local integer spell_id = GetHandleData(GetTriggeringTrigger())
local Spell spell = spell_id
local Vampire vamp = GetHandleData(spell.caster)
local Villager v
local Animal ani
// Villager
if IsVillager(spell.target) then
set v = GetHandleData(spell.target)
// Make sure, victim is still alive
if v.blood > 0 and GetUnitState(v.u, UNIT_STATE_LIFE) > 0 then
// Unpause unit
call PauseUnit(v.u, false)
call SetUnitAnimation( spell.target, "stand")
// If blood is less enough, victim switches sides
if v.blood <= SUCKED_TO_DEATH_BLOOD then
// Guards turn passive
if v.isGuard then
call SetUnitOwner( v.u, Player(PLAYER_NEUTRAL_PASSIVE), false )
endif
call Shadow_Message( spell.playerId, "Great work! One more of them on our side..", false)
call UnitShareVision(v.u, GetOwningPlayer(spell.caster), true)
call SetVillagerState(v, VILLAGER_STATE_TRANSFORMING)
set v.masterPlayer = GetPlayerId(GetOwningPlayer(spell.caster))
call IncScoreKills(spell.playerId)
call harvestSoul(spell.caster, spell.playerId)
call CreateVampireTag(v.u, "VICTIM CONVERTED!")
// Start transformation timer or something
// More than enough blood left
else
if v.isGuard then
call GuardAttacks(v, vamp.u)
else
call StartPanic(v, vamp.u)
endif
endif
endif
// Animal
else
set ani = GetHandleData(spell.target)
// Make sure, victim is still alive
if ani.blood > 0 and GetUnitState(ani.u, UNIT_STATE_LIFE) > 0 then
// Unpause unit
call PauseUnit(ani.u, false)
call SetUnitAnimation( spell.target, "stand")
call SetAnimalState(ani, VILLAGER_STATE_WANDERING)
endif
endif
call StopSucking(spell_id)
endfunction
private function SpellStart takes unit vampire, unit victim, boolean isAnimal returns nothing
local real x = GetUnitX(victim)
local real y = GetUnitY(victim)
local Spell spell = RegisterSpell(vampire, victim, x, y, 0, false, 0, 0, 0, 0, SUCKING_COMPLETE_COUNT, 0, SPELL_ID_SUCK_BLOOD)
local Villager v
local Animal ani
local Vampire vamp = GetHandleData(vampire)
local timer t = NewTimer()
local effect e
local real life_percent
// Set Player Id for spell
set spell.playerId = GetPlayerId(GetOwningPlayer(vampire))
// Get life percent of victim
set life_percent = GetUnitState(spell.target, UNIT_STATE_LIFE) / GetUnitState(spell.target, UNIT_STATE_MAX_LIFE)
// Villager
// ================================
if not isAnimal then
// Get struct data
set v = GetHandleData(victim)
// Set state to paralyzed
call SetVillagerState(v, VILLAGER_STATE_PARALYZED)
// Set current blood depending on life
set v.blood = R2I(life_percent * v.bloodMax)
// Create blood bar gfx
call CreateBloodBarTagVillager(spell.playerId, spell.x, spell.y, v.blood, v.bloodMax)
// Animal
// ================================
else
// Get struct data
set ani = GetHandleData(victim)
// Set state to paralyzed
call SetAnimalState(ani, VILLAGER_STATE_PARALYZED)
// Set current blood depending on life
set ani.blood = R2I(life_percent * ani.bloodMax)
// call Debug_Message("Life Percent: "+R2S(life_percent)+ " Blood Max: "+I2S(ani.bloodMax))
// Create blood bar gfx
call CreateBloodBarTagAnimal(spell.playerId, spell.x, spell.y, life_percent)
endif
// Target is set invulnerable while being sucked
call SetUnitInvulnerable(spell.target, true)
call SetUnitTimeScale(spell.target, 0.5)
// Vampire blinks to target
set e = AddSpecialEffectTarget("BlackBlink.mdl", vampire, "origin")
call RegisterEffect(e,1.0)
call SetUnitPosition(vampire, x-64*Cos(GetUnitFacing(victim)*bj_DEGTORAD), y -64 * Sin(GetUnitFacing(victim) * bj_DEGTORAD))
call SetUnitFacing(vampire, bj_RADTODEG * Atan2(y - GetUnitY(vampire), x - GetUnitX(vampire)))
// Unit animations
call IssueImmediateOrder(vampire, "holdposition" )
call SetUnitAnimation( vampire, "spell")
call SetUnitAnimation( victim, "death")
// Additional sucking eye candy
set e = AddSpecialEffectTarget("Abilities\\Spells\\Items\\VampiricPotion\\VampPotionCaster.mdl", vampire, "origin")
set spell.effect_id = RegisterEffect(e,0)
// Create Trigger that detects when vampire interrupts sucking
set spell.trg = CreateTrigger()
call TriggerRegisterUnitEvent( spell.trg, vampire, EVENT_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterUnitEvent( spell.trg, vampire, EVENT_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterUnitEvent( spell.trg, vampire, EVENT_UNIT_DEATH )
call TriggerAddAction( spell.trg, function InterruptSucking )
call SetHandleData(spell.trg, spell)
// Start sucking timer
set spell.t = NewTimer()
call SetTimerData(spell.t, spell)
call TimerStart(spell.t, SUCKING_INTERVAL, true, function SuckingTimerCallback)
set e = null
set t = null
endfunction
// This creates all possible blood bar positions
private function InitBloodBar takes nothing returns nothing
local integer i = 0
local integer j = 0
// Create empty string array
set i = 0
loop
exitwhen i > BAR_COUNT
set BloodBar[i] = ""
set i = i + 1
endloop
// Now loop through positions 0 .. BAR_COUNT
set i = 0
loop
exitwhen i > BAR_COUNT
// Red fiels (as much as i)
set j = 1
loop
exitwhen j > i
set BloodBar[i] = BloodBar[i] + "|cff"+BAR_COLOR_RED+"|"+"|"
set j = j + 1
endloop
// grey (BAR_COUNT - i)
set j = 1
loop
exitwhen j > BAR_COUNT-i
set BloodBar[i] = BloodBar[i] + "|cff"+BAR_COLOR_DARK+"|"+"|"
set j = j + 1
endloop
set BloodBar[i] = BloodBar[i] + "|r"
set i = i + 1
endloop
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local unit t = GetSpellTargetUnit()
local integer id = GetPlayerId(GetOwningPlayer(u))
local Villager v
local Animal ani
local integer validTarget = 0
// Villager and alive?
if IsVillager(t) and GetUnitState(t, UNIT_STATE_LIFE) > 0 then
// Get struct data
set v = GetHandleData(t)
// Check if vampire is behind victim
if IsUnitBehind(u, t) then
// Target is only valid if not already transforming or paralyzed
if v.state == VILLAGER_STATE_TRANSFORMING then
call Problem_Message(id, "This character has already been converted. It will turn into a vampire soon!")
elseif v.state == VILLAGER_STATE_PARALYZED then
call Problem_Message(id, "This character is already being sucked by another vampire!")
else
call SpellStart(u,t, false)
endif
else
call Problem_Message(id, "You must stand behind your victim!")
endif
// Animal and alive?
elseif IsAnimal(t) and GetUnitState(t, UNIT_STATE_LIFE) > 0 then
// Get struct data
set ani = GetHandleData(t)
if ani.state == VILLAGER_STATE_PARALYZED then
call Problem_Message(id, "This animal is already being sucked by another vampire!")
elseif ani.isAggressive then
call Problem_Message(id, "You cannot suck aggressive animals!")
else
call SpellStart(u,t, true)
endif
else
call Problem_Message(id, "Invalid target!")
endif
set u = null
set t = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction(trg, function Actions)
set trg = null
call InitBloodBar()
set SUCK_DRAIN_AMOUNT = MAX_BLOOD / SUCKING_COMPLETE_COUNT
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Transformation initializer Init
globals
constant integer VAMPIRE_MANA_COST = 0
constant integer RAT_MANA_COST = 10
constant integer WOLF_MANA_COST = 25
constant integer BAT_MANA_COST = 50
constant real TRANSFORMATION_TIME = 1.2
private boolean array Transformation[1]
private unit array Hero[1]
private integer array Level[1]
private integer array XP[1]
private real array Facing[1]
private real array Health[1]
private real array Mana[1]
private real array PosX[1]
private real array PosY[1]
private integer array NewForm[1]
endglobals
private function ConditionsVampireForm takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_VAMPIRE_FORM
endfunction
private function ConditionsRatForm takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_RAT_FORM
endfunction
private function ConditionsWolfForm takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_WOLF_FORM
endfunction
private function ConditionsBatForm takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_BAT_FORM
endfunction
private function ConditionsDemonForm takes nothing returns boolean
return GetSpellAbilityId() == SPELL_ID_OVERLORD_FORM
endfunction
private function TransformationCallback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Vampire vamp = GetTimerData(t)
local CastBar bar = vamp.castBar
local effect e = null
call ReleaseTimer(t)
set t = null
// If hero is already dead
if GetUnitState(vamp.u, UNIT_STATE_LIFE) <= 0 then
// If hero still alive
else
call vamp.changeForm(vamp.newForm)
call SetUnitAnimation(vamp.u, "slam")
call QueueUnitAnimation(vamp.u, "stand")
set e = AddSpecialEffectTarget("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", vamp.u, "origin")
call DestroyEffect(e)
set e = null
endif
set vamp.inTransformation = false
endfunction
private function StartTransformation takes unit u, integer newForm, real duration returns nothing
local integer id = GetPlayerId(GetOwningPlayer(u))
// local effect e = null
local Vampire vamp = GetHandleData(u)
local CastBar bar = vamp.castBar
local effect e = null
call Debug_Message("Start transformation..")
if vamp.spells[SPELL_FAST_TRANSFORM] then
set duration = duration * FAST_TRANSFORM_FACTOR
endif
// When same form
if GetUnitTypeId(u) == newForm then
// do nothing
elseif not vamp.inTransformation then
set vamp.inTransformation = true
set vamp.newForm = newForm
// Let's go
if (GetLocalPlayer() == Player(id)) then
call ForceUICancel()
endif
call bar.startCastBar( duration )
// call bar.setPercentage(100, duration)
call SetUnitTimeScale(vamp.u, 1.4)
call SetUnitAnimation(vamp.u, "Spell")
call QueueUnitAnimation(vamp.u, "Spell")
call QueueUnitAnimation(vamp.u, "Spell")
call QueueUnitAnimation(vamp.u, "Spell")
call QueueUnitAnimation(vamp.u, "Spell")
call PauseUnit(vamp.u, true)
set vamp.transformation_timer = NewTimer()
call SetTimerData(vamp.transformation_timer, vamp)
set e = AddSpecialEffect("DarkHarvest.mdl", GetUnitX(u), GetUnitY(u))
call RegisterEffect(e, duration)
call TimerStart(vamp.transformation_timer, duration, false, function TransformationCallback)
endif
set e = null
endfunction
private function VampireForm takes nothing returns nothing
call StartTransformation(GetSpellAbilityUnit(), VAMPIRE, 1.0)
endfunction
private function RatForm takes nothing returns nothing
call StartTransformation(GetSpellAbilityUnit(), RAT, 1.0)
endfunction
private function WolfForm takes nothing returns nothing
call StartTransformation(GetSpellAbilityUnit(), WOLF, 1.0)
endfunction
private function BatForm takes nothing returns nothing
call StartTransformation(GetSpellAbilityUnit(), BAT, 3.0)
endfunction
private function DemonForm takes nothing returns nothing
call StartTransformation(GetSpellAbilityUnit(), OVERLORD, 8.0)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( trg, Condition( function ConditionsVampireForm ) )
call TriggerAddAction( trg, function VampireForm )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( trg, Condition( function ConditionsRatForm ) )
call TriggerAddAction( trg, function RatForm )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( trg, Condition( function ConditionsWolfForm ) )
call TriggerAddAction( trg, function WolfForm )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( trg, Condition( function ConditionsBatForm ) )
call TriggerAddAction( trg, function BatForm )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( trg, Condition( function ConditionsDemonForm ) )
call TriggerAddAction( trg, function DemonForm )
set trg = null
endfunction
endscope
//TESH.scrollpos=75
//TESH.alwaysfold=0
scope Fear initializer Init
globals
private constant integer AbilID = SPELL_ID_FEAR
private constant integer FEAR_MAX_TARGETS = 5
private constant integer MAX_TICKS = 5
private constant real FEAR_RANGE = 500
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AbilID
endfunction
private function Run_Away takes unit u returns nothing
local integer playerId = GetPlayerId(GetOwningPlayer(u))
local real x = GetUnitX(u) + 1024.00 * Cos(GetRandomReal(0, 360) * bj_DEGTORAD)
local real y = GetUnitY(u) + 1024.00 * Sin(GetRandomReal(0, 360) * bj_DEGTORAD)
// Make unit move around
call IssuePointOrder(u, "move", x, y )
if IsUnitSelected(u, Player(playerId)) and Player(playerId) == GetLocalPlayer() then
call ClearSelection()
endif
set u = null
endfunction
private function Callback takes nothing returns nothing
local timer t = GetExpiredTimer()
local Spell spell = GetTimerData(t)
local Villager v
local Animal ani
set t = null
set spell.ticks = spell.ticks + 1
if spell.ticks < MAX_TICKS then
call Run_Away(spell.target)
else
if IsVillager(spell.target) then
set v = GetHandleData(spell.target)
call SetVillagerState(v, v.defaultState)
endif
call ReleaseEffect(spell.effect_id)
call ReleaseSpell(spell)
endif
endfunction
private function Target_Conditions takes nothing returns boolean
return ( IsVillager(GetFilterUnit()) or IsAnimal(GetFilterUnit()) ) and GetUnitState(GetFilterUnit(), UNIT_STATE_LIFE) > 0
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local unit t = null
local group targets = NewGroup()
local Spell spell
local effect e
local integer effect_id
local Villager v
local Animal ani
// Get targets
call GroupEnumUnitsInRange(targets, GetUnitX(u), GetUnitY(u), FEAR_RANGE, Condition(function Target_Conditions))
// Target Number is limited
loop
exitwhen CountUnitsInGroup(targets) <= FEAR_MAX_TARGETS
call GroupRemoveUnit(targets, FirstOfGroup(targets))
endloop
// Buff'em!
loop
set t = FirstOfGroup(targets)
exitwhen t == null
// Effect
set e = AddSpecialEffectTarget("FearTargetNew.mdl", t, "overhead")
set effect_id = RegisterEffect(e, 0)
// Register spell (caster, target, x, y, damage, crit, health, mana, armor, speed, ticks, effect_id, name_id)
set spell = RegisterSpell(u,t,0,0,0,false,0,0,0,0,0,effect_id,0)
if IsVillager(t) then
set v = GetHandleData(t)
call SetVillagerState(v, VILLAGER_STATE_FEAR)
endif
// Make 'em run
call Run_Away(t)
call GroupRemoveUnit(targets, t)
set spell.t = NewTimer()
call SetTimerData(spell.t, spell)
call TimerStart(spell.t, GENERIC_DOT_INTERVAL, true, function Callback)
endloop
// Cleanup
call ReleaseGroup(targets)
set targets = null
set u = null
set t = null
set e = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CallSpawns initializer Init
globals
private constant integer AbilID = 'A02M'
private constant integer SPAWN_COUNT = 3
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == AbilID
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local unit spawn
local effect e
local integer i = 0
local real x = GetUnitX(u)
local real y = GetUnitY(u)
loop
exitwhen i > (SPAWN_COUNT-1)
set spawn = CreateUnit(Player(9), SPAWN, x+GetRandomReal(-64,64), y+GetRandomReal(-64,64), bj_UNIT_FACING)
set e = AddSpecialEffect("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", GetUnitX(spawn), GetUnitY(spawn))
call DestroyEffect(e)
call RegisterSpawn(spawn)
set i = i + 1
endloop
set u = null
set spawn = null
set e = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=14
//TESH.alwaysfold=0
library HunterSystem initializer Init requires BasicFunctions, VillagerSystem, CastBar
globals
private unit ResurrectionStone
endglobals
private function HunterRevives takes nothing returns nothing
local timer t = GetExpiredTimer()
local Hunter hunter= GetTimerData(t)
call TimerDialogDisplay(ReviveTimerWindows[hunter.playerId], false)
call hunter.revive()
set t = null
endfunction
private function HunterDies takes nothing returns nothing
local Hunter hunter = GetHandleData(GetTriggeringTrigger())
local unit killer = GetKillingUnit()
call Debug_Message("Hunter dead event")
// Update score
call IncScoreDeaths(hunter.playerId)
set killer = null
// Disable death trigger
call DisableTrigger(hunter.onDeathTrigger)
// Create timer for first time
if ReviveTimers[hunter.playerId] == null then
set ReviveTimers[hunter.playerId] = NewTimer()
endif
// Create window for first time
if ReviveTimerWindows[hunter.playerId] == null then
set ReviveTimerWindows[hunter.playerId] = CreateTimerDialog(ReviveTimers[hunter.playerId])
call TimerDialogSetTitle(ReviveTimerWindows[hunter.playerId], "|cffFF0000Respawn in:|r")
endif
// Make window visible to player
if (GetLocalPlayer() == Player(hunter.playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call TimerDialogDisplay(ReviveTimerWindows[hunter.playerId], true)
endif
// Start timer to revival
call SetTimerData(ReviveTimers[hunter.playerId], hunter)
call TimerStart(ReviveTimers[hunter.playerId], HUNTER_RESPAWN_TIME, false, function HunterRevives )
endfunction
private function CreateReloadTag takes integer data, real duration returns nothing
local Hunter hunter = data
local texttag t = CreateTextTag()
call SetTextTagText(t, RELOAD_STRING, 0.0184)
call SetTextTagPos(t, GetUnitX(hunter.u), GetUnitY(hunter.u), BAR_TAG_Z_OFFSET)
// call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, duration-0.5)
call SetTextTagLifespan(t, duration)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(hunter.u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set hunter.reloadTag = t
set t = null
endfunction
private function CreateGoldTag takes unit u, string s returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.04)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 1.0)
call SetTextTagLifespan(t, 2.0)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function UpdateCastbarPosition takes nothing returns nothing
local Hunter hunter = GetTimerData(GetExpiredTimer())
local CastBar bar = hunter.castBar
local real x = GetUnitX(hunter.u)
local real y = GetUnitY(hunter.u)
set bar.x = x
set bar.y = y
// call SetUnitX(bar.bar, x)
// call SetUnitY(bar.bar, y)
call SetTextTagPos(hunter.reloadTag, x, y, BAR_TAG_Z_OFFSET)
endfunction
private function ReloadFinished takes nothing returns nothing
local Hunter hunter = GetTimerData(GetExpiredTimer())
call hunter.reloadFinished()
endfunction
private function VampireTracker takes nothing returns nothing
local Hunter hunter = GetTimerData(GetExpiredTimer())
local integer i
local unit u
local real uX
local real uY
local real dx
local real dy
local real distance
set i = PLAYER_VAMPIRES_START_ID
loop
exitwhen i > PLAYER_VAMPIRES_END_ID
if HeroByPlayer[i] != null and GetUnitState(HeroByPlayer[i], UNIT_STATE_LIFE ) > 0 and not (GetUnitAbilityLevel(HeroByPlayer[i], 'Binv') > 0 ) and not (GetUnitTypeId(HeroByPlayer[i]) == RAT) then
set u = HeroByPlayer[i]
set uX = GetUnitX(u)
set uY = GetUnitY(u)
set dx = uX - GetUnitX(hunter.u)
set dy = uY - GetUnitY(hunter.u)
set distance = SquareRoot(dx * dx + dy * dy)
if (GetLocalPlayer() == Player(hunter.playerId)) and distance <= VAMPIRE_TRACKER_DISTANCE then
// Purple Ping
call PingMinimapEx(uX, uY, 1.0, 181, 133, 240, false)
endif
endif
set i = i + 1
endloop
set u = null
endfunction
struct Hunter
unit u = null
boolean isDead = false
trigger onDeathTrigger = null
integer castBar = 0
integer playerId = 0
integer shots = 0
timer reloadTimer = null
timer reloadTagTimer = null
real reloadTime = 0
boolean isReloading = false
texttag reloadTag = null
timer trackerTimer = null
boolean hasTracker = false
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
local CastBar bar = CastBar.create()
set this.u = u
set HandleIdTable[GetHandleId(this.u)] = this
call UnitAddType(this.u, UNIT_TYPE_PEON)
set this.playerId = GetPlayerId(GetOwningPlayer(u))
set bar.zOffset = BAR_Z_OFFSET
set bar.color = PLAYER_COLOR_ORANGE
set bar.target = this.u
call bar.show(false)
set this.castBar = bar
// On death trigger
set this.onDeathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent( this.onDeathTrigger, this.u, EVENT_UNIT_DEATH )
set HandleIdTable[GetHandleId( this.onDeathTrigger)] = this
call TriggerAddAction( this.onDeathTrigger, function HunterDies)
// Create reload timer
set this.reloadTimer = NewTimer()
call SetTimerData(this.reloadTimer, this)
// Add gold for player
call SetPlayerState( Player(this.playerId), PLAYER_STATE_RESOURCE_GOLD, ( GetPlayerState(Player(this.playerId), PLAYER_STATE_RESOURCE_GOLD) + HUNTER_START_GOLD ) )
// Set base reload times
if GetUnitTypeId(this.u) == GUNSLINGER then
set this.reloadTime = BASE_RELOAD_TIME_GUNSLINGER
elseif GetUnitTypeId(this.u) == ASSASSIN then
set this.reloadTime = BASE_RELOAD_TIME_ASSASSIN
endif
set HeroStructIdByPlayer[this.playerId] = this
set HeroByPlayer[this.playerId] = this.u
// Damage Detection
call StructuredDD.add(this.u)
return this
endmethod
public method bountyTime takes integer gold returns nothing
call SetPlayerState(Player(this.playerId), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(this.playerId), PLAYER_STATE_RESOURCE_GOLD) + gold)
call CreateGoldTag(this.u, "|cffFFFAC6+"+I2S(gold)+" gold")
endmethod
public method reloadFinished takes nothing returns nothing
// call PauseUnit(this.u, false)
call UnitRemoveAbility(this.u, 'Abun')
set this.shots = 0
set this.isReloading = false
call IssueImmediateOrder(this.u, "stop")
if this.reloadTagTimer != null then
call ReleaseTimer(this.reloadTagTimer)
set this.reloadTagTimer = null
endif
if this.reloadTag != null then
call DestroyTextTag(this.reloadTag)
set this.reloadTag = null
endif
endmethod
public method toggleTracker takes boolean activate returns nothing
// Activate tracker
if not this.hasTracker and activate then
set this.hasTracker = activate
set this.trackerTimer = NewTimer()
call SetTimerData(this.trackerTimer, this)
call TimerStart(this.trackerTimer, VAMPIRE_TRACKER_INTERVAL, true, function VampireTracker)
// Deactivate
elseif this.hasTracker and activate == false then
set this.hasTracker = activate
call ReleaseTimer(this.trackerTimer)
set this.trackerTimer = null
endif
endmethod
public method reload takes nothing returns nothing
local CastBar bar = this.castBar
if not this.isReloading then
set this.isReloading = true
call bar.startCastBar( this.reloadTime )
// call PauseUnit(this.u, true)
call UnitAddAbility(this.u, 'Abun')
call CreateReloadTag(this, this.reloadTime)
call TimerStart(this.reloadTimer, this.reloadTime, false, function ReloadFinished)
// Create reload timer
if this.reloadTagTimer == null then
set this.reloadTagTimer = NewTimer()
call SetTimerData(this.reloadTagTimer, this)
call TimerStart(this.reloadTagTimer, 0.02, true, function UpdateCastbarPosition)
endif
endif
endmethod
public method revive takes nothing returns nothing
local real x = GetUnitX(ResurrectionStone)
local real y = GetUnitY(ResurrectionStone)
set this.isDead = false
call SetUnitAnimation(ResurrectionStone, "Stand Alternate")
call QueueUnitAnimation(ResurrectionStone, "Work")
call QueueUnitAnimation(ResurrectionStone, "Stand")
call ReviveHero(this.u, x, y, true)
if (GetLocalPlayer() == Player(this.playerId)) then
// Use only local code (no net traffic) within this block to avoid desyncs.
call ClearSelection()
call SelectUnit(this.u, true)
endif
call PanCameraToTimedForPlayer(Player(this.playerId), x, y, 0.5)
// Enable onDeath trigger
call EnableTrigger(this.onDeathTrigger)
endmethod
public method destroy takes nothing returns nothing
local CastBar bar = this.castBar
call bar.destroy()
set this.castBar = 0
if this.u != null then
call ReleaseHandleData( this.u )
set this.u = null
endif
// Destroy triggers
if this.onDeathTrigger != null then
call ReleaseHandleData( this.onDeathTrigger )
call DestroyTrigger(this.onDeathTrigger)
set this.onDeathTrigger = null
endif
if this.reloadTimer != null then
call ReleaseTimer(this.reloadTimer)
set this.reloadTimer = null
endif
if this.reloadTagTimer != null then
call ReleaseTimer(this.reloadTagTimer)
set this.reloadTagTimer = null
endif
if this.trackerTimer != null then
call ReleaseTimer(this.trackerTimer)
set this.trackerTimer = null
endif
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
private function HunterDamagesEvent takes nothing returns nothing
local unit target = GetTriggerUnit()
local unit attacker = GetEventDamageSource()
local real damage = GetEventDamage()
local Hunter hunter
// call Debug_Message("Villager takes damage | "+GetUnitName(GetEventDamageSource())+" dealt "+R2S(GetEventDamage())+" to: "+GetUnitName(GetTriggerUnit()))
if IsHunter(attacker) then
set hunter = GetHandleData(attacker)
if GetUnitTypeId(attacker) == GUNSLINGER then
set hunter.shots = hunter.shots + 1
call Debug_Message("hunter attacks (shots: "+I2S(hunter.shots)+")")
if hunter.shots >= MAX_SHOTS_GUNSLINGER then
call hunter.reload()
endif
elseif GetUnitTypeId(attacker) == ASSASSIN then
set hunter.shots = hunter.shots + 1
call Debug_Message("hunter attacks (shots: "+I2S(hunter.shots)+")")
if hunter.shots >= MAX_SHOTS_ASSASSIN then
call hunter.reload()
endif
endif
if damage > 0 then
call CreateDamageTag(attacker, target, I2S(R2I(damage)))
endif
endif
set attacker = null
set target = null
endfunction
private function HunterKillsConditions takes nothing returns boolean
return IsHunter(GetKillingUnit())
endfunction
private function HunterKills takes nothing returns nothing
local unit t = GetDyingUnit()
local Hunter hunter = GetHandleData(GetKillingUnit())
local Vampire vamp
local integer bounty
call Debug_Message("Hunter kills event")
call IncScoreKills(hunter.playerId)
// Vampires
if IsPlayerVampiric(t) then
set vamp = GetHandleData(GetDyingUnit())
call IncScorePvP(hunter.playerId)
set bounty = BOUNTY_VAMPIRE + (GetHeroLevel(vamp.u)-1)*BOUNTY_VAMPIRE_LEVEL_BONUS
call hunter.bountyTime( bounty )
call GiveXP(hunter.u, bounty)
// Message
// call Game_Message(PlayerNames[hunter.playerId]+" has killed "+PlayerNames[vamp.playerId] )
elseif GetUnitTypeId(t) == SPAWN then
set bounty = BOUNTY_SPAWN
call hunter.bountyTime( bounty )
call GiveXP(hunter.u, bounty)
elseif GetUnitTypeId(t) == ZOMBIE then
set bounty = BOUNTY_ZOMBIE
call hunter.bountyTime( BOUNTY_ZOMBIE )
call GiveXP(hunter.u, bounty)
endif
set t = null
endfunction
function RegisterHunter takes unit u returns integer
local Hunter hunter
// Throw double registration warning
if GetHandleData(u) != 0 then
call Debug_Message("|cffFF0000Error:|r Double registration of hunter!")
return 0
else
// Create struct data
set hunter = Hunter.create(u)
endif
return hunter
endfunction
private function Init takes nothing returns nothing
local trigger trg
call StructuredDD.addHandler(function HunterDamagesEvent)
set ResurrectionStone = gg_unit_nbse_0082
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( trg, Condition( function HunterKillsConditions ) )
call TriggerAddAction( trg, function HunterKills )
set trg = null
endfunction
endlibrary
//TESH.scrollpos=12
//TESH.alwaysfold=0
scope VampireTrap initializer Init
globals
private constant integer AbilID = 'A03B'
private constant real ACTIVATION_RANGE = 128
private constant integer BEAR_TRAP = 'o001'
private constant real TRAP_READY_TIME = 6.0
private constant real TRAP_TIME_MIN = 8.00
private constant real TRAP_TIME_MAX = 12.00
endglobals
private function TrapActivated takes nothing returns nothing
local timer t = GetExpiredTimer()
local Trap trap = GetTimerData(t)
set t = null
call trap.activate()
endfunction
private function TrapCatchesConditions takes nothing returns boolean
return IsUndead(GetTriggerUnit()) and IsUnitType(GetTriggerUnit(), UNIT_TYPE_GROUND) and not (GetUnitTypeId(GetTriggerUnit()) == RAT)
endfunction
private function TrapCatchedSomething takes nothing returns nothing
local Trap trap = GetHandleData(GetTriggeringTrigger())
local unit t = GetTriggerUnit()
local unit dummy
local real x = GetUnitX(trap.u)
local real y = GetUnitY(trap.u)
local integer playerId = GetPlayerId(GetOwningPlayer(trap.u))
// call Debug_Message("Trap catched "+GetUnitName(t))
// call UnitDamageTarget(trap.u, t, 30, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
call SetUnitX(t, x)
call SetUnitY(t, y)
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), 'h00A', GetUnitX(t), GetUnitY(t), bj_UNIT_FACING)
call IssueTargetOrder(dummy, "ensnare", t)
call RemoveUnit(dummy)
if GetLocalPlayer() == Player(playerId) then
// Purple Ping
call PingMinimapEx(x, y, 10.0, 181, 133, 240, false)
call DisplayTimedTextToPlayer(Player(playerId),0,0,5, "Attention - One of your traps has catched something!")
endif
set t = null
set dummy = null
endfunction
struct Trap
unit u = null
integer playerId = 0
trigger catchTrigger = null
timer readyTimer = null
static method create takes real x, real y, integer playerId returns thistype
local thistype this = thistype.allocate()
local effect e
set this.u = CreateUnit(Player(playerId), BEAR_TRAP, x, y, bj_UNIT_FACING)
set HandleIdTable[GetHandleId(this.u)] = this
set this.playerId = playerId
// Effect
set e = AddSpecialEffect("Abilities\\Spells\\Human\\ControlMagic\\ControlMagicTarget.mdl", x, y)
call RegisterEffect(e, 3)
// Set colors
call SetUnitVertexColor(this.u, 255, 255, 255, 80)
call SetUnitAnimation(this.u, "Birth")
call SetUnitTimeScale(this.u, 0.33)
set this.readyTimer = NewTimer()
call SetTimerData(this.readyTimer, this)
call TimerStart(this.readyTimer, TRAP_READY_TIME, false, function TrapActivated)
set e = null
return this
endmethod
public method activate takes nothing returns nothing
call ReleaseTimer(this.readyTimer)
set this.readyTimer = null
// Catch trigger
set this.catchTrigger = CreateTrigger()
call TriggerRegisterUnitInRange(this.catchTrigger, this.u, ACTIVATION_RANGE, null)
call TriggerAddCondition( this.catchTrigger, Condition( function TrapCatchesConditions ) )
set HandleIdTable[GetHandleId( this.catchTrigger)] = this
call TriggerAddAction( this.catchTrigger, function TrapCatchedSomething)
call CreateTagOnUnit(this.u, "|cff71828CTrap armed!|r")
endmethod
public method destroy takes nothing returns nothing
if this.u != null then
call HandleIdTable.remove( GetHandleId( this.u ) )
call SetUnitTimeScale(this.u, 1)
call KillUnit(this.u)
set this.u = null
endif
if this.catchTrigger != null then
call HandleIdTable.remove( GetHandleId( this.catchTrigger ) )
call DestroyTrigger( this.catchTrigger )
set this.catchTrigger = null
endif
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
private function CreateTrapConditions takes nothing returns boolean
return GetSpellAbilityId() == AbilID
endfunction
private function CreateTrap takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local real x = GetLocationX(GetSpellTargetLoc())
local real y = GetLocationY(GetSpellTargetLoc())
local integer id = GetPlayerId(GetOwningPlayer(u))
local Trap trap
set trap = Trap.create(x,y,id)
// Cleanup
set u = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function CreateTrapConditions ) )
call TriggerAddAction( trg, function CreateTrap )
set trg = null
endfunction
endscope
//TESH.scrollpos=30
//TESH.alwaysfold=0
scope Mage initializer Init
globals
// Fire stuff
private constant integer SKILL_FIRE_MASTERY = 'A02V'
private constant integer SKILL_FIREBALL = 'A02U'
// Frost stuff
private constant integer SKILL_FROST_MASTERY = 'A02W'
private constant integer SKILL_FROSTBOLT = 'A031'
// Lightning stuff
endglobals
private function LearnFireMasteryConditions takes nothing returns boolean
return GetLearnedSkill() == SKILL_FIRE_MASTERY
endfunction
private function LearnFrostMasteryConditions takes nothing returns boolean
return GetLearnedSkill() == SKILL_FROST_MASTERY
endfunction
private function ExChangeMage takes unit u, integer unitId returns unit
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real facing = GetUnitFacing(u)
local integer playerId = GetPlayerId(GetOwningPlayer(u))
local real life = GetUnitState(u, UNIT_STATE_LIFE)
local real mana = GetUnitState(u, UNIT_STATE_MANA)
local Hunter hunter = GetHandleData(u)
call Debug_Message("Exchange mage!")
// Save inventory
call SaveInventory(u)
// Destroy struct
call hunter.destroy()
// Remove old hero
call RemoveUnit(u)
// Update struct data and such
// Create new hero
set u = CreateUnit(Player(playerId), unitId, x, y, facing)
// Set life and mana
call SetUnitState(u, UNIT_STATE_LIFE, life)
call SetUnitState(u, UNIT_STATE_MANA, mana)
// Load inventory
call LoadInventory(u)
call RegisterHunter(u)
if Player(playerId) == GetLocalPlayer() then
call ClearSelection()
call SelectUnit(u, true)
call ForceUICancel()
endif
return u
endfunction
private function LearnFireMastery takes nothing returns nothing
local unit u = GetLearningUnit()
local effect e
set u = ExChangeMage(u, FIRE_MAGE)
call UnitAddAbility(u, SKILL_FIREBALL)
call SetUnitAnimation(u, "spell")
set e = AddSpecialEffectTarget("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl", u, "overhead")
call DestroyEffect(e)
set u = null
set e = null
endfunction
private function LearnFrostMastery takes nothing returns nothing
local unit u = GetLearningUnit()
local effect e
set u = ExChangeMage(u, FROST_MAGE)
call UnitAddAbility(u, SKILL_FROSTBOLT)
call SetUnitAnimation(u, "spell")
set e = AddSpecialEffectTarget("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl", u, "overhead")
call DestroyEffect(e)
set u = null
set e = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition( trg, Condition( function LearnFireMasteryConditions ) )
call TriggerAddAction( trg, function LearnFireMastery )
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition( trg, Condition( function LearnFrostMasteryConditions ) )
call TriggerAddAction( trg, function LearnFrostMastery )
endfunction
endscope
//TESH.scrollpos=5
//TESH.alwaysfold=0
scope Assassin initializer Init
globals
private constant integer SKILL_SHOOT_CROSSBOW = 'A030'
endglobals
private function ShootCrossbowConditions takes nothing returns boolean
return GetSpellAbilityId() == SKILL_SHOOT_CROSSBOW
endfunction
private function ShootCrossbow takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local Hunter hunter = GetHandleData(u)
local timer t = NewTimer()
call hunter.reload()
set u = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function ShootCrossbowConditions ) )
call TriggerAddAction( trg, function ShootCrossbow )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Sentinal initializer Init
globals
private constant integer ABILITY_ID = 'A03C'
endglobals
private function Conditions takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_ID
endfunction
private function Actions takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
local unit t = GetSpellTargetUnit()
call UnitShareVision(t, GetOwningPlayer(u), true)
set u = null
set t = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
scope Gunslinger initializer Init
globals
// Fire stuff
private constant integer SKILL_FAST_RELOAD = 'A039'
private constant integer ABILITY_RELOAD = 'A03C'
endglobals
private function LearnFastReloadConditions takes nothing returns boolean
return GetLearnedSkill() == SKILL_FAST_RELOAD
endfunction
private function LearnFastReload takes nothing returns nothing
local unit u = GetLearningUnit()
local Hunter hunter = GetHandleData(u)
if GetUnitAbilityLevel(u, SKILL_FAST_RELOAD) == 1 then
set hunter.reloadTime = FAST_RELOAD_1_GUNSLINGER
call Debug_Message("Learned fast reload lv 1")
elseif GetUnitAbilityLevel(u, SKILL_FAST_RELOAD) == 2 then
set hunter.reloadTime = FAST_RELOAD_2_GUNSLINGER
call Debug_Message("Learned fast reload lv 2")
elseif GetUnitAbilityLevel(u, SKILL_FAST_RELOAD) == 3 then
set hunter.reloadTime = FAST_RELOAD_3_GUNSLINGER
call Debug_Message("Learned fast reload lv 3")
elseif GetUnitAbilityLevel(u, SKILL_FAST_RELOAD) == 4 then
set hunter.reloadTime = FAST_RELOAD_4_GUNSLINGER
call Debug_Message("Learned fast reload lv 4")
endif
set u = null
endfunction
private function ReloadConditions takes nothing returns boolean
return GetSpellAbilityId() == ABILITY_RELOAD
endfunction
private function Reload takes nothing returns nothing
local Hunter hunter = GetHandleData(GetSpellAbilityUnit())
call hunter.reload()
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_HERO_SKILL )
call TriggerAddCondition( trg, Condition( function LearnFastReloadConditions ) )
call TriggerAddAction( trg, function LearnFastReload )
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition( trg, Condition( function ReloadConditions ) )
call TriggerAddAction( trg, function Reload )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library AnimalSystem initializer Init requires HandleTable, BasicFunctions, ItemFunctions, Alloc, StructuredDD, IsUnitInSight
globals
private Table MeatCounts
endglobals
function IsAnimal takes unit u returns boolean
if GetUnitTypeId(u) == RABBIT then
return true
endif
if GetUnitTypeId(u) == CHICKEN then
return true
endif
if GetUnitTypeId(u) == RACOON then
return true
endif
if GetUnitTypeId(u) == PIG then
return true
endif
if GetUnitTypeId(u) == SHEEP then
return true
endif
if GetUnitTypeId(u) == DEER then
return true
endif
if GetUnitTypeId(u) == WILD_WOLF then
return true
endif
if GetUnitTypeId(u) == GIANT_WOLF then
return true
endif
if GetUnitTypeId(u) == BEAR then
return true
endif
return false
endfunction
function SetAnimalState takes integer id, integer state returns nothing
local Animal ani = id
// Only do something if we have a new state
if state != ani.state then
// STANDING
if state == VILLAGER_STATE_STAND then
// WANDERING
elseif state == VILLAGER_STATE_WANDERING then
// PARALYZED
elseif state == VILLAGER_STATE_PARALYZED then
call PauseUnit(ani.u, true)
endif
set ani.lastState = ani.state
set ani.state = state
endif
endfunction
private function GetBlood takes unit u returns integer
if GetUnitTypeId(u) == RABBIT then
return MAX_BLOOD_RABBIT
endif
if GetUnitTypeId(u) == CHICKEN then
return MAX_BLOOD_CHICKEN
endif
if GetUnitTypeId(u) == RACOON then
return MAX_BLOOD_RACOON
endif
if GetUnitTypeId(u) == PIG then
return MAX_BLOOD_PIG
endif
if GetUnitTypeId(u) == SHEEP then
return MAX_BLOOD_SHEEP
endif
if GetUnitTypeId(u) == DEER then
return MAX_BLOOD_DEER
endif
return MAX_BLOOD
endfunction
function OnAnimalDead takes nothing returns nothing
local Animal ani = GetHandleData(GetTriggeringTrigger())
local integer i = 0
set AnimalCount = AnimalCount - 1
loop
exitwhen i >= (ani.meatCount)
call CreateIngredient(ITEM_INGREDIENT_MEAT, GetUnitX(ani.u), GetUnitY(ani.u))
set i = i + 1
endloop
call ani.destroy()
endfunction
struct Animal
unit u = null
integer handle_id = 0
integer typeId = 0
integer blood = MAX_BLOOD
integer bloodMax = 0
// States
integer state = 0
integer lastState = 0
integer defaultState = 0
integer meatCount = 0
// Triggers
trigger onDeathTrigger = null
boolean isAggressive = false
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
// Unit and handle
set this.u = u
set this.handle_id = GetHandleId(u)
call SetHandleData(this.u, this)
set this.blood = GetBlood(u)
set this.bloodMax = GetBlood(u)
set this.meatCount = MeatCounts[GetUnitTypeId(u)]
// On death trigger
set this.onDeathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent( this.onDeathTrigger, this.u, EVENT_UNIT_DEATH )
call TriggerAddAction( this.onDeathTrigger, function OnAnimalDead )
call SetHandleData(this.onDeathTrigger, this)
set AnimalCount = AnimalCount + 1
return this
endmethod
public method destroy takes nothing returns nothing
call Debug_Message("Destroying animal struct data "+I2S(this))
if this.u != null then
call ReleaseHandleData( this.u )
set this.u = null
endif
// Destroy triggers
if this.onDeathTrigger != null then
call ReleaseHandleData( this.onDeathTrigger )
call DestroyTrigger(this.onDeathTrigger)
set this.onDeathTrigger = null
endif
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
function RegisterAnimal takes unit animal, integer defaultState returns integer
local Animal ani
// Throw double registration warning
if GetHandleData(animal) != 0 then
call Debug_Message("|cffFF0000Error:|r Double registration of animal!")
endif
// Differentiate between aggressive and non-aggressive?
set ani = Animal.create(animal)
// Set default state
set ani.defaultState = defaultState
call SetAnimalState(ani, defaultState)
call SetUnitOwner(animal, Player(PLAYER_NEUTRAL_PASSIVE), false)
if GetUnitTypeId(animal) == WILD_WOLF or GetUnitTypeId(animal) == GIANT_WOLF or GetUnitTypeId(animal) == BEAR then
set ani.isAggressive = true
call SetUnitOwner(animal, Player(10), false)
endif
// Register for damage detection
call StructuredDD.add(animal)
return ani
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set MeatCounts = Table.create()
set MeatCounts[RABBIT] = 1
set MeatCounts[CHICKEN] = 1
set MeatCounts[RACOON] = 1
set MeatCounts[PIG] = 1
set MeatCounts[SHEEP] = 1
set MeatCounts[DEER] = 2
set MeatCounts[WILD_WOLF] = 2
set MeatCounts[GIANT_WOLF] = 3
set MeatCounts[BEAR] = 3
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CreateAnimals initializer Init
globals
private intpool animalTypePool
private constant real ANIMAL_RESPAWN_PERIOD = 45.0
endglobals
private function RegisterAnimalConditions takes nothing returns boolean
return IsAnimal(GetFilterUnit())
endfunction
private function RespawnAnimalConditions takes nothing returns boolean
return ( AnimalCount < ANIMAL_MAX_COUNT )
endfunction
private function CreateAnimal takes nothing returns nothing
local integer i
local real x
local real y
local unit u
// Determine spawning area
set i = AnimalAreaPool.getRandomInt()
set x = GetRandomReal(GetRectMinX(AnimalAreas[i]), GetRectMaxX(AnimalAreas[i]))
set y = GetRandomReal(GetRectMinY(AnimalAreas[i]), GetRectMaxY(AnimalAreas[i]))
// Determine unit type
set i = animalTypePool.getRandomInt()
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), i, x, y, bj_UNIT_FACING)
call RegisterAnimal(u, VILLAGER_STATE_WANDERING)
set u = null
endfunction
private function CreateStartAnimals takes nothing returns nothing
local integer i = 0
local integer j
local group targets = NewGroup()
local unit t
local real x
local real y
// Register pre-placed animals
// ===============================================================
call GroupEnumUnitsInRect(targets, bj_mapInitialPlayableArea, Condition(function RegisterAnimalConditions))
loop
set t = FirstOfGroup(targets)
exitwhen t == null
call RegisterAnimal(t, VILLAGER_STATE_WANDERING)
call GroupRemoveUnit(targets, t)
endloop
// Create a bunch of procedural animals
// ===============================================================
set i = 0
loop
exitwhen i > (ANIMAL_MAX_COUNT-1)
call CreateAnimal()
set i = i + 1
endloop
set t = null
call Debug_Message("AnimalCount: "+I2S(AnimalCount) )
endfunction
private function CreateCritters takes nothing returns nothing
local integer i
local integer j
local unit u
local real x
local real y
// Create spiders
set i = 0
loop
exitwhen i > (SPIDER_COUNT-1)
// Determine spawning area
set j = AnimalAreaPool.getRandomInt()
set x = GetRandomReal(GetRectMinX(AnimalAreas[j]), GetRectMaxX(AnimalAreas[j]))
set y = GetRandomReal(GetRectMinY(AnimalAreas[j]), GetRectMaxY(AnimalAreas[j]))
set j = GetRandomInt(0,9)
if j >= 2 then
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'n00C', x, y, bj_UNIT_FACING)
else
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'nfro', x, y, bj_UNIT_FACING)
endif
set i = i + 1
endloop
set u = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set animalTypePool = intpool.create()
call animalTypePool.addInt(RABBIT, RABBIT_WEIGHT)
call animalTypePool.addInt(RACOON, RACOON_WEIGHT)
call animalTypePool.addInt(DEER, DEER_WEIGHT)
call animalTypePool.addInt(WILD_WOLF, WOLF_WEIGHT)
call animalTypePool.addInt(BEAR, BEAR_WEIGHT)
// Create full animal load at game start
set trg = CreateTrigger()
call TriggerAddAction( trg, function CreateStartAnimals )
call TriggerExecute(trg)
call DestroyTrigger(trg)
// Create spiders and critters at game start
set trg = CreateTrigger()
call TriggerAddAction( trg, function CreateCritters )
call TriggerExecute(trg)
call DestroyTrigger(trg)
// Periodic trigger to re-create animals
set trg = CreateTrigger()
call TriggerRegisterTimerEvent(trg, ANIMAL_RESPAWN_PERIOD, true)
call TriggerAddCondition( trg, Condition( function RespawnAnimalConditions ) )
call TriggerAddAction( trg, function CreateAnimal )
set trg = null
endfunction
endscope
//TESH.scrollpos=24
//TESH.alwaysfold=0
scope CityRats initializer Init
globals
private constant integer MAX_RATS = 50
private constant real RAT_RESPAWN_PERIOD = 45.0
private integer RatCount = 0
endglobals
private function RespawnRatsConditions takes nothing returns boolean
return ( RatCount < MAX_RATS )
endfunction
private function RatDeathConditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == CITY_RAT
endfunction
private function RatDies takes nothing returns nothing
set RatCount = RatCount - 1
call Debug_Message("A rat dies..")
endfunction
private function CreateRat takes nothing returns nothing
local integer i = GetRandomInt(1,100)
local real x
local real y
local unit u
local rect area
if i > 30 then
set area = VillageArea1
else
set area = VillageArea2
endif
set x = GetRandomReal(GetRectMinX(area), GetRectMaxX(area))
set y = GetRandomReal(GetRectMinY(area), GetRectMaxY(area))
// Spawn Rat
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), CITY_RAT, x, y, bj_UNIT_FACING)
set RatCount = RatCount + 1
set u = null
set area = null
endfunction
private function CreateStartRats takes nothing returns nothing
local integer i = 0
// Create a bunch of procedural rats
// ===============================================================
set i = 0
loop
exitwhen i > (MAX_RATS-1)
call CreateRat()
set i = i + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
// Create rats at game start
set trg = CreateTrigger()
call TriggerAddAction( trg, function CreateStartRats )
call TriggerExecute(trg)
call DestroyTrigger(trg)
// Periodic trigger to re-create rats
set trg = CreateTrigger()
call TriggerRegisterTimerEvent(trg, RAT_RESPAWN_PERIOD, true)
call TriggerAddCondition( trg, Condition( function RespawnRatsConditions ) )
call TriggerAddAction( trg, function CreateRat )
// Rat dies
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( trg, Condition( function RatDeathConditions ) )
call TriggerAddAction( trg, function RatDies )
set trg = null
endfunction
endscope
//TESH.scrollpos=6
//TESH.alwaysfold=0
library ExperienceSystem initializer Init
//Configuration globals
globals
private real XP_CARRY = 0
endglobals
private function CreateXPTag takes unit u, string s returns nothing
local texttag t = CreateTextTag()
local integer playerId = GetPlayerId(GetOwningPlayer(u))
call SetTextTagColor(t, 182, 91, 234, 255)
call SetTextTagText(t, s, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 1)
call SetTextTagLifespan(t, 2)
call SetTextTagPermanent(t, false)
if Player(playerId) == GetLocalPlayer() then
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
//This applies the XP accordingly.
function GiveXP takes unit u, integer XP returns nothing
call AddHeroXP(u, XP, false)
call CreateXPTag(u, "+" + I2S(XP))
endfunction
//This trigger stops players from gaining XP when they shouldn't be.
private function Cut_XP_Gain takes nothing returns nothing
local integer i = 0
loop
exitwhen i > 12
call SetPlayerHandicapXP(Player(i), 0.00)
set i = i + 1
endloop
call DestroyTimer(GetExpiredTimer())
endfunction
private function Init takes nothing returns nothing // by MoCo
call Cut_XP_Gain()
endfunction
endlibrary
//TESH.scrollpos=26
//TESH.alwaysfold=0
scope Weather initializer Init
globals
private constant real RAIN_CHANCE = 15 // 15
private constant real RAIN_CHECK_TIME = 60
private constant real RAIN_DURATION_MIN = 60
private constant real RAIN_DURATION_MAX = 300
private constant integer RAIN_EFFECT = 'RLhr'
private weathereffect Rain
private boolean isRaining = false
endglobals
// Ashenvale heavy 'RAhr'
// Ashenvale light 'RAlr'
// lor heavy 'RLhr'
// Lor light 'RLlr'
private function Rain_Over takes nothing returns nothing
local timer t = GetExpiredTimer()
call ReleaseTimer(t)
call EnableWeatherEffect( Rain, false )
set isRaining = false
set t = null
endfunction
private function Check_Raining takes nothing returns nothing
local real r = GetRandomReal(0,100)
local timer t
local real rain_time
if r <= RAIN_CHANCE and not isRaining then
set isRaining = true
set rain_time = GetRandomReal(RAIN_DURATION_MIN, RAIN_DURATION_MAX)
call EnableWeatherEffect( Rain, true )
set t = NewTimer()
call TimerStart(t, rain_time, false, function Rain_Over)
endif
set t = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set Rain = AddWeatherEffect(bj_mapInitialPlayableArea, RAIN_EFFECT)
call EnableWeatherEffect( Rain, false )
set trg = CreateTrigger()
call TriggerRegisterTimerEvent(trg, RAIN_CHECK_TIME, true)
call TriggerAddAction( trg, function Check_Raining )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Gates initializer Init requires BasicFunctions, TimerUtils
globals
destructable array Gates[1]
private destructable array Portculis[1]
boolean array GatesOpen[1]
timer array GateTimers[1]
constant real GATE_OPEN_TIMEOUT = 9
endglobals
function OnGateClose takes nothing returns nothing
local integer i = GetTimerData(GetExpiredTimer())
call DestructableRestoreLife(Gates[i], GetDestructableMaxLife(Gates[i]), true)
endfunction
function OpenGate takes integer i returns nothing
call KillDestructable(Gates[i])
call TimerStart(GateTimers[i], GATE_OPEN_TIMEOUT, false, function OnGateClose)
endfunction
private function Conditions takes nothing returns boolean
return IsVillager(GetTriggerUnit()) or IsHunter(GetTriggerUnit()) or ( IsVampire(GetTriggerUnit()) and UnitHasItemOfType(GetTriggerUnit(), VAMPIRE_ITEM_CITY_GATE_KEY) ) or GetUnitTypeId(GetTriggerUnit()) == VAMPIRE_VILLAGER
endfunction
private function Gate1 takes nothing returns nothing
call OpenGate(1)
endfunction
private function Gate2 takes nothing returns nothing
call OpenGate(2)
endfunction
private function Gate3 takes nothing returns nothing
call OpenGate(3)
endfunction
private function Gate4 takes nothing returns nothing
call OpenGate(4)
endfunction
private function Gate5 takes nothing returns nothing
call OpenGate(5)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set Gates[1] = gg_dest_B004_0296 // South
set Gates[2] = gg_dest_B005_1231 // East
set Gates[3] = gg_dest_B006_0439 // North-East
set Gates[4] = gg_dest_B006_1121 // Noth-West
set Gates[5] = gg_dest_B00A_4563 // West
set Portculis[0] = null
set Portculis[1] = gg_dest_B007_0691
set Portculis[2] = gg_dest_B007_2189
set Portculis[3] = gg_dest_B007_2179
call SetDestructableInvulnerable(Gates[1], true)
call SetDestructableInvulnerable(Gates[2], true)
call SetDestructableInvulnerable(Gates[3], true)
call SetDestructableInvulnerable(Gates[4], true)
call SetDestructableInvulnerable(Gates[5], true)
call SetDestructableInvulnerable(Portculis[1], true)
call SetDestructableInvulnerable(Portculis[2], true)
call SetDestructableInvulnerable(Portculis[3], true)
set GatesOpen[1] = false
set GatesOpen[2] = false
set GatesOpen[3] = false
set GatesOpen[4] = false
set GatesOpen[5] = false
set GateTimers[1] = NewTimer()
set GateTimers[2] = NewTimer()
set GateTimers[3] = NewTimer()
set GateTimers[4] = NewTimer()
set GateTimers[5] = NewTimer()
call SetTimerData(GateTimers[1], 1)
call SetTimerData(GateTimers[2], 2)
call SetTimerData(GateTimers[3], 3)
call SetTimerData(GateTimers[4], 4)
call SetTimerData(GateTimers[5], 5)
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, gg_rct_Gate1 )
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction( trg, function Gate1 )
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, gg_rct_Gate2 )
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction( trg, function Gate2 )
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, gg_rct_Gate3 )
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction( trg, function Gate3 )
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, gg_rct_Gate4 )
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction( trg, function Gate4 )
set trg = CreateTrigger( )
call TriggerRegisterEnterRectSimple( trg, gg_rct_Gate5 )
call TriggerAddCondition(trg, Condition(function Conditions))
call TriggerAddAction( trg, function Gate5 )
set trg = null
endfunction
endlibrary
//TESH.scrollpos=6
//TESH.alwaysfold=0
scope NeutralVampires initializer Init
globals
private timer VampireTimer
private constant real NEUTRAL_VAMPIRE_INTERVAL = 10 // 30
private intpool spawnArea
endglobals
private function SpawnNeutralVampire takes nothing returns nothing
local integer i
local real x
local real y
local rect r = null
local unit u = null
local effect e = null
set i = spawnArea.getRandomInt()
if i == 1 then
set r = gg_rct_VillageArea1
endif
if i == 2 then
set r = gg_rct_VillageArea2
endif
if i == 3 then
set r = gg_rct_AnimalArea1
endif
if i == 4 then
set r = gg_rct_AnimalArea2
endif
if i == 5 then
set r = gg_rct_AnimalArea3
endif
set x = GetRandomReal(GetRectMinX(r), GetRectMaxX(r))
set y = GetRandomReal(GetRectMinY(r), GetRectMaxY(r))
set u = CreateUnit(Player(9), SPAWN, x, y, bj_UNIT_FACING)
set e = AddSpecialEffect("Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl", GetUnitX(u), GetUnitY(u))
call DestroyEffect(e)
call RegisterSpawn(u)
set r = null
set u = null
set e = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set VampireTimer = NewTimer()
set spawnArea = intpool.create()
call spawnArea.addInt(1, 1.0) // Village area 1
call spawnArea.addInt(2, 0.5) // Village area 2
call spawnArea.addInt(3, 1.0) // Forest South
call spawnArea.addInt(4, 0.6) // Forest East
call spawnArea.addInt(5, 1.0) // Forest North
call TimerStart(VampireTimer, NEUTRAL_VAMPIRE_INTERVAL, true, function SpawnNeutralVampire)
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GhostMerchant initializer Init
globals
private constant real STAY_TIME_MIN = 60
private constant real STAY_TIME_MAX = 120
private constant real NEXT_VISIT_TIME_MIN = 180
private constant real NEXT_VISIT_TIME_MAX = 300
private constant integer ITEM_COUNT_MIN = 5
private constant integer ITEM_COUNT_MAX = 7
private unit GhostMerchant = null
private boolean GhostMerchantOnMap = false
private timer GhostMerchantTimer
endglobals
private function GhostMerchantToggle takes nothing returns nothing
local integer i
local integer j
local real x
local real y
local real count
// Ghost Merchant arrives
if not GhostMerchantOnMap then
set GhostMerchantOnMap = true
// Display info message for vampire players
call Shadow_Message(0, "Hurry! The Ghost Merchant has been spotted somewhere in the forests.", true)
// Determine spawn points
set i = AnimalAreaPool.getRandomInt()
set x = GetRandomReal(GetRectMinX(AnimalAreas[i]), GetRectMaxX(AnimalAreas[i]))
set y = GetRandomReal(GetRectMinY(AnimalAreas[i]), GetRectMaxY(AnimalAreas[i]))
if DEBUG_MODE and FORCE_TEST_SPAWN then
set x = -3072
set y = -7160
endif
// Create Ghost Merchant
set GhostMerchant = CreateUnit(Player(9), GHOST_MERCHANT, x, y, 270)
call SetUnitVertexColor(GhostMerchant, 255, 255, 255, 100)
call PingMinimapForForceEx(ForceVampires, x, y, 6.0, bj_MINIMAPPINGSTYLE_SIMPLE, 171, 236, 255)
call ShareVision(GhostMerchant, 0, 5, true)
// Add some items
call CreateVampireItemPool()
set count = GetRandomInt(ITEM_COUNT_MIN, ITEM_COUNT_MAX)
set i = 0
loop
exitwhen i > (count-1)
set j = VampireItems.getRandomInt()
call VampireItems.removeInt(j)
call AddItemToStock(GhostMerchant, j, 1, 1)
set i = i + 1
endloop
// Start timer til leave
call TimerStart(GhostMerchantTimer, GetRandomReal(STAY_TIME_MIN, STAY_TIME_MAX), false, function GhostMerchantToggle)
// Ghost Merchant leaves
else
set GhostMerchantOnMap = false
// Display info message for vampire players
call Shadow_Message(0, "The Ghost Merchant has left but will return soon enough.", true)
call KillUnit(GhostMerchant)
set GhostMerchant = null
// Start timer til next arrival
if DEBUG_MODE and FORCE_TEST_SPAWN then
call TimerStart(GhostMerchantTimer, GetRandomReal(5, 10), false, function GhostMerchantToggle)
else
call TimerStart(GhostMerchantTimer, GetRandomReal(NEXT_VISIT_TIME_MIN, NEXT_VISIT_TIME_MAX), false, function GhostMerchantToggle)
endif
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set GhostMerchantTimer = NewTimer()
// Start timer til next arrival
if DEBUG_MODE and FORCE_TEST_SPAWN then
call TimerStart(GhostMerchantTimer, GetRandomReal(5, 10), false, function GhostMerchantToggle)
else
call TimerStart(GhostMerchantTimer, GetRandomReal(NEXT_VISIT_TIME_MIN, NEXT_VISIT_TIME_MAX), false, function GhostMerchantToggle)
endif
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Baron initializer Init
private function Actions takes nothing returns nothing
local unit u = GetDyingUnit()
call Game_Message(GetHeroProperName(u)+" has been killed! Overlord " + PlayerNames[OverlordPlayer]+" wins the game!")
call GameVictory(PLAYER_VAMPIRES_START_ID, PLAYER_VAMPIRES_END_ID)
call GameDefeat(PLAYER_HUNTERS_START_ID, PLAYER_HUNTERS_END_ID)
set u = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger( )
call TriggerRegisterUnitEvent( trg, gg_unit_H001_0006, EVENT_UNIT_DEATH )
call TriggerAddAction( trg, function Actions )
endfunction
endscope
//TESH.scrollpos=48
//TESH.alwaysfold=0
scope Zombies initializer Init
globals
private constant real ZOMBIE_ASSAULT_DURATION_MIN = 60
private constant real ZOMBIE_ASSAULT_DURATION_MAX = 120
private constant real NEXT_ZOMBIE_ASSAULT_TIME_MIN = 180
private constant real NEXT_ZOMBIE_ASSAULT_TIME_MAX = 300
private constant real ZOMBIE_SPAWN_TIME_MIN = 1
private constant real ZOMBIE_SPAWN_TIME_MAX = 7
private constant integer ZOMBIE_MAX_MIN = 9
private constant integer ZOMBIE_MAX_MAX = 18
private constant integer ZOMBIE_AREA_COUNT = 2
private constant real ZOMBIE_LIFE_DURATION = 180
private rect array ZombieAreas[1]
private rect TroubleArea
private timer ZombieAssaultTimer
private timer ZombieSpawnTimer = null
private boolean ZombieAssaultActive = false
private integer ZombieCount = 0
private integer ZombieMax = 0
endglobals
private function SpawnZombies takes nothing returns nothing
local real x = GetRandomReal(GetRectMinX(TroubleArea), GetRectMaxX(TroubleArea))
local real y = GetRandomReal(GetRectMinY(TroubleArea), GetRectMaxY(TroubleArea))
local unit u
local effect e
set u = CreateUnit(Player(9), ZOMBIE, x, y, bj_UNIT_FACING)
call SetUnitAnimation(u, "birth")
call QueueUnitAnimation(u, "stand")
set e = AddSpecialEffect("Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl", x,y)
call DestroyEffect(e)
call UnitApplyTimedLife(u, 'Brai', ZOMBIE_LIFE_DURATION)
set ZombieCount = ZombieCount + 1
set u = null
set e = null
endfunction
private function ZombieSpawnCallback takes nothing returns nothing
call ReleaseTimer(ZombieSpawnTimer)
if ZombieCount < ZombieMax then
call SpawnZombies()
set ZombieSpawnTimer = NewTimer()
call TimerStart(ZombieSpawnTimer, GetRandomReal(ZOMBIE_SPAWN_TIME_MIN,ZOMBIE_SPAWN_TIME_MAX), false, function ZombieSpawnCallback)
else
set ZombieSpawnTimer = null
endif
endfunction
private function ZombieAssaultToggle takes nothing returns nothing
local real x
local real y
// Zombie assault
if not ZombieAssaultActive then
set ZombieAssaultActive = true
call Game_Message("|cff97F8D3Beware! Zombies are rising up their graves!|r")
set ZombieCount = 0
set ZombieMax = GetRandomInt(ZOMBIE_MAX_MIN,ZOMBIE_MAX_MAX)
set TroubleArea = ZombieAreas[GetRandomInt(1,ZOMBIE_AREA_COUNT)]
set x = GetRectCenterX(TroubleArea)
set y = GetRectCenterY(TroubleArea)
call PingMinimapEx(x, y, 5.0, 154, 248, 211, false)
set ZombieSpawnTimer = NewTimer()
call TimerStart(ZombieSpawnTimer, GetRandomReal(ZOMBIE_SPAWN_TIME_MIN,ZOMBIE_SPAWN_TIME_MAX), false, function ZombieSpawnCallback)
call TimerStart(ZombieAssaultTimer, GetRandomReal(ZOMBIE_ASSAULT_DURATION_MIN, ZOMBIE_ASSAULT_DURATION_MAX), false, function ZombieAssaultToggle)
// Zombie assault over
else
set ZombieAssaultActive = false
set TroubleArea = null
if ZombieSpawnTimer != null then
call ReleaseTimer(ZombieSpawnTimer)
set ZombieSpawnTimer = null
endif
call TimerStart(ZombieAssaultTimer, GetRandomReal(NEXT_ZOMBIE_ASSAULT_TIME_MIN, NEXT_ZOMBIE_ASSAULT_TIME_MAX), false, function ZombieAssaultToggle)
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set ZombieAreas[0] = null
set ZombieAreas[1] = gg_rct_TroubleArea1
set ZombieAreas[2] = gg_rct_TroubleArea2
set ZombieAssaultTimer = NewTimer()
set trg = CreateTrigger( )
// Start timer til next arrival
if DEBUG_MODE and FORCE_TEST_SPAWN then
call TimerStart(ZombieAssaultTimer, GetRandomReal(5, 10), false, function ZombieAssaultToggle)
else
call TimerStart(ZombieAssaultTimer, GetRandomReal(NEXT_ZOMBIE_ASSAULT_TIME_MIN, NEXT_ZOMBIE_ASSAULT_TIME_MAX), false, function ZombieAssaultToggle)
endif
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
library ItemFunctions initializer Init requires BasicFunctions
globals
private Table ItemRegister
Table IngredientTable
private item TempItem
integer array IngrediantMaxPieces[1]
string array IngrediantNames[1]
constant real REGROWTH_TIME = 60.
intpool ForestItems
// Hunter Items
constant integer ITEM_GOLD = 'I01D'
constant integer ITEM_VAMPIRE_TRACKER = 'I01F'
constant integer ITEM_ARMOR_SMALL = 'I00E'
constant integer ITEM_ARMOR_MEDIUM = 'I00D'
constant integer ITEM_ARMOR_HEAVY = 'I008'
constant integer ITEM_WEAPON_GUNSLINGER_T1 = 'I00F'
constant integer ITEM_WEAPON_GUNSLINGER_T2 = 'I00G'
constant integer ITEM_WEAPON_GUNSLINGER_T3 = 'I00H'
constant integer ITEM_WEAPON_ASSASSIN_T1 = 'I00L'
constant integer ITEM_WEAPON_ASSASSIN_T2 = 'I00M'
constant integer ITEM_WEAPON_ASSASSIN_T3 = 'I00N'
constant integer ITEM_WEAPON_MAGE_T1 = 'I00I'
constant integer ITEM_WEAPON_MAGE_T2 = 'I00J'
constant integer ITEM_WEAPON_MAGE_T3 = 'I00K'
constant integer PRICE_TAG_WEAPON_T1 = 500
constant integer PRICE_TAG_WEAPON_T2 = 1000
constant integer PRICE_TAG_WEAPON_T3 = 1500
// Vampire items
// Ingredients
// Ingredients
// ==================================================================================
constant integer INGREDIENT_CANDLE = 1
constant integer INGREDIENT_SKULL = 2
constant integer INGREDIENT_MEAT = 3
constant integer INGREDIENT_HEART = 4
constant integer INGREDIENT_PUMPKIN = 5
constant integer INGREDIENT_GREEN_MUSHROOM = 6
constant integer INGREDIENT_BLUE_TRUFFLE = 7
constant integer INGREDIENT_GLIMMERWEED = 8
constant integer INGREDIENT_WINE = 9
constant integer INGREDIENT_GHOST_ESSENCE = 10
constant integer INGREDIENTS_MAX = 10
constant integer INGREDIENTS_MAX_PLUS_ONE = 11
constant integer ITEM_INGREDIENT_CANDLE = 'I005'
constant integer ITEM_INGREDIENT_SKULL = 'I00P'
constant integer ITEM_INGREDIENT_MEAT = 'I00B'
constant integer ITEM_INGREDIENT_HEART = 'I004'
constant integer ITEM_INGREDIENT_GREEN_MUSHROOM = 'I001'
constant integer ITEM_INGREDIENT_GLIMMERWEED = 'I00V'
constant integer ITEM_INGREDIENT_PUMPKIN = 'I006'
constant integer ITEM_INGREDIENT_BLUE_TRUFFLE = 'I00O'
constant integer ITEM_INGREDIENT_WINE = 'I003'
constant integer ITEM_INGREDIENT_GHOST_ESSENCE = 'I000'
constant integer INGREDIENT_INFO_CANDLE = 'A01N'
constant integer INGREDIENT_INFO_SKULL = 'A01M'
constant integer INGREDIENT_INFO_MEAT = 'A01Q'
constant integer INGREDIENT_INFO_HEART = 'A01P'
constant integer INGREDIENT_INFO_GREEN_MUSHROOM = 'A01R'
constant integer INGREDIENT_INFO_GLIMMERWEED = 'A01T'
constant integer INGREDIENT_INFO_PUMPKIN = 'A01S'
constant integer INGREDIENT_INFO_BLUE_TRUFFLE = 'A01V'
constant integer INGREDIENT_INFO_WINE = 'A01W'
constant integer INGREDIENT_INFO_GHOST_ESSENCE = 'A01X'
constant integer INGREDIENT_MAX_CANDLE = 10
constant integer INGREDIENT_MAX_SKULL = 6
constant integer INGREDIENT_MAX_MEAT = 6
constant integer INGREDIENT_MAX_HEART = 8
constant integer INGREDIENT_MAX_PUMPKIN = 4
constant integer INGREDIENT_MAX_GREEN_MUSHROOM = 10
constant integer INGREDIENT_MAX_BLUE_TRUFFLE = 10
constant integer INGREDIENT_MAX_GLIMMERWEED = 8
constant integer INGREDIENT_MAX_WINE = 6
constant integer INGREDIENT_MAX_GHOST_ESSENCE = 8
endglobals
function RegisterItem takes item i returns nothing
set ItemRegister[GetHandleId(i)] = 1
// call Debug_Message("registering item "+GetItemName(i))
endfunction
function ReleaseItem takes item i returns nothing
call ItemRegister.remove(GetHandleId(i))
endfunction
function IsItemRegistered takes item i returns boolean
return ItemRegister.has(GetHandleId(i))
endfunction
function IsIngredient takes item thisItem returns boolean
return GetItemLevel(thisItem) == 8
endfunction
function CreateAnyItem takes integer itemId, real x, real y returns nothing
local item i = CreateItem(itemId, x, y)
if IsIngredient(i) then
call RegisterItem(i)
endif
set i = null
endfunction
function CreateIngredient takes integer itemId, real x, real y returns nothing
local item i = CreateItem(itemId, x, y)
call RegisterItem(i)
set i = null
endfunction
function IsHunterItem takes item thisItem returns boolean
return GetItemLevel(thisItem) <= 5
endfunction
function IsVampireItem takes item thisItem returns boolean
return GetItemLevel(thisItem) >= 7
endfunction
function IsArmor takes item thisItem returns boolean
return GetItemTypeId(thisItem) == ITEM_ARMOR_SMALL or GetItemTypeId(thisItem) == ITEM_ARMOR_MEDIUM or GetItemTypeId(thisItem) == ITEM_ARMOR_HEAVY
endfunction
function IsWeapon takes item thisItem returns boolean
return GetItemLevel(thisItem) >= 2 and GetItemLevel(thisItem) <= 4
endfunction
function IsWeaponUsable takes item thisItem, unit u returns boolean
if GetItemLevel(thisItem) == 2 and GetUnitTypeId(u) == GUNSLINGER then
return true
endif
if GetItemLevel(thisItem) == 3 and GetUnitTypeId(u) == ASSASSIN then
return true
endif
if GetItemLevel(thisItem) == 4 and ( GetUnitTypeId(u) == MAGE or GetUnitTypeId(u) == FIRE_MAGE or GetUnitTypeId(u) == FROST_MAGE) then
return true
endif
return false
endfunction
function IsRegrowthItem takes item ingredient returns boolean
if GetItemTypeId(ingredient) == ITEM_INGREDIENT_GREEN_MUSHROOM then
return true
endif
if GetItemTypeId(ingredient) == ITEM_INGREDIENT_BLUE_TRUFFLE then
return true
endif
if GetItemTypeId(ingredient) == ITEM_INGREDIENT_GLIMMERWEED then
return true
endif
return false
endfunction
function IsGold takes item thisItem returns boolean
return GetItemTypeId(thisItem) == ITEM_GOLD
endfunction
function IsRemovalItem takes integer itemId returns boolean
if itemId == ITEM_INGREDIENT_SKULL then
return true
endif
if itemId == ITEM_INGREDIENT_PUMPKIN then
return true
endif
if itemId == ITEM_WEAPON_GUNSLINGER_T1 then
return true
endif
if itemId == ITEM_WEAPON_GUNSLINGER_T2 then
return true
endif
if itemId == ITEM_WEAPON_GUNSLINGER_T3 then
return true
endif
if itemId == ITEM_WEAPON_ASSASSIN_T1 then
return true
endif
if itemId == ITEM_WEAPON_ASSASSIN_T2 then
return true
endif
if itemId == ITEM_WEAPON_ASSASSIN_T3 then
return true
endif
if itemId == ITEM_WEAPON_MAGE_T1 then
return true
endif
if itemId == ITEM_WEAPON_MAGE_T2 then
return true
endif
if itemId == ITEM_WEAPON_MAGE_T3 then
return true
endif
return false
endfunction
function GetItemOfTypeWeapon takes unit u, item pickedItem returns item
local integer i = 0
local boolean done = false
local item checkItem
set TempItem = null
// count items of this class
set i = 0
loop
exitwhen i > 5 or done
set checkItem = UnitItemInSlot(u, i)
if IsWeapon(checkItem) and checkItem != pickedItem then
set TempItem = checkItem
set done = true
endif
set i = i + 1
endloop
set checkItem = null
return TempItem
endfunction
function GetItemOfTypeArmor takes unit u, item pickedItem returns item
local integer i = 0
local boolean done = false
local item checkItem
set TempItem = null
// count items of this class
set i = 0
loop
exitwhen i > 5 or done
set checkItem = UnitItemInSlot(u, i)
if IsArmor(checkItem) and checkItem != pickedItem then
set TempItem = checkItem
set done = true
endif
set i = i + 1
endloop
set checkItem = null
return TempItem
endfunction
function DetroyItem takes item i returns nothing
if ItemRegister.has(GetHandleId(i)) then
call ItemRegister.remove(GetHandleId(i))
endif
call RemoveItem(i)
endfunction
function DropItem takes unit u, item i, real x, real y returns nothing
local integer itemType = GetItemTypeId(i)
if IsIngredient(i) then
call DetroyItem(i)
call CreateIngredient(itemType, x, y)
else
call Debug_Message("drop item "+GetItemName(i))
call UnitRemoveItem(u, i)
call SetItemPosition(i, x, y)
if not IsItemRegistered(i) then
call RegisterItem(i)
endif
endif
endfunction
function RemoveOrDropItem takes unit u, item pickedItem, integer itemId, real x, real y returns nothing
// If skull or pumpkin out of shop then remove
if IsRemovalItem(itemId) and not IsItemRegistered(pickedItem) then
call Debug_Message("RemoveOrDropItem: Destroy item")
call DetroyItem(pickedItem)
// else drop item
else
call Debug_Message("RemoveOrDropItem: Drop item")
call DropItem(u, pickedItem, x, y)
endif
endfunction
function GetWeaponCost takes integer itemId returns integer
if itemId == ITEM_WEAPON_GUNSLINGER_T1 or itemId == ITEM_WEAPON_ASSASSIN_T1 or itemId == ITEM_WEAPON_MAGE_T1 then
return PRICE_TAG_WEAPON_T1
endif
if itemId == ITEM_WEAPON_GUNSLINGER_T2 or itemId == ITEM_WEAPON_ASSASSIN_T2 or itemId == ITEM_WEAPON_MAGE_T2 then
return PRICE_TAG_WEAPON_T2
endif
if itemId == ITEM_WEAPON_GUNSLINGER_T3 or itemId == ITEM_WEAPON_ASSASSIN_T3 or itemId == ITEM_WEAPON_MAGE_T3 then
return PRICE_TAG_WEAPON_T3
endif
return 0
endfunction
private function InitItems takes nothing returns nothing
// Create tables
set ItemRegister = Table.create()
set IngredientTable = Table.create()
// Set table to receive ingredient ID for itemId
set IngredientTable[ITEM_INGREDIENT_CANDLE] = INGREDIENT_CANDLE
set IngredientTable[ITEM_INGREDIENT_SKULL] = INGREDIENT_SKULL
set IngredientTable[ITEM_INGREDIENT_MEAT] = INGREDIENT_MEAT
set IngredientTable[ITEM_INGREDIENT_HEART] = INGREDIENT_HEART
set IngredientTable[ITEM_INGREDIENT_GREEN_MUSHROOM] = INGREDIENT_GREEN_MUSHROOM
set IngredientTable[ITEM_INGREDIENT_PUMPKIN] = INGREDIENT_PUMPKIN
set IngredientTable[ITEM_INGREDIENT_GLIMMERWEED] = INGREDIENT_GLIMMERWEED
set IngredientTable[ITEM_INGREDIENT_BLUE_TRUFFLE] = INGREDIENT_BLUE_TRUFFLE
set IngredientTable[ITEM_INGREDIENT_WINE] = INGREDIENT_WINE
set IngredientTable[ITEM_INGREDIENT_GHOST_ESSENCE] = INGREDIENT_GHOST_ESSENCE
set IngredientInfoAbilities[INGREDIENT_CANDLE] = INGREDIENT_INFO_CANDLE
set IngredientInfoAbilities[INGREDIENT_SKULL] = INGREDIENT_INFO_SKULL
set IngredientInfoAbilities[INGREDIENT_MEAT] = INGREDIENT_INFO_MEAT
set IngredientInfoAbilities[INGREDIENT_HEART] = INGREDIENT_INFO_HEART
set IngredientInfoAbilities[INGREDIENT_GREEN_MUSHROOM] = INGREDIENT_INFO_GREEN_MUSHROOM
set IngredientInfoAbilities[INGREDIENT_PUMPKIN] = INGREDIENT_INFO_PUMPKIN
set IngredientInfoAbilities[INGREDIENT_GLIMMERWEED] = INGREDIENT_INFO_GLIMMERWEED
set IngredientInfoAbilities[INGREDIENT_BLUE_TRUFFLE] = INGREDIENT_INFO_BLUE_TRUFFLE
set IngredientInfoAbilities[INGREDIENT_WINE] = INGREDIENT_INFO_WINE
set IngredientInfoAbilities[INGREDIENT_GHOST_ESSENCE] = INGREDIENT_INFO_GHOST_ESSENCE
set IngrediantMaxPieces[INGREDIENT_CANDLE] = INGREDIENT_MAX_CANDLE
set IngrediantMaxPieces[INGREDIENT_SKULL] = INGREDIENT_MAX_SKULL
set IngrediantMaxPieces[INGREDIENT_MEAT] = INGREDIENT_MAX_MEAT
set IngrediantMaxPieces[INGREDIENT_HEART] = INGREDIENT_MAX_HEART
set IngrediantMaxPieces[INGREDIENT_GREEN_MUSHROOM] = INGREDIENT_MAX_GREEN_MUSHROOM
set IngrediantMaxPieces[INGREDIENT_PUMPKIN] = INGREDIENT_MAX_PUMPKIN
set IngrediantMaxPieces[INGREDIENT_GLIMMERWEED] = INGREDIENT_MAX_GLIMMERWEED
set IngrediantMaxPieces[INGREDIENT_BLUE_TRUFFLE] = INGREDIENT_MAX_BLUE_TRUFFLE
set IngrediantMaxPieces[INGREDIENT_WINE] = INGREDIENT_MAX_WINE
set IngrediantMaxPieces[INGREDIENT_GHOST_ESSENCE] = INGREDIENT_MAX_GHOST_ESSENCE
set IngrediantNames[INGREDIENT_CANDLE] = "|cffFBF0C8+1 candle|r"
set IngrediantNames[INGREDIENT_SKULL] = "|cffDBDBDB+1 skull|r"
set IngrediantNames[INGREDIENT_MEAT] = "|cffF57575+1 meat|r"
set IngrediantNames[INGREDIENT_HEART] = "|cffE02339+1 human heart|r"
set IngrediantNames[INGREDIENT_GREEN_MUSHROOM] = "|cff8BFF8B+1 green mushroom|r"
set IngrediantNames[INGREDIENT_PUMPKIN] = "|cffF4A564+1 pumpkin|r"
set IngrediantNames[INGREDIENT_GLIMMERWEED] = "|cff43CDB1+1 glimmerweed|r"
set IngrediantNames[INGREDIENT_BLUE_TRUFFLE] = "|cff7DB2FB+1 blue truffle|r"
set IngrediantNames[INGREDIENT_WINE] = "|cff56897A+1 wine|r"
set IngrediantNames[INGREDIENT_GHOST_ESSENCE] = "|cffABF2EF+1 ghost essence|r"
set ForestItems = intpool.create()
call ForestItems.addInt( ITEM_INGREDIENT_GREEN_MUSHROOM, 1.00)
call ForestItems.addInt( ITEM_INGREDIENT_GLIMMERWEED, 0.50)
call ForestItems.addInt( ITEM_INGREDIENT_BLUE_TRUFFLE, 0.18)
call Debug_Message("Items successfully initialized!")
endfunction
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger()
call TriggerAddAction(trg, function InitItems)
call TriggerExecute(trg)
set trg = null
endfunction
endlibrary
//TESH.scrollpos=173
//TESH.alwaysfold=0
scope Ingredients initializer Init
globals
endglobals
private function ItemManipulateConditions takes nothing returns boolean
return GetUnitTypeId(GetManipulatingUnit()) != SAFE_SYSTEM_SAFE
endfunction
private function DisplayIngredientsTag takes unit u, string s, integer id returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1.5)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
private function RegrowForestItem takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer iType
local integer i
local real x
local real y
call ReleaseTimer(t)
set t = null
call Debug_Message("Regrow forest item")
set iType = ForestItems.getRandomInt()
// Determine spawning area
set i = AnimalAreaPool.getRandomInt()
set x = GetRandomReal(GetRectMinX(AnimalAreas[i]), GetRectMaxX(AnimalAreas[i]))
set y = GetRandomReal(GetRectMinY(AnimalAreas[i]), GetRectMaxY(AnimalAreas[i]))
call CreateIngredient(iType, x, y)
endfunction
private function RegisterPreplacedIngrediants takes nothing returns nothing
local item ingredient = GetFilterItem()
if IsIngredient(ingredient) then
call RegisterItem(ingredient)
endif
set ingredient = null
endfunction
// Removel Item = Items that are not registered and infinitely available in shops (pumpkins, skulls)
private function ItemManipulate takes nothing returns nothing
local unit u = GetManipulatingUnit()
local item pickedItem = GetManipulatedItem()
local item checkItem = null
local integer playerId = GetPlayerId(GetOwningPlayer(u))
local integer itemTypeId = GetItemTypeId(pickedItem)
local real x = GetItemX(pickedItem)
local real y = GetItemY(pickedItem)
local Vampire vamp
local Hunter hunter
local integer ingredientId
local timer t = null
local integer i
local boolean pickup = false
// Pickup or drop?
if GetTriggerEventId() == EVENT_PLAYER_UNIT_PICKUP_ITEM then
set pickup = true
call Debug_Message("on item manipulate (pickup)")
else
call Debug_Message("on item manipulate (drop)")
endif
// Pickup an item
// =============================================================================================
if pickup then
// Vampire items
if IsVampireItem(pickedItem) and not IsUndead(u) then
call Problem_Message(playerId, "You cannot use this item!")
call RemoveOrDropItem(u, pickedItem, itemTypeId, x, y)
// Hunter items
elseif IsHunterItem(pickedItem) and IsUndead(u) then
call Problem_Message(playerId, "You cannot use this item!")
if IsGold(pickedItem) then
call RemoveItem(pickedItem)
call CreateItem(ITEM_GOLD, x, y)
else
call RemoveOrDropItem(u, pickedItem, itemTypeId, x, y)
endif
// Ingredient
// ===================================================
elseif IsIngredient(pickedItem) then
set ingredientId = IngredientTable[itemTypeId] // Get the ingredient ID
// If hero is in a form that allows pickup
if CanPickupIngredients(u) then
call Debug_Message("Vampire tries to pick up an ingredient ["+I2S(ingredientId)+"] ("+IngrediantNames[ingredientId]+")")
// Get vampire struct data
set vamp = GetHandleData(u)
// If there is still place for some more ingredients..
if vamp.getIngredientCount(ingredientId) < IngrediantMaxPieces[ingredientId] then
// Increase ingredients count
call vamp.incIngredient(ingredientId)
// If regrowth item then
if IsRegrowthItem(pickedItem) then
set t = NewTimer()
call TimerStart(t, REGROWTH_TIME, false, function RegrowForestItem)
set t = null
endif
// Remove the item
call DetroyItem(pickedItem)
// Display message or tag
call DisplayIngredientsTag(u, IngrediantNames[ingredientId], ingredientId)
// If bag is full
else
call Problem_Message(playerId, "You cannot carry any more of this ingredient type!")
// Remove or drop item
call RemoveOrDropItem(u, pickedItem, itemTypeId, x, y)
endif
// If not a vampire who picks up the igredient
else
if IsUndead(u) then
call Problem_Message(playerId, "You cannot pick up ingredients in this form!")
else
call Problem_Message(playerId, "You cannot use this item!")
endif
// Remove or drop item
call RemoveOrDropItem(u, pickedItem, itemTypeId, x, y)
endif
// On successful pickup
else
// Hunter items
if IsHunter(u) then
// Get hunter struct data
set hunter = GetHandleData(u)
// Weapons
if IsWeapon(pickedItem) then
// If not usable
if not IsWeaponUsable(pickedItem, u) then
call Problem_Message(playerId, "You cannot use this type of weapon!")
if IsItemRegistered(pickedItem) then
call Debug_Message("drop registered item")
call DropItem(u, checkItem, x, y)
else
call SetPlayerState(Player(playerId), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(Player(playerId), PLAYER_STATE_RESOURCE_GOLD) + GetWeaponCost(itemTypeId))
call DetroyItem(pickedItem)
call Debug_Message("blub")
endif
else
set checkItem = GetItemOfTypeWeapon(u, pickedItem)
// Check for two weapons at once
if checkItem != null then
call DropItem(u, checkItem, x, y)
call Warning_Message(playerId, GetItemName(checkItem)+" has been swapped with "+GetItemName(pickedItem)+". (note that you can use only one weapon at a time)")
endif
endif
// Armor
elseif IsArmor(pickedItem) then
set checkItem = GetItemOfTypeArmor(u, pickedItem)
// Check for two armor at once
if checkItem != null then
call DropItem(u, checkItem, x, y)
call Warning_Message(playerId, "Armor has been swapped! (note that you can use only one piece of armor at a time)")
endif
// Gold
elseif IsGold(pickedItem) then
call DetroyItem(pickedItem)
call hunter.bountyTime(CRATE_GOLD)
call RemoveItem(pickedItem)
// Vampire Tracker
elseif itemTypeId == ITEM_VAMPIRE_TRACKER then
call hunter.toggleTracker(true)
endif
endif
endif
// Drop item
// =============================================================================================
else
call Debug_Message("on item drop ("+GetItemName(pickedItem)+")")
// Register item
if not IsItemRegistered(pickedItem) then
call RegisterItem(pickedItem)
endif
// Hunter items
if IsHunter(u) then
// Get hunter struct data
set hunter = GetHandleData(u)
// Vampire Tracker
if itemTypeId == ITEM_VAMPIRE_TRACKER then
call hunter.toggleTracker(false)
endif
endif
endif
set u = null
set pickedItem = null
set checkItem = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
call EnumItemsInRect(bj_mapInitialPlayableArea, null, function RegisterPreplacedIngrediants)
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_DROP_ITEM )
call TriggerAddCondition( trg, Condition(function ItemManipulateConditions))
call TriggerAddAction( trg, function ItemManipulate )
call Debug_Message("Ingredients Init ok!")
endfunction
endscope
//TESH.scrollpos=75
//TESH.alwaysfold=0
scope Cauldron initializer Init
globals
private rect array CauldronAreas[1]
private region array CauldronRegions[1]
private unit array Cauldrons[1]
private boolean array CauldronsInUse[1]
private unit array CauldronUsers[1]
private integer CAULDRONS_USED = 5 // constant
private intpool CauldronPool
private constant real CAULDRON_USE_RANGE = 150
private integer CauldronCount = 0
private constant integer CAULDRON = 'h006'
endglobals
private function FreeCauldron takes integer id returns nothing
local Vampire vamp
if CauldronUsers[id] != null then
set vamp = GetHandleData(CauldronUsers[id])
set vamp.nearCauldron = false
endif
set CauldronUsers[id] = null
set CauldronsInUse[id] = false
call SetUnitOwner(Cauldrons[id], Player(PLAYER_NEUTRAL_PASSIVE), true)
call Debug_Message("Cauldron freed ("+I2S(id)+")")
endfunction
//private function LeaveCauldronArea takes nothing returns nothing
// local integer id = GetHandleData(GetTriggeringTrigger())
// local unit u = GetTriggerUnit()
// local integer playerId = GetPlayerId(GetOwningPlayer(u))
// if u == CauldronUsers[id] then
// call FreeCauldron(id)
// endif
// set u = null
//endfunction
private function CheckCauldronOccupied takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetTimerData(t)
// if not IsUnitInRegion(CauldronRegions[id], CauldronUsers[id]) or GetUnitState(CauldronUsers[id], UNIT_STATE_LIFE) <= 0 or CauldronUsers[id] == null then
if not IsUnitInRange(Cauldrons[id], CauldronUsers[id], CAULDRON_USE_RANGE) or GetUnitState(CauldronUsers[id], UNIT_STATE_LIFE) <= 0 or CauldronUsers[id] == null then
call ReleaseTimer(t)
call FreeCauldron(id)
endif
set t = null
endfunction
private function OccupyCauldron takes nothing returns nothing
local integer id = GetHandleData(GetTriggeringTrigger())
local unit u = GetTriggerUnit()
local integer playerId = GetPlayerId(GetOwningPlayer(u))
local timer t
local effect e
local Vampire vamp = GetHandleData(u)
if not CauldronsInUse[id] then
set CauldronUsers[id] = u
set CauldronsInUse[id] = true
call SetUnitOwner(Cauldrons[id], Player(playerId), true)
call Debug_Message("Cauldron occupied ("+I2S(id)+")")
set t = NewTimer()
call SetTimerData(t, id)
call TimerStart(t, 0.75, true, function CheckCauldronOccupied)
set e = AddSpecialEffect("Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl", GetUnitX(Cauldrons[id]), GetUnitY(Cauldrons[id]))
call DestroyEffect(e)
set vamp.nearCauldron = true
else
if CauldronUsers[id] != u then
call DisplayTimedTextToPlayer(Player(playerId), 0, 0, 10, "This cauldron is currently in use by another player!")
endif
endif
set e = null
set t = null
set u = null
endfunction
private function Use_Cauldron_Conditions takes nothing returns boolean
return CanPickupIngredients(GetTriggerUnit())
endfunction
private function CreateCauldron takes nothing returns nothing
local integer id
local real x
local real y
local trigger trg
// Get random cauldron from pool (and remove)
set id = CauldronPool.getRandomInt()
if DEBUG_MODE and FORCE_TEST_SPAWN then
set id = 2
endif
call CauldronPool.removeInt(id)
// Get middle of area
set x = GetRectCenterX(CauldronAreas[id])
set y = GetRectCenterY(CauldronAreas[id])
// Create cauldron there
set Cauldrons[id] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), CAULDRON, x, y, bj_UNIT_FACING)
// Now create all those triggers
// Vampire approaches cauldron
set trg = CreateTrigger()
// call TriggerRegisterEnterRegion(trg, CauldronRegions[id], null)
call TriggerRegisterUnitInRange(trg, Cauldrons[id], CAULDRON_USE_RANGE, null)
call TriggerAddCondition( trg, Condition( function Use_Cauldron_Conditions ) )
call TriggerAddAction( trg, function OccupyCauldron )
call SetHandleData(trg, id)
set trg = null
endfunction
private function Actions takes nothing returns nothing
local integer i
if DEBUG_MODE and FORCE_TEST_SPAWN then
set CAULDRONS_USED = 1
endif
set i = 0
loop
exitwhen i > (CAULDRONS_USED-1)
call CreateCauldron()
set i = i + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local integer i
set CauldronAreas[0] = null
set CauldronAreas[1] = gg_rct_CauldronArea1
set CauldronAreas[2] = gg_rct_CauldronArea2
set CauldronAreas[3] = gg_rct_CauldronArea3
set CauldronAreas[4] = gg_rct_CauldronArea4
set CauldronAreas[5] = gg_rct_CauldronArea5
set CauldronAreas[6] = gg_rct_CauldronArea6
set CauldronAreas[7] = gg_rct_CauldronArea7
set CauldronAreas[8] = gg_rct_CauldronArea8
set CauldronAreas[9] = gg_rct_CauldronArea9
set CauldronAreas[10] = gg_rct_CauldronArea10
set CauldronAreas[11] = gg_rct_CauldronArea11
set CauldronAreas[12] = gg_rct_CauldronArea12
set CauldronAreas[13] = gg_rct_CauldronArea13
set CauldronAreas[14] = gg_rct_CauldronArea14
set CauldronAreas[15] = gg_rct_CauldronArea15
set CauldronAreas[16] = gg_rct_CauldronArea16
set CauldronAreas[17] = gg_rct_CauldronArea17
set CauldronAreas[18] = gg_rct_CauldronArea18
set CauldronAreas[19] = gg_rct_CauldronArea19
set CauldronAreas[20] = gg_rct_CauldronArea20
set CauldronAreas[21] = gg_rct_CauldronArea21
set CauldronAreas[22] = gg_rct_CauldronArea22
set CauldronAreas[23] = gg_rct_CauldronArea23
set CauldronAreas[24] = gg_rct_CauldronArea24
set CauldronAreas[25] = gg_rct_CauldronArea25
set CauldronAreas[26] = gg_rct_CauldronArea26
set CauldronAreas[27] = gg_rct_CauldronArea27
set CauldronAreas[28] = gg_rct_CauldronArea28
set CauldronCount = 28
set CauldronPool = intpool.create()
set CauldronRegions[0] = null
set Cauldrons[0] = null
set CauldronsInUse[0] = false
set CauldronUsers[0] = null
set i = 1
loop
exitwhen i > CauldronCount
set Cauldrons[i] = null
set CauldronsInUse[i] = false
set CauldronUsers[i] = null
call CauldronPool.addInt(i, 1.0)
set CauldronRegions[i] = CreateRegion()
call RegionAddRect(CauldronRegions[i], CauldronAreas[i])
set i = i + 1
endloop
call Actions()
endfunction
endscope
//TESH.scrollpos=259
//TESH.alwaysfold=0
library CraftingRecipes initializer Init requires BasicFunctions
globals
constant integer CRAFTING_BLOODLINE_ELIXIR = 1
constant integer CRAFTING_ABILITY_BLOODLINE_ELIXIR = 'A01Y'
constant integer CRAFTING_ITEM_BLOODLINE_ELIXIR = 'I00A'
constant integer CRAFTING_MOONSTONE = 2
constant integer CRAFTING_ABILITY_MOONSTONE = 'A01Z'
constant integer CRAFTING_ITEM_MOONSTONE = 'I018'
constant integer CRAFTING_INVISIBILITY_POTION = 3
constant integer CRAFTING_ABILITY_INVISIBILITY_POTION = 'A020'
constant integer CRAFTING_ITEM_INVISIBILITY_POTION = 'I01B'
constant integer CRAFTING_HUMAN_POTION = 4
constant integer CRAFTING_ABILITY_HUMAN_POTION = 'A01H'
constant integer CRAFTING_ITEM_HUMAN_POTION = 'I01C'
constant integer CRAFTING_MANA_POTION = 5
constant integer CRAFTING_ABILITY_MANA_POTION = 'A022'
constant integer CRAFTING_ITEM_MANA_POTION = 'I01E'
constant integer CRAFTING_ELIXIR_OF_WISDOM = 6
constant integer CRAFTING_ABILITY_ELIXIR_OF_WISDOM = 'A024'
constant integer CRAFTING_ITEM_ELIXIR_OF_WISDOM = 'I01G'
constant integer CRAFTING_HEALTH_POTION = 7
constant integer CRAFTING_ABILITY_HEALTH_POTION = 'A04P'
constant integer CRAFTING_ITEM_HEALTH_POTION = 'I01K'
constant integer CRAFTING_RECIPES_MAX = 7
integer array CraftItems[1]
integer array CraftRecipes[1]
integer array CraftAbilities[1]
endglobals
private function DisplayCraftingTag takes unit u, string s, integer id returns nothing
local texttag t = CreateTextTag()
call SetTextTagText(t, s, 0.0184)
call SetTextTagPos(t, GetUnitX(u), GetUnitY(u), 0.00)
call SetTextTagVelocity(t, 0, 0.08)
call SetTextTagVisibility(t, false)
call SetTextTagFadepoint(t, 0)
call SetTextTagLifespan(t, 1.5)
call SetTextTagPermanent(t, false)
if GetOwningPlayer(u) == GetLocalPlayer() then
// Use only local code (no net traffic) within this block to avoid desyncs.
call SetTextTagVisibility(t, true)
endif
set t = null
endfunction
struct Recipe
integer id = 0
boolean test = false
integer array ingredients[11]
static method create takes integer id returns thistype
local thistype this = thistype.allocate()
set this.id = id
return this
endmethod
public method tryUseIngredients takes integer id returns boolean
local Vampire vamp = id
local integer i
local boolean insufficientIngredients = false
local item craftItem = null
local effect e = null
// First, check if ingredients are fully available
set i = 1
loop
exitwhen i > INGREDIENTS_MAX or insufficientIngredients
if vamp.ingredients[i] < this.ingredients[i] then
set insufficientIngredients = true
endif
set i = i + 1
endloop
// If not, return false
if insufficientIngredients then
call Problem_Message(vamp.playerId, "You do not have enough ingredients to craft this item!")
return false
// If fully available, remove them from vampire
else
set i = 1
loop
exitwhen i > INGREDIENTS_MAX
set vamp.ingredients[i] = vamp.ingredients[i] - this.ingredients[i]
set i = i + 1
endloop
endif
call vamp.SetIngredientAbilities()
// create item and add to vampire inventory
set craftItem = CreateItem(CraftItems[this.id], GetUnitX(vamp.u), GetUnitY(vamp.u))
call UnitAddItem(vamp.u, craftItem)
call DisplayCraftingTag(vamp.u, GetItemName(craftItem)+" successfully crafted!", vamp.playerId)
set e = null
set e = AddSpecialEffect("Objects\\Spawnmodels\\Undead\\UndeadDissipate\\UndeadDissipate.mdl", GetUnitX(vamp.u), GetUnitY(vamp.u))
call DestroyEffect(e)
set craftItem = null
call Shadow_Message(vamp.playerId, "Good work!", false)
return true
endmethod
public method destroy takes nothing returns nothing
call this.deallocate() // the line of code that you NEED for any deconstructor
endmethod
endstruct
function CheckIngredientsAvailable takes integer vampId, integer recipeId returns boolean
local Recipe recipe = recipeId
local Vampire vamp = vampId
local boolean ingredientsOk = true
local integer i
// First, check if ingredients are fully available
set i = 1
loop
exitwhen i > INGREDIENTS_MAX or not ingredientsOk
if vamp.ingredients[i] < recipe.ingredients[i] then
set ingredientsOk = false
endif
set i = i + 1
endloop
return ingredientsOk
endfunction
private function ConditionsCraftBloodlineElixir takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_BLOODLINE_ELIXIR
endfunction
private function ConditionsCraftMoonstone takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_MOONSTONE
endfunction
private function ConditionsCraftInvisibilityPotion takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_INVISIBILITY_POTION
endfunction
private function ConditionsCraftHumanPotion takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_HUMAN_POTION
endfunction
private function ConditionsCraftHealthPotion takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_HEALTH_POTION
endfunction
private function ConditionsCraftManaPotion takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_MANA_POTION
endfunction
private function ConditionsCraftElixirOfWisdom takes nothing returns boolean
return GetSpellAbilityId() == CRAFTING_ABILITY_ELIXIR_OF_WISDOM
endfunction
private function CraftItem takes integer recipeId returns nothing
local Vampire vamp = GetHandleData(GetSpellAbilityUnit())
local boolean ingredientsAvailable = false
local Recipe recipe
if not vamp.nearCauldron then
call Problem_Message(vamp.playerId, "You must have occupied a witch's cauldron to use alchemy crafting!")
elseif IsVampireAnimalForm(vamp.u) then
call Problem_Message(vamp.playerId, "You cannot craft in animal form!")
else
set recipe = CraftRecipes[recipeId]
call recipe.tryUseIngredients(vamp)
endif
endfunction
private function CraftBloodlineElixir takes nothing returns nothing
call CraftItem(CRAFTING_BLOODLINE_ELIXIR)
endfunction
private function CraftMoonstone takes nothing returns nothing
call CraftItem(CRAFTING_MOONSTONE)
endfunction
private function CraftInvisibilityPotion takes nothing returns nothing
call CraftItem(CRAFTING_INVISIBILITY_POTION)
endfunction
private function CraftHumanPotion takes nothing returns nothing
call CraftItem(CRAFTING_HUMAN_POTION)
endfunction
private function CraftHealthPotion takes nothing returns nothing
call CraftItem(CRAFTING_HEALTH_POTION)
endfunction
private function CraftManaPotion takes nothing returns nothing
call CraftItem(CRAFTING_MANA_POTION)
endfunction
private function CraftElixirOfWisdom takes nothing returns nothing
call CraftItem(CRAFTING_ELIXIR_OF_WISDOM)
endfunction
private function CreateRecipes takes nothing returns nothing
local Recipe recipe
local integer name
// Bloodline Elixir
// ====================================================================
set name = CRAFTING_BLOODLINE_ELIXIR
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_BLOODLINE_ELIXIR
set CraftItems[name] = CRAFTING_ITEM_BLOODLINE_ELIXIR
set recipe.ingredients[INGREDIENT_CANDLE] = 0 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 1 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 2 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 2 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 1 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 0 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 0 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 1 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Moonstone
// ====================================================================
set name = CRAFTING_MOONSTONE
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_MOONSTONE
set CraftItems[name] = CRAFTING_ITEM_MOONSTONE
set recipe.ingredients[INGREDIENT_CANDLE] = 1 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 1 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 0 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 0 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 0 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 1 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 1 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 1 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 0 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Potion of Invisibility
// ====================================================================
set name = CRAFTING_INVISIBILITY_POTION
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_INVISIBILITY_POTION
set CraftItems[name] = CRAFTING_ITEM_INVISIBILITY_POTION
set recipe.ingredients[INGREDIENT_CANDLE] = 1 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 0 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 0 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 1 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 0 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 0 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 1 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 0 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Potion of human form
// ====================================================================
set name = CRAFTING_HUMAN_POTION
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_HUMAN_POTION
set CraftItems[name] = CRAFTING_ITEM_HUMAN_POTION
set recipe.ingredients[INGREDIENT_CANDLE] = 0 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 0 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 0 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 1 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 1 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 2 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 0 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 1 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Health Potion
// ====================================================================
set name = CRAFTING_HEALTH_POTION
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_HEALTH_POTION
set CraftItems[name] = CRAFTING_ITEM_HEALTH_POTION
set recipe.ingredients[INGREDIENT_CANDLE] = 0 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 0 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 1 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 1 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 0 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 1 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 0 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 1 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Mana Potion
// ====================================================================
set name = CRAFTING_MANA_POTION
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_MANA_POTION
set CraftItems[name] = CRAFTING_ITEM_MANA_POTION
set recipe.ingredients[INGREDIENT_CANDLE] = 0 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 0 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 0 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 1 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 0 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 1 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 1 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 1 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 0 // Ghost Essence
// Elixir of Wisdom
// ====================================================================
set name = CRAFTING_ELIXIR_OF_WISDOM
set recipe = Recipe.create(name)
set CraftRecipes[name] = recipe
set CraftAbilities[name] = CRAFTING_ABILITY_ELIXIR_OF_WISDOM
set CraftItems[name] = CRAFTING_ITEM_ELIXIR_OF_WISDOM
set recipe.ingredients[INGREDIENT_CANDLE] = 0 // Candles
set recipe.ingredients[INGREDIENT_SKULL] = 0 // Skulls
set recipe.ingredients[INGREDIENT_MEAT] = 0 // Meat
set recipe.ingredients[INGREDIENT_HEART] = 1 // Hearts
set recipe.ingredients[INGREDIENT_PUMPKIN] = 1 // Pumpkins
set recipe.ingredients[INGREDIENT_GREEN_MUSHROOM] = 1 // Green Mushrooms
set recipe.ingredients[INGREDIENT_BLUE_TRUFFLE] = 0 // Blue Truffles
set recipe.ingredients[INGREDIENT_GLIMMERWEED] = 1 // Glimmerweed
set recipe.ingredients[INGREDIENT_WINE] = 1 // Wine
set recipe.ingredients[INGREDIENT_GHOST_ESSENCE] = 1 // Ghost Essence
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger()
call TriggerAddAction(trg, function CreateRecipes)
call TriggerExecute(trg)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftBloodlineElixir))
call TriggerAddAction(trg, function CraftBloodlineElixir)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftMoonstone))
call TriggerAddAction(trg, function CraftMoonstone)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftInvisibilityPotion))
call TriggerAddAction(trg, function CraftInvisibilityPotion)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftHumanPotion))
call TriggerAddAction(trg, function CraftHumanPotion)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftHealthPotion))
call TriggerAddAction(trg, function CraftHealthPotion)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftManaPotion))
call TriggerAddAction(trg, function CraftManaPotion)
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(trg, Condition(function ConditionsCraftElixirOfWisdom))
call TriggerAddAction(trg, function CraftElixirOfWisdom)
set trg = null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CreateForestItems initializer Init
globals
constant integer FOREST_ITEMS_MIN = 60
constant integer FOREST_ITEMS_MAX = 90
endglobals
private function Actions takes nothing returns nothing
local integer i = 0
local integer max = GetRandomInt(FOREST_ITEMS_MIN,FOREST_ITEMS_MAX)
local integer iType
local real x
local real y
local integer j
loop
exitwhen i > (max-1)
set iType = ForestItems.getRandomInt()
// Determine spawning area
set j = AnimalAreaPool.getRandomInt()
set x = GetRandomReal(GetRectMinX(AnimalAreas[j]), GetRectMaxX(AnimalAreas[j]))
set y = GetRandomReal(GetRectMinY(AnimalAreas[j]), GetRectMaxY(AnimalAreas[j]))
call CreateIngredient(iType, x, y)
set i = i + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call Actions()
endfunction
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
library VampireItems initializer Init requires BasicFunctions
globals
private constant real EPIC_CHANCE = 0.25
private constant real RARE_CHANCE = 0.50
private constant real UNCOMMON_CHANCE = 1.00
constant integer VAMPIRE_ITEM_CLAWS_OF_ATTACK = 'I00S'
constant integer VAMPIRE_ITEM_DEMONIC_CLAWS = 'I01J'
constant integer VAMPIRE_ITEM_RING_OF_PROTECTION = 'I009'
constant integer VAMPIRE_ITEM_BLOODSTONE = 'I019'
constant integer VAMPIRE_ITEM_MANASTONE = 'I01A'
constant integer VAMPIRE_ITEM_CITY_GATE_KEY = 'I00W'
constant integer VAMPIRE_ITEM_BLINK_DAGGER = 'I00Q'
constant integer VAMPIRE_ITEM_RIVAL_STAFF = 'I00U'
constant integer VAMPIRE_ITEM_DEATHLORD_CROWN = 'I00R'
constant integer VAMPIRE_ITEM_IMMUNITY_NECKLACE = 'I00X'
constant integer VAMPIRE_ITEM_ILLUSION_WAND = 'I00Y'
constant integer VAMPIRE_ITEM_CRYSTAL_BALL = 'I00Z'
constant integer VAMPIRE_ITEM_GRIMOIRE = 'I010'
constant integer VAMPIRE_ITEM_SPEED_BOOTS = 'I00T'
constant integer VAMPIRE_ITEM_TRUESIGHT_GEM = 'I011'
intpool VampireItems
endglobals
function CreateVampireItemPool takes nothing returns nothing
call VampireItems.flush()
// Uncommon Items
call VampireItems.addInt(VAMPIRE_ITEM_ILLUSION_WAND, UNCOMMON_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_CRYSTAL_BALL, UNCOMMON_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_CLAWS_OF_ATTACK, UNCOMMON_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_BLOODSTONE, UNCOMMON_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_MANASTONE, UNCOMMON_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_RING_OF_PROTECTION, RARE_CHANCE)
// Rare Items
call VampireItems.addInt(VAMPIRE_ITEM_CITY_GATE_KEY, RARE_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_SPEED_BOOTS, RARE_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_TRUESIGHT_GEM, RARE_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_DEMONIC_CLAWS, RARE_CHANCE)
// Epic Items
call VampireItems.addInt(VAMPIRE_ITEM_BLINK_DAGGER, EPIC_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_RIVAL_STAFF, EPIC_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_DEATHLORD_CROWN, EPIC_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_IMMUNITY_NECKLACE, EPIC_CHANCE)
call VampireItems.addInt(VAMPIRE_ITEM_GRIMOIRE, EPIC_CHANCE)
// call Debug_Message("vampire item pool created")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set VampireItems = intpool.create()
// Vampire Items
// Hunter Items
endfunction
endlibrary
//TESH.scrollpos=51
//TESH.alwaysfold=0
scope Crates initializer Init
globals
private constant integer CRATE = 'LTcr'
private destructable array Crates[1]
private integer CrateCount = 0
private intpool CrateItems
private real CRATE_SPAWN_CHANCE = 80.
endglobals
private function RegisterCrate takes nothing returns nothing
if GetDestructableTypeId(GetFilterDestructable()) == 'LTcr' then
set Crates[CrateCount] = GetFilterDestructable()
set CrateCount = CrateCount + 1
endif
endfunction
private function CrateDies takes nothing returns nothing
local destructable crate = GetDyingDestructable()
local real x = GetDestructableX(crate)
local real y = GetDestructableY(crate)
local real r = GetRandomReal(0,100)
call Debug_Message("Crate dies")
// if r <= CRATE_SPAWN_CHANCE then
call CreateAnyItem(CrateItems.getRandomInt(), x, y)
// endif
set crate = null
endfunction
private function Actions takes nothing returns nothing
local integer CrateCountTarget = 0
local integer i = 0
local trigger trg
// Store all map crates in array
call EnumDestructablesInRect(bj_mapInitialPlayableArea, null, function RegisterCrate )
// call Debug_Message("Crate count before cleanup: "+I2S(CrateCount))
// Check total count and the count we want to achieve
set CrateCountTarget = R2I( I2R(CrateCount) * CRATE_USE_FACTOR )
loop
exitwhen CrateCount <= CrateCountTarget
// Get random crate in array
set i = GetRandomInt(0, CrateCount) // Get random crate in array
call RemoveDestructable(Crates[i]) // Remove it
set Crates[i] = Crates[CrateCount-1] // Put last one it it's place
set Crates[CrateCount-1] = null // Nulify variable in array
set CrateCount = CrateCount - 1 // Reduce count
endloop
set trg = CreateTrigger()
call TriggerAddAction( trg, function CrateDies )
set i = 0
loop
exitwhen i > (CrateCount-1)
call TriggerRegisterDeathEvent( trg, Crates[i] )
set i = i + 1
endloop
endfunction
private function CrateDiesConditions takes nothing returns boolean
return GetDestructableTypeId( GetDyingDestructable() ) == 'LTcr'
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set CrateItems = intpool.create()
call CrateItems.addInt(ITEM_GOLD, 1.0)
call CrateItems.addInt(ITEM_INGREDIENT_WINE, 1.0)
call CrateItems.addInt(ITEM_INGREDIENT_CANDLE, 1.0)
set trg = CreateTrigger()
call TriggerAddAction( trg, function Actions )
call TriggerExecute(trg)
// set trg = CreateTrigger()
// call TriggerRegisterDestDeathInRegionEvent( trg, bj_mapInitialPlayableArea )
// call TriggerAddCondition( trg, Condition( function CrateDiesConditions ) )
// call TriggerAddAction( trg, function CrateDies )
set trg = null
call Debug_Message("Crate initialization succesfull!")
endfunction
endscope
//TESH.scrollpos=14
//TESH.alwaysfold=0
scope WineBottles initializer Init
globals
private item array WineBottles[1]
private integer WineBottleCount = 0
endglobals
private function RegisterWineBottle takes nothing returns nothing
if GetItemTypeId(GetFilterItem()) == ITEM_INGREDIENT_WINE then
set WineBottles[WineBottleCount] = GetFilterItem()
set WineBottleCount = WineBottleCount + 1
endif
endfunction
private function Actions takes nothing returns nothing
local integer WineCountTarget = 0
local integer i = 0
// Store all map wines in array
call EnumItemsInRect(bj_mapInitialPlayableArea, null, function RegisterWineBottle )
// call Debug_Message("Wine bottle count before cleanup: "+I2S(WineBottleCount))
// Check total count and the count we want to achieve
set WineCountTarget = R2I( I2R(WineBottleCount) * WINE_USE_FACTOR )
loop
exitwhen WineBottleCount <= WineCountTarget
// Get random crate in array
set i = GetRandomInt(0, WineBottleCount) // Get random crate in array
call DetroyItem(WineBottles[i]) // Remove it
set WineBottles[i] = WineBottles[WineBottleCount-1] // Put last one it it's place
set WineBottles[WineBottleCount-1] = null // Nulify variable in array
set WineBottleCount = WineBottleCount - 1 // Reduce count
endloop
// call Debug_Message("Wine bottle count after cleanup: "+I2S(WineBottleCount))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
set trg = CreateTrigger()
call TriggerAddAction( trg, function Actions )
call TriggerExecute(trg)
call DestroyTrigger(trg)
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ItemStack initializer Init
globals
private constant integer MAX_CHARGES = 9
trigger trg_Item_Stack
endglobals
private function Item_Stack_Conditions takes nothing returns boolean
return GetItemCharges(GetManipulatedItem()) > 0
endfunction
private function Item_Stack_Actions takes nothing returns nothing
local integer i = 0
local item iteminslot
local integer charges1 = 0
local integer charges2 = 0
local integer total_charges = 0
set charges2 = GetItemCharges(GetManipulatedItem())
loop
exitwhen i > 5 or charges2 == 0
set iteminslot = UnitItemInSlot(GetManipulatingUnit(), i)
if ( GetItemTypeId(iteminslot) == GetItemTypeId(GetManipulatedItem()) and iteminslot != GetManipulatedItem()) and GetItemCharges(iteminslot) < MAX_CHARGES then
set charges1 = GetItemCharges(iteminslot)
set charges2 = GetItemCharges( GetManipulatedItem() )
set total_charges = charges1 + charges2
if total_charges > MAX_CHARGES then
set charges2 = total_charges - MAX_CHARGES
set total_charges = 9
call SetItemCharges(GetManipulatedItem(), charges2)
else
set charges2 = 0
call RemoveItem( GetManipulatedItem() )
set i = 5
endif
call SetItemCharges(iteminslot, total_charges)
endif
set i = i + 1
endloop
set iteminslot = null
endfunction
private function Item_Move_Conditions takes nothing returns boolean
return GetIssuedOrderId() > 852001 and GetIssuedOrderId() < 852008
endfunction
private function Item_Move_Actions takes nothing returns nothing
local integer charges = GetItemCharges(GetOrderTargetItem())
local integer total_charges
if GetOrderTargetItem() == UnitItemInSlot(GetOrderedUnit(), GetIssuedOrderId()-852002) then
// Clicked on the same field again
if charges > 1 then
set charges = charges/2
call SetItemCharges(GetOrderTargetItem(), GetItemCharges(GetOrderTargetItem()) - charges)
call DisableTrigger(trg_Item_Stack)
call UnitAddItemByIdSwapped(GetItemTypeId(GetOrderTargetItem()), GetTriggerUnit())
call EnableTrigger(trg_Item_Stack)
call SetItemCharges(bj_lastCreatedItem, charges)
endif
else
// Clicked on another field
set total_charges = GetItemCharges(GetOrderTargetItem()) + GetItemCharges(UnitItemInSlot(GetOrderedUnit(), GetIssuedOrderId()-852002))
if total_charges <= MAX_CHARGES then
if charges > 0 and GetItemTypeId(GetOrderTargetItem()) == GetItemTypeId(UnitItemInSlot(GetOrderedUnit(), GetIssuedOrderId()-852002)) then
call SetItemCharges(GetOrderTargetItem(), total_charges)
call RemoveItem(UnitItemInSlot(GetOrderedUnit(), GetIssuedOrderId()-852002))
endif
endif
endif
endfunction
//===========================================================================
private function OnInit takes nothing returns nothing
local integer i = 0
local trigger trg
set trg_Item_Stack = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg_Item_Stack, EVENT_PLAYER_UNIT_PICKUP_ITEM )
call TriggerAddCondition( trg_Item_Stack, Condition( function Item_Stack_Conditions ) )
call TriggerAddAction( trg_Item_Stack, function Item_Stack_Actions )
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
call TriggerAddCondition( trg, Condition( function Item_Move_Conditions ) )
call TriggerAddAction( trg, function Item_Move_Actions )
set trg = null
endfunction
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerAddAction( trg, function OnInit )
call TriggerExecute(trg)
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Potions initializer Init
globals
private constant real MOONSTONE_TIME_DELAY = 0.5
endglobals
private function BloodlineConditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == CRAFTING_ITEM_BLOODLINE_ELIXIR
endfunction
private function BloodlineActions takes nothing returns nothing
local Vampire vamp = GetHandleData(GetManipulatingUnit())
call Debug_Message("Elixir of bloodline used")
call vamp.addStrengthBonus(2)
endfunction
private function WisdomConditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == CRAFTING_ITEM_ELIXIR_OF_WISDOM
endfunction
private function WisdomActions takes nothing returns nothing
local Vampire vamp = GetHandleData(GetManipulatingUnit())
call Debug_Message("Elixir of wisdom used")
set vamp.levelupPoints = vamp.levelupPoints + 1
call vamp.addAbilities()
endfunction
private function MoonstoneConditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == CRAFTING_ITEM_MOONSTONE
endfunction
private function MoonstoneActions takes nothing returns nothing
local Vampire vamp = GetHandleData(GetManipulatingUnit())
local real time
call Debug_Message("moon stone used")
call Game_Message(PlayerNames[vamp.playerId]+" has just extended nighttime duration by 30 minutes!")
set time = GetFloatGameState(GAME_STATE_TIME_OF_DAY)
call Debug_Message("current time: "+R2S(time))
set time = time - MOONSTONE_TIME_DELAY
if time < 0. then
set time = 24. + time
endif
if (time < 21.) and (time > 18.) then
set time = 21.
endif
call Debug_Message("Time: "+R2S(time))
call SetFloatGameState(GAME_STATE_TIME_OF_DAY, time)
endfunction
private function HumanPotionConditions takes nothing returns boolean
return GetItemTypeId(GetManipulatedItem()) == CRAFTING_ITEM_HUMAN_POTION
endfunction
private function HumanPotionActions takes nothing returns nothing
local Vampire vamp = GetHandleData(GetManipulatingUnit())
call vamp.changeForm(VAMPIRE_VILLAGER)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg
// Bloodline Elixir
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( trg, Condition( function BloodlineConditions ) )
call TriggerAddAction( trg, function BloodlineActions )
// Moonstone
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( trg, Condition( function MoonstoneConditions ) )
call TriggerAddAction( trg, function MoonstoneActions )
// Human Form
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( trg, Condition( function HumanPotionConditions ) )
call TriggerAddAction( trg, function HumanPotionActions )
// Wisdom
set trg = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( trg, EVENT_PLAYER_UNIT_USE_ITEM )
call TriggerAddCondition( trg, Condition( function WisdomConditions ) )
call TriggerAddAction( trg, function WisdomActions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DisplayStructData initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = S2I(SubString( GetEventPlayerChatString(), 4, 3 ))
local Villager v
set v = id
call Debug_Message("Test Data of ID "+I2S(id))
call Debug_Message("Unit name: "+GetUnitName(v.u))
call Debug_Message("Unit position: "+R2S(GetUnitX(v.u))+" | "+R2S(GetUnitY(v.u)))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "data", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DisplayStructDataVampire initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = S2I(SubString( GetEventPlayerChatString(), 4, 3 ))
local Vampire vamp
set vamp = id
call Debug_Message("Struct data ID "+I2S(id)+" name: "+GetUnitName(vamp.u) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "data", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DisplayVillagerData initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,5, "Civilians: "+I2S(CivilianCount)+ " | Guards: " + I2S(GuardCount)+ " | All: " + I2S(VillagerCount))
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,5, "Guards Stayput: "+I2S(GuardCountStayput)+ " | Guards on Patrol: " + I2S(GuardCountPatrol))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "vdata", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GetOrder initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
call Debug_Message("Vampire Order: "+I2S( GetUnitCurrentOrder(gg_unit_U000_0003) ) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "getorders", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CliffLevel initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer level
set level = GetTerrainCliffLevel(-3275, -1967)
call Debug_Message("Cliff Level Pathing Blocker: "+I2S(level) )
set level = GetTerrainCliffLevel(-2562, -2042)
call Debug_Message("Cliff Level normal: "+I2S(level) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "cliff", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SetXP initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer xp = S2I(SubString( GetEventPlayerChatString(), 5, 4 ))
local Vampire vamp = HeroStructIdByPlayer[id]
call Debug_Message("Set XP to: "+I2S(xp))
call SetHeroXP(vamp.u, xp , true)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "setxp", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=4
//TESH.alwaysfold=0
scope GiveGold initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer amount = S2I(SubString( GetEventPlayerChatString(), 8, 7 ))
call Debug_Message(PlayerNames[id] + " has been given " + I2S(amount) + " gold.")
call SetPlayerState( GetTriggerPlayer(), PLAYER_STATE_RESOURCE_GOLD, ( GetPlayerState(GetTriggerPlayer(), PLAYER_STATE_RESOURCE_GOLD) + amount ) )
call SetPlayerState( GetTriggerPlayer(), PLAYER_STATE_RESOURCE_LUMBER, ( GetPlayerState(GetTriggerPlayer(), PLAYER_STATE_RESOURCE_LUMBER) + amount ) )
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(1), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(2), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(3), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(4), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(5), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(6), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(7), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(8), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(9), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(10), "givegold", false )
call TriggerRegisterPlayerChatEvent( trg, Player(11), "givegold", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GiveVision initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
set bj_lastCreatedFogModifier = CreateFogModifierRect(Player(0), FOG_OF_WAR_VISIBLE, bj_mapInitialPlayableArea, true, false)
call FogModifierStart(bj_lastCreatedFogModifier)
call Debug_Message(PlayerNames[id] + " has been given full map vision.")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "givevision", true )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope GiveIngredients initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local Vampire vamp = HeroStructIdByPlayer[id]
local integer i
set i = 1
loop
exitwhen i > INGREDIENTS_MAX
set vamp.ingredients[i] = IngrediantMaxPieces[i]
set i = i + 1
endloop
call vamp.SetIngredientAbilities()
call Debug_Message(PlayerNames[id] + " has been given full ingredients")
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "giveing", true )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope ShowIngredients initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local Vampire vamp = HeroStructIdByPlayer[id]
local integer i
set i = 1
loop
exitwhen i > INGREDIENTS_MAX
call Debug_Message(IngrediantNames[i] + " : "+I2S(vamp.ingredients[i]))
set i = i + 1
endloop
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "showing", true )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope SetLevel initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local integer lv = S2I(SubString( GetEventPlayerChatString(), 8, 2 ))
local Vampire vamp = HeroStructIdByPlayer[id]
call Debug_Message("Set Level to: "+I2S(lv))
call SetHeroLevelBJ(vamp.u, lv, true)
set vamp.level = lv
set vamp.levelupPoints = lv
call vamp.addAbilities()
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "setlevel", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope KillMe initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local Vampire vamp = HeroStructIdByPlayer[id]
call KillUnit(vamp.u)
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "killme", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope Heal initializer Init
private function Conditions takes nothing returns boolean
return DEBUG_MODE
endfunction
private function Actions takes nothing returns nothing
local integer id = GetPlayerId(GetTriggerPlayer())
local Vampire vamp = HeroStructIdByPlayer[id]
call SetUnitState(vamp.u, UNIT_STATE_LIFE, GetUnitState(vamp.u, UNIT_STATE_MAX_LIFE))
call SetUnitState(vamp.u, UNIT_STATE_MANA, GetUnitState(vamp.u, UNIT_STATE_MAX_MANA))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local trigger trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "heal", false )
call TriggerAddCondition( trg, Condition( function Conditions ) )
call TriggerAddAction( trg, function Actions )
set trg = null
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope DebugStuff initializer Init
//===========================================================================
private function Init takes nothing returns nothing
call UnitAddAbility(gg_unit_n000_0163, 'A03E')
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope RemoveDebugStuff initializer Init
private function Actions takes nothing returns nothing
if DEBUG_MODE == false then
call RemoveUnit( gg_unit_nvil_0022 )
call RemoveUnit( gg_unit_nvil_0023 )
call RemoveUnit( gg_unit_nvil_0021 )
call RemoveUnit( gg_unit_nvil_0024 )
call RemoveUnit( gg_unit_n000_0025 )
call RemoveUnit( gg_unit_U000_0017 )
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call Actions()
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope CreateTestHunters initializer Init
globals
private constant real POSITION_X = -3689
private constant real POSITION_Y = -7170
endglobals
private function Actions takes nothing returns nothing
local unit u
local item i
if DEBUG_MODE then
set u = CreateUnit(Player(0), GUNSLINGER, POSITION_X, POSITION_Y, bj_UNIT_FACING)
call RegisterHunter(u)
set i = CreateItem('I017', GetUnitX(u), GetUnitY(u))
call UnitAddItem(u, i)
set u = CreateUnit(Player(0), ASSASSIN, POSITION_X, POSITION_Y, bj_UNIT_FACING)
call RegisterHunter(u)
set u = CreateUnit(Player(0), MAGE, POSITION_X, POSITION_Y, bj_UNIT_FACING)
call RegisterHunter(u)
endif
set u = null
set i = null
endfunction
//===========================================================================
private function Init takes nothing returns nothing
call Actions()
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope VisionTester initializer Init
globals
private unit t1
private unit t2
private unit t3
private unit t4
private unit t5
private unit t6
endglobals
private function TimerCallback takes nothing returns nothing
local Villager v = GetIdForHandle(t5)
// 4 units
if IsUnitBehind(BehindTesterAttacker, t1) then
call SetUnitVertexColor(t1, 0, 0, 255, 255)
elseif IsUnitInSight(t1, BehindTesterAttacker) then
call SetUnitVertexColor(t1, 255, 0, 0, 255)
else
call SetUnitVertexColor(t1, 255, 255, 255, 255)
endif
if IsUnitBehind(BehindTesterAttacker, t2) then
call SetUnitVertexColor(t2, 0, 0, 255, 255)
elseif IsUnitInSight(t2, BehindTesterAttacker) then
call SetUnitVertexColor(t2, 255, 0, 0, 255)
else
call SetUnitVertexColor(t2, 255, 255, 255, 255)
endif
if IsUnitBehind(BehindTesterAttacker, t3) then
call SetUnitVertexColor(t3, 0, 0, 255, 255)
elseif IsUnitInSight(t3, BehindTesterAttacker) then
call SetUnitVertexColor(t3, 255, 0, 0, 255)
else
call SetUnitVertexColor(t3, 255, 255, 255, 255)
endif
if IsUnitBehind(BehindTesterAttacker, t4) then
call SetUnitVertexColor(t4, 0, 0, 255, 255)
elseif IsUnitInSight(t4, BehindTesterAttacker) then
call SetUnitVertexColor(t4, 255, 0, 0, 255)
else
call SetUnitVertexColor(t4, 255, 255, 255, 255)
endif
if IsUnitBehind(BehindTesterAttacker, t5) then
call SetUnitVertexColor(t5, 0, 0, 255, 255)
elseif IsUnitInSight(t5, BehindTesterAttacker) then
call SetUnitVertexColor(t5, 255, 0, 0, 255)
else
call SetUnitVertexColor(t5, 255, 255, 255, 255)
endif
// call Debug_Message("Range: "+R2S(DistanceBetweenPoints(GetUnitLoc(t5), Location(v.homeX, v.homeY))))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local timer t = NewTimer()
set BehindTesterAttacker = gg_unit_U000_0017
set t1 = gg_unit_nvil_0021
set t2 = gg_unit_nvil_0022
set t3 = gg_unit_nvil_0023
set t4 = gg_unit_nvil_0024
set t5 = gg_unit_n000_0025
call TimerStart(t, 0.25, true, function TimerCallback)
endfunction
endscope
//TESH.scrollpos=42
//TESH.alwaysfold=0
scope PathTest initializer Init
globals
timer benchmark_timer
trigger DoIt
integer count = 0
boolean done = false
endglobals
private function TimerEnd takes nothing returns nothing
endfunction
private function BenchmarkDone takes nothing returns nothing
local real time = TimerGetElapsed(benchmark_timer)
call Debug_Message("IsTerrainWalkable: "+R2S(time)+" (calls: "+I2S(count)+")")
call ReleaseTimer(benchmark_timer)
endfunction
private function Test1 takes nothing returns nothing
local boolean blub
set blub = IsTerrainWalkable(-2784, -2140)
set count = count + 1
if count >= 2500 then
set done = true
endif
endfunction
private function Actions takes nothing returns nothing
local boolean notPathable = false
local timer t
// Benachmark IsTerrainWalkable
call Debug_Message("Start benchmark..")
set t = NewTimer()
call TimerStart(benchmark_timer, 99999, false, function TimerEnd)
loop
exitwhen done
call TriggerExecute(DoIt)
endloop
call Debug_Message("benchmark 1")
call BenchmarkDone()
set notPathable = IsTerrainPathable(-2784, -2140, PATHING_TYPE_WALKABILITY)
if notPathable then
call Debug_Message("IS NOT pathable")
else
call Debug_Message("IS pathable")
endif
set notPathable = IsTerrainPathable(-2880, -2140, PATHING_TYPE_WALKABILITY)
if notPathable then
call Debug_Message("IS NOT pathable")
else
call Debug_Message("IS pathable")
endif
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set DoIt = CreateTrigger( )
call TriggerAddAction(DoIt, function Test1)
call Actions()
endfunction
endscope
//TESH.scrollpos=12
//TESH.alwaysfold=0
scope PerformanceTester initializer Init
globals
private boolean END = false
private real DURATION = 1.0
private integer COUNT = 0
private trigger DoIt = null
endglobals
private function OnEnd takes nothing returns nothing
local timer t = GetExpiredTimer()
call ReleaseTimer(t)
set t = null
set END = true
call Debug_Message("performance test stopped "+I2S(COUNT))
endfunction
private function TestPerformance takes nothing returns nothing
local unit u1 = gg_unit_nvlw_0012
local unit u2 = gg_unit_U000_0004
local boolean wall = false
local real x1 = GetUnitX(u1)
local real y1 = GetUnitY(u1)
local real x2 = GetUnitX(u2)
local real y2 = GetUnitY(u2)
set wall = WallInBetween(x1,y1, x2,y2)
set COUNT = COUNT + 1
endfunction
private function Actions takes nothing returns nothing
local timer t = NewTimer()
call Debug_Message("Started performance test..")
call TimerStart(t, DURATION, false, function OnEnd)
loop
exitwhen END == true
call TriggerExecute(DoIt)
endloop
set t = null
call Debug_Message("Wall in between count in "+R2S(DURATION)+" sec: "+I2S(COUNT))
endfunction
//===========================================================================
private function Init takes nothing returns nothing
set DoIt = CreateTrigger( )
call TriggerAddAction(DoIt, function TestPerformance)
call Actions()
endfunction
endscope
//TESH.scrollpos=0
//TESH.alwaysfold=0
scope HeavyCalcTester initializer Init
private function TimerCallback takes nothing returns nothing
call Debug_Message("Heavy Calc. count: "+I2S(HEAVY_CALC_COUNT))
set HEAVY_CALC_COUNT = 0
endfunction
//===========================================================================
private function Init takes nothing returns nothing
local timer t = NewTimer()
call TimerStart(t, 0.5, true, function TimerCallback)
endfunction
endscope