AMHS (Anti Map Hack System) created by PandaMine
Current Version: 5.2
IT IS HIGHLY RECOMMENDED THAT YOU READ THROUGH EVERY README/MANUAL IN THE AMHS v5.x - THE WHOLE SYSTEM HAS CHANGED
Many thanks to Strilanc who's suggestions greatly increased the speed and efficiency of the system
Advantages
- First AMH system that works with replays, fully (thanks to my replay detect function, credits to Toadcop and Captain Griffein)
- Counters all the major features of ALL and I mean ALL public map hacks (there isnt much I can do for private ones). Check the MH List trigger in the map for more info
- Prevents any MH from revealing units on the screen
- Prevents any MH from revealing units on the minimap
- Prevents any MH from revealing special effects on the screen
Disadvantages
- The replay detect function (used to disable the system when viewing replays) uses up one pause and makes a noticable message.
- With the new AMHS v5.x, you need to input the data for every unit that the map uses into the engine since there unfortunately isn't any known method for WE/JASS to read/write data to the Object Editor
- JassNewGen (vJASS) is mandatory, there is not going to be any non JassNewGen releases
How does the system work?
The current version of the system works by hiding units/minimap icons/destructables/effects if they are not visible by a player so any MH will not reveal them
Fog Protect and Shadow Engine
This a huge engine that fully replaces the default Blizzard engine for managing shadows and UnitVertexColor/UnitScale. The system works by completely and graphically hiding a unit if it is not visible (determined by IsUnitVisible) to a player. It also adds many more options, too many to go through in this post (read the Readme).
This also works with Invisible Units
Spoiler:
Code: Select all
library FogProtectShadowEngine needs ReplayDetectEngine, AMHSCache
//*************************************************************************
//* * *
//* FOG PROTECT & SHADOW ENGINE v1.20 *
//* CONFIGURATION SETTINGS START HERE * *
//* * *
//*************************************************************************
globals
// This is the default alpha value used for shadows. From visual experimentation the alpha
// value of Blizzards shadows appear to be 180. If desire you can change the value
// NOTE: If you wish you can change the alpha value of a shadow using the SetShadowAlpha
// method at any time, this is just the default value when the shadow is created
private constant integer shadowalpha_default = 180
// This is the interval period used by the system. 0.025 should be the LOWEST value, anything
// lower is pointless since 0.025 matches Wc3's maximum FPS (60 fp/s). If the system is
// causing lag then you should increase it to a value between 0.025 and 0.05. Anything higher
// then 0.05 is seriously not recommended since it will look visually choppy.
// NOTE: The system is INCREDIBLY efficient and it uses the struct-loop system (no H2I/attach
// methods are used for the timer interval) so in 99% of cases you should never have to increase
// the period
private constant real period = 0.025
// By default Blizzard shadows are disabled when a unit dies (note when a unit dies, this doesn't
// necessarily mean when its removed from the game. If a unit is removed from the by killunit
// or removeunit the shadow is destroyed, however should a hero die then the shadow will not
// be removed, instead it will be disabled. A units death is evaluated by the
// GetUnitState(u,UNIT_STATE_MAX_LIFE) <= 0.405. Should the unit be revived by a spell such
// as reincarnation then its shadow will return back to what it was before it died
// Setting this to false will mean the shadow will still remain even if the unit dies. NOTE: If
// hideshadowondeath is enabled it can be detect with the GetShadowVisibility method, so this
// means you would need to take care of when a unit dies when dealing with showing/hiding shadows
private constant boolean hideshadowondeath = true
endglobals
//*************************************************************************
//* * *
//* FOG PROTECT & SHADOW ENGINE v1.20 * *
//* CONFIGURATION SETTINGS END HERE * *
//* * *
//*************************************************************************
// Create has used to store buffs
globals
private gamecache fp_datacache
private boolean cachefirst = true
private trigger RegisterUnit = CreateTrigger()
private group g = CreateGroup()
//Stack for shadow struct
private integer array s_StructStack
private integer array s_StructFreeStack
private integer s_StructNumber = 0
private integer s_StructFreeNumber = -1
//Stack for unit/graphic struct
private integer array gp_StructStack
private integer array gp_StructFreeStack
private integer gp_StructNumber = 0
private integer gp_StructFreeNumber = -1
endglobals
private function H2I takes handle h returns integer
return h
return 0
endfunction
private function InitializeDataCache takes nothing returns nothing
call FlushGameCache(InitGameCache("fp_datacache"))
set fp_datacache=InitGameCache("fp_datacache")
endfunction
//! runtextmacro AMHS_HandleInit()
//Shadow Struct -> Public Use
struct shadow
readonly real x
readonly real y
readonly real centrex
readonly real centrey
readonly real width
readonly real height
readonly integer r
readonly integer g
readonly integer b
readonly integer a
readonly unit u
readonly string path
readonly image i
readonly boolean enabled = true
readonly boolean deadunit = false
readonly integer position //position in relation to struct stack
static method Create takes unit u, real centrex, real centrey, real width, real height, integer alpha, string path returns shadow
local shadow s = shadow.create()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
set s.x = x
set s.y = y
set s.width = width
set s.height = height
set s.a = alpha
set s.u = u
set s.centrex = centrex
set s.centrey = centrey
set s.path = path
if path == "normal" or path == "Normal" or path == "NORMAL" or path == "Shadow" or path == "shadow" or path == "SHADOW" then
set s.path = "ReplaceableTextures\\Shadows\\Shadow.blp"
elseif path == "flyer" or path == "Flyer" or path == "FLYER" or path == "ShadowFlyer" or path == "shadowflyer" or path == "SHADOWFLYER" then
set s.path = "Textures\\Shadow.blp"
elseif path == "none" or path == "None" or path == "NONE" then
set s.path = ""
endif
set s.i = CreateImage(s.path, width, height, 0, x - (width / 2), y - (height / 2), 0, centrex, centrey, 0, 2) // image type indicator
call SetImageRenderAlways(s.i, true)
call ShowImage(s.i, true)
call SetImageColor(s.i,255,255,255,alpha)
set s.r = 255
set s.g = 255
set s.b = 255
set s.a = 180
//Update Struct Stack
if s_StructFreeNumber<0 then
set s.position = s_StructNumber
set s_StructStack[s_StructNumber] = s
set s_StructNumber = s_StructNumber+1
else
set s.position = s_StructFreeStack[s_StructFreeNumber]
set s_StructStack[s.position] = s
set s_StructFreeStack[s_StructFreeNumber] = -1
set s_StructFreeNumber = s_StructFreeNumber-1
endif
//! runtextmacro AMHS_StoreStructShadow("s.u","s")
return s
endmethod
public method ChangeDeadUnit takes boolean flag returns nothing
set this.deadunit = flag
endmethod
method GetShadowPath takes nothing returns string
return this.path
endmethod
method GetShadowAlpha takes nothing returns integer
return this.a
endmethod
method GetShadowRed takes nothing returns integer
return this.r
endmethod
method GetShadowGreen takes nothing returns integer
return this.g
endmethod
method GetShadowBlue takes nothing returns integer
return this.b
endmethod
method GetShadowCentreX takes nothing returns real
return this.centrex
endmethod
method GetShadowCentreY takes nothing returns real
return this.centrey
endmethod
method GetShadowHeight takes nothing returns real
return this.height
endmethod
method GetShadowWidth takes nothing returns real
return this.width
endmethod
method GetShadowUnit takes nothing returns unit
return this.u
endmethod
method GetDefaultShadowCentreX takes nothing returns real
local string s = UnitId2String(GetUnitTypeId(this.u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
return GetStoredReal(fp_datacache,s,"centrex")
else
return I2R(0)
endif
endmethod
method GetDefaultShadowCentreY takes nothing returns real
local string s = UnitId2String(GetUnitTypeId(this.u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
return GetStoredReal(fp_datacache,s,"centrey")
else
return I2R(0)
endif
endmethod
method GetDefaultShadowHeight takes nothing returns real
local string s = UnitId2String(GetUnitTypeId(this.u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
return GetStoredReal(fp_datacache,s,"height")
else
return I2R(0)
endif
endmethod
method GetDefaultShadowWidth takes nothing returns real
local string s = UnitId2String(GetUnitTypeId(this.u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
return GetStoredReal(fp_datacache,s,"width")
else
return I2R(0)
endif
endmethod
method GetDefaultShadowPath takes nothing returns string
local string s = UnitId2String(GetUnitTypeId(this.u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
return GetStoredString(fp_datacache,s,"path")
else
return ""
endif
endmethod
method SetShadowColor takes integer red, integer green, integer blue, integer alpha returns nothing
call SetImageColor(this.i,red,green,blue,alpha)
set this.r = red
set this.g = green
set this.b = blue
set this.a = alpha
endmethod
method SetShadowAlpha takes integer alpha returns nothing
call SetImageColor(this.i,this.r,this.g,this.b,alpha)
set this.a = alpha
endmethod
method SetShadowVisibility takes boolean visibility returns nothing
call ShowImage(this.i,visibility)
set this.enabled = visibility
endmethod
method SetShadowImage takes string path returns nothing
local string truepath = path
call DestroyImage(this.i)
set this.i = null
if path == "normal" or path == "Normal" or path == "NORMAL" then
set truepath = "ReplaceableTextures\\Shadows\\Shadow.blp"
elseif path == "flyer" or path == "Flyer" or path == "FLYER" then
set truepath = "Textures\\Shadow.blp"
elseif path == "none" or path == "None" or path == "NONE" then
set truepath = ""
endif
set this.i = CreateImage(truepath, this.width, this.height, 0, this.x - (this.width / 2), this.y - (this.height / 2), 0, this.centrex, this.centrey, 0, 2) // image type indicator
set this.path = truepath
call SetImageRenderAlways(this.i, true)
call ShowImage(this.i, true)
call SetImageColor(this.i,this.r,this.g,this.b,this.a)
endmethod
method SetShadowImageEx takes string path, real centrex, real centrey, real width, real height returns nothing
local string truepath = path
call DestroyImage(this.i)
set this.i = null
if path == "normal" or path == "Normal" or path == "NORMAL" then
set truepath = "ReplaceableTextures\\Shadows\\Shadow.blp"
elseif path == "flyer" or path == "Flyer" or path == "FLYER" then
set truepath = "Textures\\Shadow.blp"
elseif path == "none" or path == "None" or path == "NONE" then
set truepath = ""
endif
set this.i = CreateImage(truepath, width, height, 0, this.x - (width / 2), this.y - (height / 2), 0, centrex, centrey, 0, 2) // image type indicator
set this.path = truepath
set this.centrex = centrex
set this.centrey = centrey
set this.width = width
set this.height = height
call SetImageRenderAlways(this.i, true)
call ShowImage(this.i, true)
call SetImageColor(this.i,this.r,this.g,this.b,this.a)
endmethod
method SetShadowDimeansions takes real centrex, real centrey, real width, real height returns nothing
call DestroyImage(this.i)
set this.i = null
set this.i = CreateImage(this.path, width, height, 0, this.x - (width / 2), this.y - (height / 2), 0, centrex, centrey, 0, 2) // image type indicator
set this.centrex = centrex
set this.centrey = centrey
set this.width = width
set this.height = height
call SetImageRenderAlways(this.i, true)
call ShowImage(this.i, true)
call SetImageColor(this.i,this.r,this.g,this.b,this.a)
endmethod
method onDestroy takes nothing returns nothing
call DestroyImage(this.i)
set this.i = null
set s_StructStack[this.position] = -1
if (this.position>=(s_StructNumber-1)) then
set s_StructNumber = s_StructNumber-1
else
set s_StructFreeNumber = s_StructFreeNumber+1
set s_StructFreeStack[s_StructFreeNumber] = this.position
endif
//! runtextmacro AMHS_DestroyStructShadow("this.u")
set this.u = null
set this.position = -1
endmethod
endstruct
//Struct for managing SetUnitVertexColor/SetUnitScale
struct unitgraphic
readonly unit u
readonly integer r
readonly integer g
readonly integer b
readonly integer a
readonly real x
readonly real y
readonly real z
readonly boolean enabled
readonly integer position //position in relation to struct stack
static method Create takes unit u, integer red, integer green, integer blue, integer alpha, real x, real y, real z returns unitgraphic
local unitgraphic gp = unitgraphic.create()
set gp.r = red
set gp.g = green
set gp.b = blue
set gp.a = alpha
set gp.x = x
set gp.y = y
set gp.z = z
set gp.u = u
set gp.enabled = true
//Update Struct Stack
if gp_StructFreeNumber<0 then
set gp.position = gp_StructNumber
set gp_StructStack[gp_StructNumber] = gp
set gp_StructNumber = gp_StructNumber+1
else
set gp.position = gp_StructFreeStack[gp_StructFreeNumber]
set gp_StructStack[gp.position] = gp
set gp_StructFreeStack[gp_StructFreeNumber] = -1
set gp_StructFreeNumber = gp_StructFreeNumber-1
endif
//! runtextmacro AMHS_StoreStructUnitGraphic("gp.u","gp")
set u = null
return gp
endmethod
method SetVertexColor takes integer red, integer green, integer blue, integer alpha returns nothing
set this.r = red
set this.g = green
set this.b = blue
set this.a = alpha
endmethod
method SetVertexColorBJ takes real red, real green, real blue, real transparency returns nothing
call this.SetVertexColor(PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-transparency))
endmethod
method SetScale takes real scaleX, real scaleY, real scaleZ returns nothing
set this.x = scaleX
set this.y = scaleY
set this.z = scaleZ
endmethod
method SetScalePercent takes real percentScaleX, real percentScaleY, real percentScaleZ returns nothing
call this.SetScale(percentScaleX * 0.01, percentScaleY * 0.01, percentScaleZ * 0.01)
endmethod
method SetGraphicVisibility takes boolean visibility returns nothing
set this.enabled = visibility
endmethod
method GetScaleX takes nothing returns real
return this.x
endmethod
method GetScaleY takes nothing returns real
return this.y
endmethod
method GetScaleZ takes nothing returns real
return this.z
endmethod
method GetVertexColorRed takes nothing returns integer
return this.r
endmethod
method GetVertexColorGreen takes nothing returns integer
return this.g
endmethod
method GetVertexColorBlue takes nothing returns integer
return this.b
endmethod
method GetVertexColorAlpha takes nothing returns integer
return this.a
endmethod
method GetGraphicVisibility takes nothing returns boolean
return this.enabled
endmethod
method onDestroy takes nothing returns nothing
set gp_StructStack[this.position] = -1
if (this.position>=(gp_StructNumber-1)) then
set gp_StructNumber = gp_StructNumber-1
else
set gp_StructFreeNumber = gp_StructFreeNumber+1
set gp_StructFreeStack[gp_StructFreeNumber] = this.position
endif
set this.position = -1
//! runtextmacro AMHS_DestroyStructUnitGraphic("this.u")
set this.u = null
endmethod
endstruct
//Public Functions
function RegisterUnitShadow takes integer UnitID, real centrex, real centrey, real height, real width, string ShadowType returns nothing
local string s
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
set s = UnitId2String(UnitID)
call StoreBoolean(fp_datacache,s,"exist",true)
call StoreReal(fp_datacache,s,"height",height)
call StoreReal(fp_datacache,s,"width",width)
call StoreReal(fp_datacache,s,"centrex",centrex)
call StoreReal(fp_datacache,s,"centrey",centrey)
call StoreString(fp_datacache,s,"path",ShadowType)
endfunction
function RegisterUnitTintEx takes integer UnitID, integer red, integer green, integer blue, integer alpha returns nothing
local string s
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
set s = UnitId2String(UnitID)
call StoreBoolean(fp_datacache,s,"customtint",true)
call StoreInteger(fp_datacache,s,"tintred",red)
call StoreInteger(fp_datacache,s,"tintgreen",green)
call StoreInteger(fp_datacache,s,"tintblue",blue)
call StoreInteger(fp_datacache,s,"tintalpha",alpha)
endfunction
function RegisterUnitTint takes integer UnitID, integer red, integer green, integer blue returns nothing
call RegisterUnitTintEx(UnitID,red,green,blue,255)
endfunction
function RegisterUnitScaleEx takes integer UnitID, real scaleX, real scaleY, real scaleZ returns nothing
local string s
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
set s = UnitId2String(UnitID)
call StoreBoolean(fp_datacache,s,"customscale",true)
call StoreReal(fp_datacache,s,"scalex",scaleX)
call StoreReal(fp_datacache,s,"scaley",scaleY)
call StoreReal(fp_datacache,s,"scalez",scaleZ)
endfunction
function RegisterUnitScale takes integer UnitID, real scale returns nothing
call RegisterUnitScaleEx(UnitID,scale,scale,scale)
endfunction
globals
private integer array bs_StructStack
private integer array bs_StructFreeStack
private integer bs_StructNumber = 0
private integer bs_StructFreeNumber = -1
endglobals
private struct buffstruct
integer BuffID
real x = 0
real y = 0
real z = 0
real increasex
real increasey
real increasez
integer increasecount
real SizeDurationIncrease = 0
integer position
real Duration
integer Level = 0
static method Create takes integer BuffID, real x, real y, real z, real SizeDurationIncrease, real Duration, integer Level returns buffstruct
local buffstruct bs = buffstruct.create()
set bs.x = x
set bs.y = y
set bs.z = z
set bs.SizeDurationIncrease = SizeDurationIncrease
set bs.BuffID = BuffID
set bs.Duration = Duration
set bs.Level = Level
if SizeDurationIncrease > 0 then
set bs.increasecount = R2I(SizeDurationIncrease/period)
set bs.increasex = bs.x/bs.increasecount
set bs.increasey = bs.y/bs.increasecount
set bs.increasez = bs.z/bs.increasecount
endif
//Update Struct Stack
if bs_StructFreeNumber<0 then
set bs.position = bs_StructNumber
set bs_StructStack[bs_StructNumber] = bs
set bs_StructNumber = bs_StructNumber+1
else
set bs.position = bs_StructFreeStack[bs_StructFreeNumber]
set bs_StructStack[bs.position] = bs
set bs_StructFreeStack[bs_StructFreeNumber] = -1
set bs_StructFreeNumber = bs_StructFreeNumber-1
endif
return bs
endmethod
endstruct
function RegisterBuffScaleEx takes integer BuffID, real scaleX, real scaleY, real scaleZ, real SizeDurationIncrease, real Duration, integer Level returns nothing
local buffstruct bs
set bs = buffstruct.Create(BuffID,scaleX,scaleY,scaleZ,SizeDurationIncrease,Duration,Level)
endfunction
function RegisterBuffScale takes integer BuffID, real scale,real SizeDurationIncrease, real Duration, integer Level returns nothing
call RegisterBuffScaleEx(BuffID,scale,scale,scale,SizeDurationIncrease,Duration,Level)
endfunction
function SetUnitVertexColorAMHS takes unit whichUnit, integer red, integer green, integer blue, integer alpha returns nothing
local unitgraphic gp
if whichUnit != null then
//! runtextmacro AMHS_GetStructUnitGraphic("whichUnit","gp")
call gp.SetVertexColor(red,green,blue,alpha)
endif
endfunction
function SetUnitVertexColorBJAMHS takes unit whichUnit, real red, real green, real blue, real transparency returns nothing
call SetUnitVertexColorAMHS(whichUnit, PercentTo255(red), PercentTo255(green), PercentTo255(blue), PercentTo255(100.0-transparency))
endfunction
function SetUnitScaleAMHS takes unit whichUnit, real scaleX, real scaleY, real scaleZ returns nothing
local unitgraphic gp
if whichUnit != null then
//! runtextmacro AMHS_GetStructUnitGraphic("whichUnit","gp")
call gp.SetScale(scaleX,scaleY,scaleZ)
endif
endfunction
function SetUnitScalePercentAMHS takes unit whichUnit, real percentScaleX, real percentScaleY, real percentScaleZ returns nothing
call SetUnitScaleAMHS(whichUnit, percentScaleX * 0.01, percentScaleY * 0.01, percentScaleZ * 0.01)
endfunction
function GetUnitShadow takes unit u returns integer
local shadow sh
if u == null then
return 0
endif
//! runtextmacro AMHS_GetStructShadow("u","sh")
return sh
endfunction
function GetUnitGraphic takes unit u returns integer
local unitgraphic gp
if u == null then
return 0
endif
//! runtextmacro AMHS_GetStructUnitGraphic("u","gp")
return gp
endfunction
//End Public Functions
private function AddUnits takes unit u returns nothing
local string s
local string path
local real centrex
local real centrey
local real height
local real width
local integer red = 255
local integer green = 255
local integer blue = 255
local integer alpha = 255
local real x = 1
local real y = 1
local real z = 1
local shadow sh
local unitgraphic gp
set s = UnitId2String(GetUnitTypeId(u))
if GetStoredBoolean(fp_datacache,s,"exist") == true then
set path = GetStoredString(fp_datacache,s,"path")
set centrex = GetStoredReal(fp_datacache,s,"centrex")
set centrey = GetStoredReal(fp_datacache,s,"centrey")
set height = GetStoredReal(fp_datacache,s,"height")
set width = GetStoredReal(fp_datacache,s,"width")
set sh = shadow.Create(u,centrex,centrey,width,height,shadowalpha_default,path)
else
call BJDebugMsg("|cFFFF0000AMHS ERROR: Unable to create shadow for unit with UnitType ID " + s)
endif
if GetStoredBoolean(fp_datacache,s,"customtint") then
set red = GetStoredInteger(fp_datacache,s,"tintred")
set green = GetStoredInteger(fp_datacache,s,"tintgreen")
set blue = GetStoredInteger(fp_datacache,s,"tintblue")
set alpha = GetStoredInteger(fp_datacache,s,"tintalpha")
endif
if GetStoredBoolean(fp_datacache,s,"customscale") then
set x = GetStoredReal(fp_datacache,s,"scalex")
set y = GetStoredReal(fp_datacache,s,"scaley")
set z = GetStoredReal(fp_datacache,s,"scalez")
endif
set gp = unitgraphic.Create(u,red,green,blue,alpha,x,y,z)
set u = null
endfunction
private function ShadowGraphicManager takes nothing returns nothing
local unitgraphic gp
local shadow s
local integer counter = 0
local real l1 = GetRandomReal(1000,10000000000)
local real l2 = GetRandomReal(1000,10000000000)
local real l3 = GetRandomReal(1000,10000000000)
local player p = GetLocalPlayer()
loop
set gp = gp_StructStack[counter]
if integer(gp) > -1 then
if GetUnitTypeId(gp.u) == 0 then
call gp.destroy()
else
if IsUnitVisible(gp.u, p) then
if gp.enabled then
call SetUnitVertexColor(gp.u,gp.r,gp.g,gp.b,gp.a)
call SetUnitScale(gp.u,gp.x,gp.y,gp.z)
else
call SetUnitVertexColor(gp.u,0,0,0,0)
call SetUnitScale(gp.u,-l1,-l2,-l3)
endif
elseif InGame and GetLocalPlayer() == p then
call SetUnitVertexColor(gp.u,0,0,0,0)
call SetUnitScale(gp.u,-l1,-l2,-l3)
endif
endif
endif
set counter = counter + 1
exitwhen counter >= gp_StructNumber
endloop
set counter = 0
loop
set s = s_StructStack[counter]
if integer(s) > -1 then
if GetUnitTypeId(s.u) == 0 then
call s.destroy()
else
if GetUnitState(s.u,UNIT_STATE_MAX_LIFE) > 0.405 and s.deadunit then
call s.ChangeDeadUnit(false)
call s.SetShadowVisibility(true)
endif
if IsUnitVisible(s.u, p) then
if s.enabled then
call ShowImage(s.i,true)
else
call ShowImage(s.i,false)
endif
elseif InGame and GetLocalPlayer() == p then
call ShowImage(s.i,false)
endif
call SetImagePosition(s.i,GetUnitX(s.u),GetUnitY(s.u),0)
endif
endif
set counter = counter + 1
exitwhen counter >= s_StructNumber
endloop
endfunction
private function GroupAdder takes nothing returns nothing
call AddUnits(GetEnumUnit())
endfunction
private function TriggerAdder takes nothing returns boolean
call AddUnits(GetTriggerUnit())
return true
endfunction
private function AntiLeak takes nothing returns boolean
return true
endfunction
private function FinalGroup takes nothing returns nothing
call GroupAddUnit(g,GetEnumUnit())
endfunction
globals
private integer array bc_StructStack
private integer array bc_StructFreeStack
private integer bc_StructNumber = 0
private integer bc_StructFreeNumber = -1
endglobals
private struct buffcheck
unit u
integer position
integer buffstructid
integer unitgraphicid
integer counter
boolean increasing
boolean decreasing
real timeelapsed
static method Create takes unit u, integer buffstructid, integer unitgraphicid returns buffcheck
local buffcheck bc = buffcheck.create()
local buffstruct bs = buffstructid
set bc.u = u
set bc.buffstructid = buffstructid
set bc.unitgraphicid = unitgraphicid
set bc.counter = 0
set bc.timeelapsed = 0
if bs.SizeDurationIncrease > 0 then
set bc.increasing = true
else
set bc.increasing = false
endif
//Update Struct Stack
if bc_StructFreeNumber<0 then
set bc.position = bc_StructNumber
set bc_StructStack[bc_StructNumber] = bc
set bc_StructNumber = bc_StructNumber+1
else
set bc.position = bs_StructFreeStack[bc_StructFreeNumber]
set bc_StructStack[bc.position] = bc
set bc_StructFreeStack[bc_StructFreeNumber] = -1
set bc_StructFreeNumber = bc_StructFreeNumber-1
endif
return bc
endmethod
method onDestroy takes nothing returns nothing
set bc_StructStack[this.position] = -1
if (this.position>=(bc_StructNumber-1)) then
set bc_StructNumber = bc_StructNumber-1
else
set bc_StructFreeNumber = bc_StructFreeNumber+1
set bc_StructFreeStack[bc_StructFreeNumber] = this.position
endif
//! runtextmacro AMHS_DestroyStructShadow("this.u")
set this.u = null
set this.position = -1
endmethod
endstruct
private function BuffManager takes nothing returns nothing
local unit u = GetEnumUnit()
local integer counter = 0
local integer lastbuffid = 0
local buffstruct bs
local buffcheck bc
local unitgraphic gp
loop
if (bs_StructStack[counter]) > -1 then
set bs = bs_StructStack[counter]
if GetUnitAbilityLevel(u, bs.BuffID) == bs.Level and bs.BuffID != lastbuffid then
set lastbuffid = bs.BuffID
//! runtextmacro AMHS_GetStructBuff("u", "bc")
if bc <= 0 then
//! runtextmacro AMHS_GetStructUnitGraphic("u","gp")
if bs.SizeDurationIncrease == 0 then
call gp.SetScale(gp.x + bs.x,gp.y + bs.y,gp.z + bs.z)
endif
set bc = buffcheck.Create(u,bs,gp)
//! runtextmacro AMHS_StoreStructBuff("u", "bc")
endif
endif
endif
set counter = counter + 1
exitwhen counter >= bs_StructNumber
endloop
endfunction
private function BuffEnumerator takes nothing returns nothing
local group g = CreateGroup()
local integer counter = 0
local buffcheck bc
local buffstruct bs
local unitgraphic gp
call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea,Condition(function AntiLeak))
call ForGroup(g,function BuffManager)
call DestroyGroup(g)
set g = null
loop
if (bc_StructStack[counter]) > -1 then
set bc = bc_StructStack[counter]
set bs = bc.buffstructid
set gp = bc.unitgraphicid
set bc.timeelapsed = bc.timeelapsed + period
if GetUnitAbilityLevel(bc.u, bs.BuffID) == bs.Level then
if bs.Duration - bc.timeelapsed <= bs.SizeDurationIncrease then
set bc.decreasing = true
endif
if bc.increasing == true then
if (bc.counter != bs.increasecount) then
call gp.SetScale(gp.x + bs.increasex,gp.y + bs.increasey,gp.z + bs.increasez)
set bc.counter = bc.counter + 1
else
set bc.increasing = false
set bc.counter = 0
endif
endif
elseif (bc.decreasing == true) then
if (bc.counter != bs.increasecount) then
call gp.SetScale(gp.x - bs.increasex,gp.y - bs.increasey,gp.z - bs.increasez)
set bc.counter = bc.counter + 1
else
set bc.decreasing = false
endif
else
call bc.destroy()
endif
endif
set counter = counter + 1
exitwhen counter >= bc_StructNumber
endloop
endfunction
private function HideUnitOnDeath takes nothing returns nothing
local shadow sh
//! runtextmacro AMHS_GetStructShadow("GetTriggerUnit()","sh")
call sh.SetShadowVisibility(false)
call sh.ChangeDeadUnit(true)
endfunction
function Trig_Shadow_Engine_Actions takes nothing returns nothing
local timer t = CreateTimer()
local timer t2 = CreateTimer()
local integer i = 0
local group tempgroup
local trigger hideondeath
//! runtextmacro AMHS_StructInitializeLine()
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
loop
exitwhen i > 15
set tempgroup = CreateGroup()
call GroupEnumUnitsOfPlayer(tempgroup, Player(i), Filter( function AntiLeak))
call ForGroup(tempgroup, function FinalGroup)
call DestroyGroup(tempgroup)
set tempgroup = null
set i = i + 1
endloop
call ForGroup(g,function GroupAdder)
call DestroyGroup(g)
call TriggerRegisterEnterRectSimple(RegisterUnit, bj_mapInitialPlayableArea)
call TriggerAddCondition(RegisterUnit, Condition (function TriggerAdder))
call TimerStart(t,period,true,function ShadowGraphicManager)
call TimerStart(t2,period,true, function BuffEnumerator)
if hideshadowondeath then
set hideondeath = CreateTrigger()
call TriggerAddAction(hideondeath, function HideUnitOnDeath)
call TriggerRegisterAnyUnitEventBJ(hideondeath, EVENT_PLAYER_UNIT_DEATH )
endif
set t = null
set tempgroup = null
set hideondeath = null
endfunction
//===========================================================================
function InitTrig_Fog_Protect_and_Shadow_Engine takes nothing returns nothing
set gg_trg_Fog_Protect_and_Shadow_Engine = CreateTrigger( )
call TriggerRegisterTimerEventSingle(gg_trg_Fog_Protect_and_Shadow_Engine, 0.00)
call TriggerAddAction( gg_trg_Fog_Protect_and_Shadow_Engine, function Trig_Shadow_Engine_Actions )
endfunction
endlibrary
MiniMap Protect
Unlike the other systems the MiniMap protect does not crash wc3, instead it prevents MH's from revealing unseen units on the MiniMap (the fog will be lifted but beneath the fog there wont be any units seen, only the terrain). This works by setting an alternate MiniMap Icon which is blank/invisible and then using local code the system cycles through each player and for every unit that player cannot see it applies this MiniMap icon so it cannot be seen on the MiniMap
Spoiler:
Code: Select all
library MiniMapProtectEngine needs ReplayDetectEngine
//*************************************************************************
//* * *
//* MINIMAP PROTECT ENGINE v3.10 *
//* CONFIGURATION SETTINGS START HERE * *
//* * *
//*************************************************************************
globals
// The MiniMap engine requires you to provide the path to the MiniMMap - Blank.blp file. This
// shouldn't change in between maps if you use the default string, remember use '//' instead of
// '/' (double dash instead of single dash).
// As noted in the readme, its a very good idea to randomize the filename and the location
// to the file.
private constant string MiniMapPath = "HGVGWEO4NV\\435983460.blp"
// This is the interval period used by the system. 0.025 should be the LOWEST value, anything
// lower is pointless since 0.025 matches Wc3's maximum FPS (60 fp/s). If the system is
// causing lag then you should increase it to a value between 0.025 and 0.05. Anything higher
// then 0.05 is seriously not recommended since it will look visually choppy.
// NOTE: The system is INCREDIBLY efficient and it uses the struct-loop system (no H2I/attach
// methods are used for the timer interval) so in 99% of cases you should never have to increase
// the period
private constant real period = 0.025
//*************************************************************************
//* * *
//* MINIMAP PROTECT ENGINE v3.10 *
//* CONFIGURATION SETTINGS END HERE * *
//* * *
//*************************************************************************
endglobals
globals
private trigger RegisterUnit = CreateTrigger()
private gamecache mm_datacache
private gamecache mm_handlecache
private boolean cachefirst = true
real test = 0
private group g = CreateGroup()
//Stack for minimaphandler struct
private integer array StructStack
private integer array StructFreeStack
private integer StructNumber = 0
private integer StructFreeNumber = -1
endglobals
private function H2I takes handle h returns integer
return h
return 0
endfunction
private function InitializeHandleCache takes nothing returns nothing
call FlushGameCache(InitGameCache("mm_handlecache"))
set mm_handlecache=InitGameCache("mm_handlecache")
endfunction
private function InitializeDataCache takes nothing returns nothing
call FlushGameCache(InitGameCache("mm_datacache"))
set mm_datacache=InitGameCache("mm_datacache")
endfunction
//Public Functions
function GetUnitMiniMapIcon takes unit u returns integer
if u == null then
return 0
else
return GetStoredInteger(mm_handlecache,I2S(H2I(u)),"0")
endif
endfunction
struct minimapicon
readonly boolean enabled = true
readonly unit u
readonly integer position //position in relation to struct stack
static method Create takes unit u returns minimapicon
local minimapicon mm = minimapicon.create()
set mm.u = u
if StructFreeNumber<0 then
set mm.position = StructNumber
set StructStack[StructNumber] = mm
set StructNumber = StructNumber+1
else
set mm.position = StructFreeStack[StructFreeNumber]
set StructStack[mm.position] = mm
set StructFreeStack[StructFreeNumber] = -1
set StructFreeNumber = StructFreeNumber-1
endif
call StoreInteger(mm_handlecache,I2S(H2I(mm.u)),"0",mm)
return mm
endmethod
method SetMiniMapIconDisplay takes boolean enabled returns nothing
set this.enabled = enabled
endmethod
method GetMiniMapIconDisplay takes nothing returns boolean
return this.enabled
endmethod
method onDestroy takes nothing returns nothing
set StructStack[this.position] = -1
if (this.position>=(StructNumber-1)) then
set StructNumber = StructNumber-1
else
set StructFreeNumber = StructFreeNumber+1
set StructFreeStack[StructFreeNumber] = this.position
endif
set this.position = -1
call StoreInteger(mm_handlecache,I2S(H2I(this.u)),"0",0)
set this.u = null
endmethod
endstruct
//Public Functions
function RegisterMiniMapIconDisplay takes integer UnitID, boolean enabled returns nothing
local string s
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
set s = UnitId2String(UnitID)
call StoreBoolean(mm_datacache,s,"exist",true)
call StoreBoolean(mm_datacache,s,"enabled",enabled)
endfunction
private function MiniMapManager takes nothing returns nothing
local integer i = 0
local minimapicon mm
local player p = GetLocalPlayer()
loop
set mm = StructStack[i]
if integer(mm) > -1 then
if GetUnitTypeId(mm.u) == 0 then
call mm.destroy()
else
if IsUnitVisible(mm.u, p) then
if mm.enabled then
call UnitSetUsesAltIcon(mm.u,false)
else
call UnitSetUsesAltIcon(mm.u,true)
endif
elseif InGame and GetLocalPlayer() == p then
call UnitSetUsesAltIcon(mm.u,true)
endif
endif
endif
set i = i + 1
exitwhen i >= StructNumber
endloop
endfunction
private function AddUnits takes unit u returns nothing
local boolean enabled = true
local minimapicon mm
local string s
set s = UnitId2String(GetUnitTypeId(u))
if GetStoredBoolean(mm_datacache,s,"exist") == true then
set enabled = GetStoredBoolean(mm_datacache,s,"enabled")
endif
set mm = minimapicon.Create(u)
endfunction
private function TriggerAdder takes nothing returns boolean
call AddUnits(GetTriggerUnit())
return true
endfunction
private function GroupAdder takes nothing returns nothing
call AddUnits(GetEnumUnit())
endfunction
private function AntiLeak takes nothing returns boolean
return true
endfunction
private function FinalGroup takes nothing returns nothing
call GroupAddUnit(g,GetEnumUnit())
endfunction
private function Trig_MiniMap_Protect_Engine_Actions takes nothing returns nothing
local timer t = CreateTimer()
local integer i = 0
local group tempgroup
local trigger enginestart = GetTriggeringTrigger()
call DestroyTrigger(enginestart)
set enginestart=null
call SetAltMinimapIcon(MiniMapPath)
call InitializeHandleCache()
if cachefirst then
call InitializeDataCache()
set cachefirst = false
endif
loop
exitwhen i > 15
set tempgroup = CreateGroup()
call GroupEnumUnitsOfPlayer(tempgroup, Player(i), Filter( function AntiLeak))
call ForGroup(tempgroup, function FinalGroup)
call DestroyGroup(tempgroup)
set tempgroup = null
set i = i + 1
endloop
call ForGroup(g,function GroupAdder)
call DestroyGroup(g)
call TriggerRegisterEnterRectSimple(RegisterUnit, bj_mapInitialPlayableArea)
call TriggerAddCondition(RegisterUnit, Condition (function TriggerAdder))
call TimerStart(t,period,true,function MiniMapManager)
set t = null
set tempgroup = null
endfunction
public function StartPreload takes nothing returns nothing
call Preload(MiniMapPath)
endfunction
//===========================================================================
function InitTrig_MiniMap_Protect_Engine takes nothing returns nothing
set gg_trg_MiniMap_Protect_Engine = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_MiniMap_Protect_Engine, 0.00)
call TriggerAddAction( gg_trg_MiniMap_Protect_Engine, function Trig_MiniMap_Protect_Engine_Actions )
endfunction
endlibrary
AddSpecialEffect Emulator
This is an emulator designed to replace AddSpecialEffect so that the FogProtect and Shadow Engine has the ability to pick up effects and hide them if they are not visible to a player (done by using AddSpecialEffectTarget on an invisible dummy unit)
Spoiler:
Code: Select all
library AddSpecialEffectEx
//*************************************************************************
//* * *
//* AddSpecialEffect EMULATOR v1.10 *
//* CONFIGURATION SETTINGS START HERE * *
//* * *
//*************************************************************************
globals
//This is the rawcode for the dummy unit, make sure you update it as it changes between
//maps. Also make sure that the model file for the AMHS (Dummy Unit) is the dummy.mdx
//file which you should have also imported into your map
private integer Dummy_UnitId = 'h000'
// This is the Maximum time of any spell effect. You must designate a default time, so the
// system at one point can clean up the dummy units used. 15 seconds is a good amount
//(I seriously doubt any spell effect will last longer then 10 seconds)
private real MaxSpellEffectTime = 15
// This is the interval period used by the system. 0.025 should be the LOWEST value, anything
// lower is pointless since 0.025 matches Wc3's maximum FPS (60 fp/s). If the system is
// causing lag then you should increase it to a value between 0.025 and 0.05. Anything higher
// then 0.05 is seriously not recommended since it will look visually choppy.
// NOTE: The system is INCREDIBLY efficient and it uses the struct-loop system (no H2I/attach
// methods are used for the timer interval) so in 99% of cases you should never have to increase
// the period
private real period = 0.25
//*************************************************************************
//* * *
//* AddSpecialEffect EMULATOR v1.10 *
//* CONFIGURATION SETTINGS END HERE * *
//* * *
//*************************************************************************
endglobals
globals
private timer t
private integer array StructStack
private integer array StructFreeStack
private integer StructNumber = 0
private integer StructFreeNumber = -1
endglobals
struct specialeffectex
string effectpath
real timeout
real x
real y
effect e
unit u
real customdeathtime = 0
integer position
static method Create takes string modelname, real x , real y, boolean showdeath, real customdeathtime returns specialeffectex
local specialeffectex se = specialeffectex.create()
set se.x = x
set se.y = y
set se.u = CreateUnit(Player(15),Dummy_UnitId,x,y,0)
call SetUnitX(se.u,x)
call SetUnitY(se.u,y)
set se.effectpath = modelname
if showdeath then
call DestroyEffect(AddSpecialEffectTarget(modelname,se.u,"origin"))
else
set se.e = AddSpecialEffectTarget(modelname,se.u,"origin")
endif
set se.customdeathtime = customdeathtime
set se.timeout = TimerGetElapsed(t)
if StructFreeNumber<0 then
set se.position = StructNumber
set StructStack[StructNumber] = se
set StructNumber = StructNumber+1
else
set se.position = StructFreeStack[StructFreeNumber]
set StructStack[se.position] = se
set StructFreeStack[StructFreeNumber] = -1
set StructFreeNumber = StructFreeNumber-1
endif
return se
endmethod
method GetSpecialEffectExPath takes nothing returns string
return this.effectpath
endmethod
method GetSpecialEffectExX takes nothing returns real
return this.x
endmethod
method GetSpecialEffectExY takes nothing returns real
return this.y
endmethod
method onDestroy takes nothing returns nothing
set StructStack[this.position] = -1
if (this.position>=(StructNumber-1)) then
set StructNumber = StructNumber-1
else
set StructFreeNumber = StructFreeNumber+1
set StructFreeStack[StructFreeNumber] = this.position
endif
set this.position = -1
call ShowUnit(this.u,false)
call SetUnitExploded(this.u, true)
call KillUnit(this.u)
set this.u = null
if this.e != null then
call DestroyEffect(this.e)
endif
set this.e = null
endmethod
endstruct
function AddSpecialEffectEx takes string modelName, real x, real y returns integer
local specialeffectex sf = specialeffectex.Create(modelName,x,y,false,0)
return sf
endfunction
function AddSpecialEffectAdvancedEx takes string modelName, real x, real y, boolean ShowDestroy, real CustomDeathTime returns integer
local specialeffectex sf = specialeffectex.Create(modelName,x,y,ShowDestroy,CustomDeathTime)
return sf
endfunction
private function SpecialEffectExManager takes nothing returns nothing
local specialeffectex se
local integer counter = 0
local timer t = GetExpiredTimer()
loop
if (StructStack[counter]) > -1 then
set se = StructStack[counter]
if se.customdeathtime != 0 then
if (TimerGetElapsed(t) - se.timeout) >= MaxSpellEffectTime then
call se.destroy()
endif
else
if (TimerGetElapsed(t) - se.timeout) >= se.customdeathtime then
call se.destroy()
endif
endif
endif
set counter = counter + 1
exitwhen counter >= StructNumber
endloop
endfunction
function Trig_AddSpecialEffect_Emulator_Actions takes nothing returns nothing
set t = CreateTimer()
call TimerStart(t,period,true,function SpecialEffectExManager)
endfunction
//===========================================================================
function InitTrig_AddSpecialEffect_Emulator takes nothing returns nothing
set gg_trg_AddSpecialEffect_Emulator = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_AddSpecialEffect_Emulator, 0.00 )
call TriggerAddAction( gg_trg_AddSpecialEffect_Emulator, function Trig_AddSpecialEffect_Emulator_Actions )
endfunction
endlibrary
Spoiler for hidden information:
v5.2
- Fixed how the system cleans up removed units and greatly increased its
efficiency (thanks to Strilac)
- Methods are now truely readonly, the members inside the shadow/unitgraphic/minimapicon structs cannot be changed apart from using the methods
- Fixed an issue with the minimap protect not working properly in multiplayer
- Added a feature which allows you to change the struct attachment system
used by AMHS (default is gamecache, so far you can use HSAS/PUI/HAIL
as an alternative)
- Added a feature that allowed you to register buffs which increase the unit scale
- Destructable Protect has been removed due to the fact that the system was so inefficient that it created lag in big maps. Although this was a problem with the systems fault, it was the only way to program the engine (unfortunatley there is no way of detecting when destructables are created apart from replacing all CreateDestructable instances with another function, this means that the system had to go through every destructable using H2I in an interval). It is unlikely the system will be re-introduced in the near future unless an alternate method is found
- A feature in Fog Protect and Shadow Engine has been added which disables shadows when a unit dies (this happens normally with Blizzards shadow engine). You however have to option to disable this or make a units shadow visible when dead using the SetShadowVisibility method
- The Manual has been updated with the recent changes
- Mentioned that if you specify an incorrect raw code the map crashes
- Added a GUI Installation explanation written by PIGGY to make it easier for the GUI users to use the system
v5.1
- A minor bug in AddSpecialEffect Emulator has been fixed
- Forgot to add the sentry ward in the test map to the Shadow Configuration
v5.00
- JassNewGen is REQUIRED for this version, and there will be no non JassNewGen releases
- Fog Crasher system has been deleted and changed. It has now been replaced with a much more reliable and effective Fog Protect Engine which works the same way MiniMap Protect works (preventing Map Hacks from revealing units on the minimap).
- Destructable Protect has been added, which works the exact same way as Mini Map protect
- This version adds a lot of functionality, giving you full control of unit shadows and many other things
- RE-READ EVERYTHING BECAUSE ALMOST EVERYTHING HAS CHANGED
v4.40
- Fixed an issue with the map randomly crashing due to FogDetect (it was an issue with the dummy unit)
- Since the DummyUnit has been changed and nothing else, to upgrade from v4.30 simply delete the old dummy unit and replace it with the new one in this map
- The test map lets you initialize all systems at once, as well as seperatly
v4.30
- When installing this version it is highly recommended that you fully delete the old system (including all triggers/global variables (start with AMHS) and the custom script section) however you don't need to delete the dummy unit or Splats\LightningData.slk or MiniMap-Blank.blp or modelcrash.mdx
- Readme's have been updated
- An issue with v4.10 not detecting replays anymore has been fixed (replay detect function has been recoded)
- An issue with MiniMap Protect not revealing the minimap icons of units after they were hidden has been fixed
- An issue with the corrupted model where it would only crash if it was rendered in screen view
- Due to this the Invis/FogDetect has been completely recoded and uses local code, for this reason in InvisDetect you no longer need to specify a point
- Forgot to mention how to initialize Minimap protect
- Added extra functionality for testing
- Improved and changed issues with the Disable functions, they have been remade and now you can disable the AMHS for a specific player, for each engine
- There is now a JassNewGen version, apart from being slightly more efficient it is much easier to install (you just copy the dimmy unit and the triggers, no need for custom script/required variable triggers)
v4.10
- Various fixes have been done from the previous version
- An issue with the point searching system in both the InvisDetect and FogDetect has been fixed
- Multiplayer problems have been fixed due to values not being synced (Fog detect no longer desyncs, InvisDetect works for all players and MiniMap protect works for all players)
- Mentioned that it is impossible to hide the "Pause Game" message created by the Replay detect function
v4.00
- NOTE: In this version it is HIGHLY recommended that you fully delete any old version of AMHS (including the variables) and then install the new system
- A very silly error that sometimes causes the map to unintentionally crash in certain situations has been fixed (FogDetect)
- The system now counters all the major features of all public Map Hacks (read MH List trigger)
- FogDetect has completely been reworked, now uses corrupted models (please read the readmes and configuration settings). It also uses a buffer and efficiency greatly improved
- InvisDetect has been completely reworked, now only uses corrupted models (please read the readmes and configuration settings), it is also much much more efficient so you can increase the buffer to insane levels
- The system no longer uses rectangles at all, it now uses points (read the readme's for more info)
- MiniMap detect has been introduced which prevents the Mini-Map from revealing units that are not visible
- 2 extra files need to be copied into your map, modelcrash.mdx (for both FogDetect/InvisDetect) and MiniMap-Blank.blp for MiniMap protect
- Test map has been greatly improved, in order to create test Units use computers (or real players). You can now test the systems seperatly to see how they work
v3.20
- This will be the last release before v4, which will contain pure jass methods of detecting MH and all MH's, not just the popular ones
- An issue with desyncs (only in replays, not in actualy gameplay) has been fixed
- Another issue with the map un-intentionally crashing when a flame-strike based spell is cast on trees in the area where the corrupted lightning is. This has been fixed, which means the FogDetect system also uses a buffer like InvisDetect (it no longer uses fog to conceal a visible point, it will search for another location on the map that is not visible to the player)
- A missing variable (AMHS_InGameOutPut) has been put into the Required Variable triggers
- Handle leaks have been fixed
v3.0
- THIS IS INCREDIBLY IMPORTANT. Since cinematic mode removes fog, it will cause the map to crash if you view the lightning rectangle. In the new version there is an option to enable/disable the Fog Detect and Invis Detect engines if you are in cinematic mode
- I recommend this version for public use, after extensive testing it seems all
bugs and desync problems have been fixed
- Now I really mean it, the function properly uses GetLocalPlayer method without desyncs, no dummy units and the function is a lot less noticable
- The InGameFunction is only called once to save on efficiency
- You now have a choice if you want to save replays at the cost of initializing
the replay engine which is very noticable (can be hidden if done during a cinematic)
- The readmes are generally clearer to understand
- Properly updated the Required Variable triggers (in previous version some
variables were missing)
- Quick Tips have been added to make it easier for people to install the system
v2.20
- The sync method used by the function to detect replays was too noticable in the game (dummy units and such could actually be seen), the function now uses GetLocalPlayer to sync the cameras properly
- The info in the map descriptions and loading screens have been fixed
v2.10
- Accidentally left a boolean named udg_temp in the map
- ExecuteFunc error in the Fog Detect engine caused the map to crash when
Fog Detect was initialized (fixed)
- the temp used to create the fog is now checked if it exists before destroyed
- Fixed what could be some possible leaks with the dummy units in InvisDetect
v2.00 (Major Changes This Version)
- Finally a 100% fail proof function was found that could detect replays, so the system is now compatible with replays even in multiplayer (thx heaps to Toad Cop, Captain Griffein and PyroGasm)
- Because of the replay detection function, when the engine's initilize they will create a very slight pause (which can be noticable in game play)
- The AMHS system has been seperated into different modules so not only is it a lot easier for myself to edit but also easier for users to modify the configuration settings
- Finally the InvisDetect system is fully functional and even more a hell of a lot more efficient, it searches manually for each force which means substancially less searches, which means you can have your buffer set to 20 and in 99% of situations it will never go higher. On the downside this means it has to create more units (handles), however previously in some situations there was a huge amount of lag because simply put a point wasn't found that satisfied all forces. This way the maximum amount of searches required is usually around 5, and for a few more units thats a very good invalid to pay
v1.20b
- The function to determine if the game was a replay does not work in multiplayer, in fact it disabled the system altogether in mutiplayer. Because of this the function has been removed which means yet again turning off fog in replays will cause Wc3 to crash (sorry)
v1.20
- A possible abuse for the replay bug has now been fixed (issue with full Gamecache)
- Efficiency of the map has increased (checks if player exists before executing code etc)
- Problem with InvisDetect system were it did more random checks then it needed to is now fixed
v1.10
- The replay bug is now fixed, you can view your map in replays even with Fog Of War turned off
- A new system that detects when maphack reveals invisible units (check the readme and configuration for more info
v1.00 Initial Release
- Fixed how the system cleans up removed units and greatly increased its
efficiency (thanks to Strilac)
- Methods are now truely readonly, the members inside the shadow/unitgraphic/minimapicon structs cannot be changed apart from using the methods
- Fixed an issue with the minimap protect not working properly in multiplayer
- Added a feature which allows you to change the struct attachment system
used by AMHS (default is gamecache, so far you can use HSAS/PUI/HAIL
as an alternative)
- Added a feature that allowed you to register buffs which increase the unit scale
- Destructable Protect has been removed due to the fact that the system was so inefficient that it created lag in big maps. Although this was a problem with the systems fault, it was the only way to program the engine (unfortunatley there is no way of detecting when destructables are created apart from replacing all CreateDestructable instances with another function, this means that the system had to go through every destructable using H2I in an interval). It is unlikely the system will be re-introduced in the near future unless an alternate method is found
- A feature in Fog Protect and Shadow Engine has been added which disables shadows when a unit dies (this happens normally with Blizzards shadow engine). You however have to option to disable this or make a units shadow visible when dead using the SetShadowVisibility method
- The Manual has been updated with the recent changes
- Mentioned that if you specify an incorrect raw code the map crashes
- Added a GUI Installation explanation written by PIGGY to make it easier for the GUI users to use the system
v5.1
- A minor bug in AddSpecialEffect Emulator has been fixed
- Forgot to add the sentry ward in the test map to the Shadow Configuration
v5.00
- JassNewGen is REQUIRED for this version, and there will be no non JassNewGen releases
- Fog Crasher system has been deleted and changed. It has now been replaced with a much more reliable and effective Fog Protect Engine which works the same way MiniMap Protect works (preventing Map Hacks from revealing units on the minimap).
- Destructable Protect has been added, which works the exact same way as Mini Map protect
- This version adds a lot of functionality, giving you full control of unit shadows and many other things
- RE-READ EVERYTHING BECAUSE ALMOST EVERYTHING HAS CHANGED
v4.40
- Fixed an issue with the map randomly crashing due to FogDetect (it was an issue with the dummy unit)
- Since the DummyUnit has been changed and nothing else, to upgrade from v4.30 simply delete the old dummy unit and replace it with the new one in this map
- The test map lets you initialize all systems at once, as well as seperatly
v4.30
- When installing this version it is highly recommended that you fully delete the old system (including all triggers/global variables (start with AMHS) and the custom script section) however you don't need to delete the dummy unit or Splats\LightningData.slk or MiniMap-Blank.blp or modelcrash.mdx
- Readme's have been updated
- An issue with v4.10 not detecting replays anymore has been fixed (replay detect function has been recoded)
- An issue with MiniMap Protect not revealing the minimap icons of units after they were hidden has been fixed
- An issue with the corrupted model where it would only crash if it was rendered in screen view
- Due to this the Invis/FogDetect has been completely recoded and uses local code, for this reason in InvisDetect you no longer need to specify a point
- Forgot to mention how to initialize Minimap protect
- Added extra functionality for testing
- Improved and changed issues with the Disable functions, they have been remade and now you can disable the AMHS for a specific player, for each engine
- There is now a JassNewGen version, apart from being slightly more efficient it is much easier to install (you just copy the dimmy unit and the triggers, no need for custom script/required variable triggers)
v4.10
- Various fixes have been done from the previous version
- An issue with the point searching system in both the InvisDetect and FogDetect has been fixed
- Multiplayer problems have been fixed due to values not being synced (Fog detect no longer desyncs, InvisDetect works for all players and MiniMap protect works for all players)
- Mentioned that it is impossible to hide the "Pause Game" message created by the Replay detect function
v4.00
- NOTE: In this version it is HIGHLY recommended that you fully delete any old version of AMHS (including the variables) and then install the new system
- A very silly error that sometimes causes the map to unintentionally crash in certain situations has been fixed (FogDetect)
- The system now counters all the major features of all public Map Hacks (read MH List trigger)
- FogDetect has completely been reworked, now uses corrupted models (please read the readmes and configuration settings). It also uses a buffer and efficiency greatly improved
- InvisDetect has been completely reworked, now only uses corrupted models (please read the readmes and configuration settings), it is also much much more efficient so you can increase the buffer to insane levels
- The system no longer uses rectangles at all, it now uses points (read the readme's for more info)
- MiniMap detect has been introduced which prevents the Mini-Map from revealing units that are not visible
- 2 extra files need to be copied into your map, modelcrash.mdx (for both FogDetect/InvisDetect) and MiniMap-Blank.blp for MiniMap protect
- Test map has been greatly improved, in order to create test Units use computers (or real players). You can now test the systems seperatly to see how they work
v3.20
- This will be the last release before v4, which will contain pure jass methods of detecting MH and all MH's, not just the popular ones
- An issue with desyncs (only in replays, not in actualy gameplay) has been fixed
- Another issue with the map un-intentionally crashing when a flame-strike based spell is cast on trees in the area where the corrupted lightning is. This has been fixed, which means the FogDetect system also uses a buffer like InvisDetect (it no longer uses fog to conceal a visible point, it will search for another location on the map that is not visible to the player)
- A missing variable (AMHS_InGameOutPut) has been put into the Required Variable triggers
- Handle leaks have been fixed
v3.0
- THIS IS INCREDIBLY IMPORTANT. Since cinematic mode removes fog, it will cause the map to crash if you view the lightning rectangle. In the new version there is an option to enable/disable the Fog Detect and Invis Detect engines if you are in cinematic mode
- I recommend this version for public use, after extensive testing it seems all
bugs and desync problems have been fixed
- Now I really mean it, the function properly uses GetLocalPlayer method without desyncs, no dummy units and the function is a lot less noticable
- The InGameFunction is only called once to save on efficiency
- You now have a choice if you want to save replays at the cost of initializing
the replay engine which is very noticable (can be hidden if done during a cinematic)
- The readmes are generally clearer to understand
- Properly updated the Required Variable triggers (in previous version some
variables were missing)
- Quick Tips have been added to make it easier for people to install the system
v2.20
- The sync method used by the function to detect replays was too noticable in the game (dummy units and such could actually be seen), the function now uses GetLocalPlayer to sync the cameras properly
- The info in the map descriptions and loading screens have been fixed
v2.10
- Accidentally left a boolean named udg_temp in the map
- ExecuteFunc error in the Fog Detect engine caused the map to crash when
Fog Detect was initialized (fixed)
- the temp used to create the fog is now checked if it exists before destroyed
- Fixed what could be some possible leaks with the dummy units in InvisDetect
v2.00 (Major Changes This Version)
- Finally a 100% fail proof function was found that could detect replays, so the system is now compatible with replays even in multiplayer (thx heaps to Toad Cop, Captain Griffein and PyroGasm)
- Because of the replay detection function, when the engine's initilize they will create a very slight pause (which can be noticable in game play)
- The AMHS system has been seperated into different modules so not only is it a lot easier for myself to edit but also easier for users to modify the configuration settings
- Finally the InvisDetect system is fully functional and even more a hell of a lot more efficient, it searches manually for each force which means substancially less searches, which means you can have your buffer set to 20 and in 99% of situations it will never go higher. On the downside this means it has to create more units (handles), however previously in some situations there was a huge amount of lag because simply put a point wasn't found that satisfied all forces. This way the maximum amount of searches required is usually around 5, and for a few more units thats a very good invalid to pay
v1.20b
- The function to determine if the game was a replay does not work in multiplayer, in fact it disabled the system altogether in mutiplayer. Because of this the function has been removed which means yet again turning off fog in replays will cause Wc3 to crash (sorry)
v1.20
- A possible abuse for the replay bug has now been fixed (issue with full Gamecache)
- Efficiency of the map has increased (checks if player exists before executing code etc)
- Problem with InvisDetect system were it did more random checks then it needed to is now fixed
v1.10
- The replay bug is now fixed, you can view your map in replays even with Fog Of War turned off
- A new system that detects when maphack reveals invisible units (check the readme and configuration for more info
v1.00 Initial Release