- Joined
- Aug 3, 2008
- Messages
- 2,345
Impossible.
/*******************************************************************************************
* Herd System
* By Element of Water (EoW)
********************************************************************************************
* What is it?
*
* Herd System is a system to keep a group of units in a "herd", similar to hunts in the
* popular Age of Empires (AoE) series. The units will always stay in a group together, and
* units straying too far from the herd will quickly rejoin it. If any member of the herd is
* attacked, the entire herd will run away from the attacker.
********************************************************************************************
* Requirements
*
* - JassHelper by Vexorian
* - Table by Vexorian
* - GroupUtils by Rising_Dusk
* - TimerUtils by Vexorian
* - ADamage by Anitarf
********************************************************************************************
* How to use it
*
* How do you use Herd System? Simple.
*
* call Herd.create(group g, real runDist)
*
* group g - a unit group containing all the units to be in the herd.
* real runDist - how far the herd will run if one of their number is attacked. A runDist of
* 0 means they do not run away and a runDist of less than 0 means they will
* run towards their attacker.
*
* You may also save your herd to a variable of type Herd, like this:
*
* local Herd h = Herd.create(myGroup, runDist)
*
* This way you can add unit groups or individual units to the Herd later, by doing:
*
* call h.addUnit(myUnit)
* or:
* call h.addGroup(myGroup)
*
* You may also remove individual units by doing:
*
* call h.removeUnit(myUnit)
********************************************************************************************
* Importing
*
* To import Herd System to your map, simply copy and paste the script into any trigger in
* your map, and make sure you have all the requirements in your map. Next, you should check
* the constant globals below and alter them to suit your map. They are all fully commented
* so you know exactly what they do.
*******************************************************************************************/
library HerdSystem requires Table, TimerUtils, GroupUtils, ADamage
globals
//Should the herd be destroyed when all the units die or are removed?
private constant boolean DESTROY_WHEN_UNITS_KILLED = true
//How big the area containing the herd is per unit contained
private constant real RECT_SIZE_PER_UNIT = 50.00
//Every x seconds the herds will be checked to maintain them. This is x.
private constant real HERD_CHECK_TIME = 10.00
//When a unit in a herd is damaged, the herd will run away from the damager. A herd can not run
//away more than once per x seconds. This is x.
private constant real TIME_BETWEEN_RUN = 10.00
//==========================================================================================
//The order id for "move". Should not be changed.
private constant integer ORDER_MOVE = 851986
endglobals
//==========================================================================================
private function CountUnitsInGroupEx takes group g returns integer
set bj_groupCountUnits = 0
call ForGroup(g, function CountUnitsInGroupEnum)
return bj_groupCountUnits
endfunction
private function GroupAddGroupEx takes group a, group b returns nothing
set bj_groupAddGroupDest = a
call ForGroup(b, function GroupAddGroupEnum)
endfunction
//==========================================================================================
globals
private real GroupMin_Temp
endglobals
private function GetGroupMinX_Enum takes nothing returns nothing
local real r = GetUnitX(GetEnumUnit())
if r < GroupMin_Temp then
set GroupMin_Temp = r
endif
endfunction
private function GetGroupMinX takes group g returns real
set GroupMin_Temp = 999999.
call ForGroup(g, function GetGroupMinX_Enum)
return GroupMin_Temp
endfunction
private function GetGroupMinY_Enum takes nothing returns nothing
local real r = GetUnitY(GetEnumUnit())
if r < GroupMin_Temp then
set GroupMin_Temp = r
endif
endfunction
private function GetGroupMinY takes group g returns real
set GroupMin_Temp = 999999.
call ForGroup(g, function GetGroupMinY_Enum)
return GroupMin_Temp
endfunction
//==========================================================================================
globals
private real GroupCenter_Min
private real GroupCenter_Temp
private integer GroupCenter_Count
endglobals
private function GetGroupCenterX_Enum takes nothing returns nothing
set GroupCenter_Temp = GroupCenter_Temp + GetUnitX(GetEnumUnit()) - GroupCenter_Min
set GroupCenter_Count = GroupCenter_Count + 1
endfunction
private function GetGroupCenterX takes group g returns real
set GroupCenter_Min = GetGroupMinX(g)
set GroupCenter_Temp = 0.
set GroupCenter_Count = 0
call ForGroup(g, function GetGroupCenterX_Enum)
return GroupCenter_Temp / GroupCenter_Count + GroupCenter_Min
endfunction
private function GetGroupCenterY_Enum takes nothing returns nothing
set GroupCenter_Temp = GroupCenter_Temp + GetUnitY(GetEnumUnit()) - GroupCenter_Min
set GroupCenter_Count = GroupCenter_Count + 1
endfunction
private function GetGroupCenterY takes group g returns real
set GroupCenter_Min = GetGroupMinY(g)
set GroupCenter_Temp = 0.
set GroupCenter_Count = 0
call ForGroup(g, function GetGroupCenterY_Enum)
return GroupCenter_Temp / GroupCenter_Count + GroupCenter_Min
endfunction
//==========================================================================================
globals
private real GroupToRect_MinX
private real GroupToRect_MinY
private real GroupToRect_MaxX
private real GroupToRect_MaxY
endglobals
private function GroupToRect_Enum takes nothing returns nothing
local real x = GetUnitX(GetEnumUnit())
local real y = GetUnitY(GetEnumUnit())
local boolean move = false
if x < GroupToRect_MinX then
set x = GroupToRect_MinX
set move = true
elseif x > GroupToRect_MaxX then
set x = GroupToRect_MaxX
set move = true
endif
if y < GroupToRect_MinY then
set y = GroupToRect_MinY
set move = true
elseif y > GroupToRect_MaxY then
set y = GroupToRect_MaxY
set move = true
endif
if move then
call IssuePointOrderById(GetEnumUnit(), ORDER_MOVE, x, y)
endif
endfunction
private function MoveGroupToRect takes group g, rect r returns nothing
set GroupToRect_MinX = GetRectMinX(r)
set GroupToRect_MinY = GetRectMinY(r)
set GroupToRect_MaxX = GetRectMaxX(r)
set GroupToRect_MaxY = GetRectMaxY(r)
call ForGroup(g, function GroupToRect_Enum)
endfunction
//==========================================================================================
globals
private real MoveGroupPolar_Cos
private real MoveGroupPolar_Sin
private real MoveGroupPolar_Dist
endglobals
private function MoveGroupPolar_Enum takes nothing returns nothing
local real x = GetUnitX(GetEnumUnit()) + MoveGroupPolar_Dist * MoveGroupPolar_Cos
local real y = GetUnitY(GetEnumUnit()) + MoveGroupPolar_Dist * MoveGroupPolar_Sin
call IssuePointOrderById(GetEnumUnit(), ORDER_MOVE, x, y)
endfunction
private function MoveGroupPolar takes group g, real angle, real dist returns nothing
if dist == 0. then
return
endif
set MoveGroupPolar_Cos = Cos(angle)
set MoveGroupPolar_Sin = Sin(angle)
set MoveGroupPolar_Dist = dist
call ForGroup(g, function MoveGroupPolar_Enum)
endfunction
//==========================================================================================
private function onHit takes unit damagedUnit, unit damageSource, real damage, real prevented returns nothing
call Herd.attacked(damagedUnit, damageSource)
endfunction
//==========================================================================================
struct Herd
private static HandleTable ht
private static Herd array herds
private static integer index = 0
private static timer tim = CreateTimer()
private integer ID
private static trigger unitDies = CreateTrigger()
//==========================================================================================
private rect container = Rect(0., 0., 0., 0.)
private group herd
private integer num = 0
private real dist
private timer runTimer
private boolean run = true
//==========================================================================================
private static method check takes nothing returns nothing
local Herd h
local integer i = 0
loop
exitwhen i >= Herd.index
set h = Herd.herds[i]
call h.groupRefresh()
call h.resetRect()
call h.sortHerd()
set i = i + 1
endloop
endmethod
//==========================================================================================
static method create takes group herd, real runDist returns Herd
local Herd h = Herd.allocate()
local unit u
set h.herd = NewGroup()
set h.dist = runDist
if herd != null then
call h.addGroup(herd)
endif
set Herd.herds[Herd.index] = h
set h.ID = Herd.index
if Herd.index == 0 then
call TimerStart(Herd.tim, HERD_CHECK_TIME, true, function Herd.check)
endif
set Herd.index = Herd.index + 1
call h.resetRect()
return h
endmethod
//==========================================================================================
private static method deathActions takes nothing returns boolean
local Herd h
local unit u = GetTriggerUnit()
if Herd.ht.exists(u) then
set h = Herd.ht[u]
call h.removeUnit(u)
endif
set u = null
return false
endmethod
//==========================================================================================
private static method resetRun takes nothing returns nothing
local timer t = GetExpiredTimer()
local Herd h = GetTimerData(t)
set h.run = true
call ReleaseTimer(t)
endmethod
static method attacked takes unit damagedUnit, unit damageSource returns nothing
local Herd h
local timer t
local real array x
local real array y
if Herd.ht.exists(damagedUnit) then
set h = Herd.ht[damagedUnit]
if h.run then
call BJDebugMsg("RUN AWAY!")
set x[0] = GetUnitX(damageSource)
set y[0] = GetUnitY(damageSource)
set x[1] = GetUnitX(damagedUnit)
set y[1] = GetUnitY(damagedUnit)
set x[2] = x[1] - x[0]
set y[2] = y[1] - y[0]
call MoveGroupPolar(h.herd, Atan2(y[2], x[2]), h.dist)
set h.run = false
set t = NewTimer()
call SetTimerData(t, h)
call TimerStart(t, TIME_BETWEEN_RUN, false, function Herd.resetRun)
endif
endif
endmethod
//==========================================================================================
private method groupRefresh takes nothing returns nothing
call GroupRefresh(.herd)
endmethod
private method resetRect takes nothing returns nothing
local real x = GetGroupCenterX(.herd)
local real y = GetGroupCenterY(.herd)
local real size = (.num * RECT_SIZE_PER_UNIT) / 2
call SetRect(.container, x - size, y - size, x + size, y + size)
endmethod
private method sortHerd takes nothing returns nothing
call MoveGroupToRect(.herd, .container)
endmethod
//==========================================================================================
method removeUnit takes unit u returns nothing
local Herd h
if Herd.ht.exists(u) then
set h = Herd.ht[u]
if h == this then
set Herd.ht[u] = 0
call GroupRemoveUnit(.herd, u)
set .num = .num - 1
endif
endif
endmethod
method addUnit takes unit u returns nothing
set Herd.ht[u] = this
call GroupAddUnit(.herd, u)
set .num = .num + 1
endmethod
private static Herd toAdd
private static method addUnits takes nothing returns nothing
call Herd.toAdd.addUnit(GetEnumUnit())
endmethod
method addGroup takes group g returns nothing
set Herd.toAdd = this
call ForGroup(g, function Herd.addUnits)
endmethod
//==========================================================================================
method onDestroy takes nothing returns nothing
call ReleaseGroup(.herd)
call RemoveRect(.container)
set Herd.index = Herd.index - 1
set Herd.herds[.ID] = Herd.herds[Herd.index]
set Herd.herds[.ID].ID = .ID
if Herd.index == 0 then
call PauseTimer(Herd.tim)
endif
endmethod
static method onInit takes nothing returns nothing
set Herd.ht = HandleTable.create()
call ADamage_AddResponse(onHit)
call TriggerRegisterAnyUnitEventBJ(Herd.unitDies, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(Herd.unitDies, Condition(function Herd.deathActions))
endmethod
//==========================================================================================
endstruct
//==========================================================================================
endlibrary
Make an arrowkey controlled vehicle system with realistic car physics/ collision and sounds, just like racing games.
@ Megafyr
Well, I already made one, just not with sounds...
http://www.hiveworkshop.com/forums/spells-569/advanced-arrow-key-movement-system-v1-2-0-a-103695/
function GetUnitZOffset takes unit u returns real
that returns how high above the ground a flying unit should be, at its current position, based on its default fly height. Blizzard's GetUnitFlyHeight function does jack shit. Using this function, you could set a missile's fly height such that it can fly straight over hills and stuff. I think it could be very useful. I am currently working on it, but unfortunately, my function is not accurate enough to be useful right now.hmm, i can give you one that would be useless to any map but very challenging..
make a unit that has an animation(s) out of various dummy units. It is not impossible just extremely useless and challenging.
noob134 meant a unit, which is not actually a unit. It is a unit made of other units. When the overall unit walks, the units which the unit is composed of begin moving in a way to make it look like the unit's making steps.
Or a unit made of special effects flying in the air.
native UnitDamageTarget takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
Element of water, maybe you shouldnt post a jass code, he doesnt like it xP
Diehard@Azeroth
What system are you working on now atm?
Custom Script: native UnitDamageTarget takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
@ noob134
I had an idea to make something like that a while ago, then I realised the maths was too hard. So, no.
I have an idea too. Make units move in a formation. All the units of the formation are unselectable, but the officer of the formation is selectable. Units can be any number in the formation and formation's maximum number of soldiers in a line is specified by player by a text message in the game. If there are 6, 6, and 4 soldiers on 3 lines, then the last line's soldiers gain larger distance between them to fit the formation's width.
And no one damn switches their position in the group, etc unit's don't switch their places with other units. If a unit of the formation died, then a unit from the very last line comes to his place and the last line gains even more additional distance between its soldiers.
I think something similar to this has already been made. However, your specific idea sounds interesting. What would happen if the officer died? How would multiple formations move if you have multiple officers (from different groups) selected? I might want to make this.
2) I don't know enough about how code works to make my own language inside wc3.
Nah, it's impossible to make it display right. You can't change tooltips dynamically.
Yeah I suppose that would simplify it, but it'd be hard for the player to understand and there would only be a limited amount of things you could do with it.
@ Eleandor
1) Sounds really interesting! I wouldn't have much idea about how to go about it, however.
2) I don't know enough about how code works to make my own language inside wc3.
Er, yeah. It's already made.
EDIT: Ok, I looked a bit at the wikipedia article on these neural network things, and basically, it's a load of different threads which interact with each other, and all run functions at the same time. How to set up a network like this which can recognise images made of wc3 units? I still have no idea whatsoever.