• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Screen Buttons

Status
Not open for further replies.
Guys I need some bro tips ;)

I made this from like 5 or more different resources I found all over wc3 community.
The thing is this is really ugly.
I can use it, as you can see it works just fine, but I want to make it available to common users as well.

So I need your help and vjass suggestions.
 

Attachments

  • ScreenButton 1.0.0.0.w3x
    56.6 KB · Views: 96
I always wanted to make on Screen buttons but didn't know how, the idea is cool but the only problem is with the icon texture quality. But sorry I can't help you in an vJASS tip I can barely understand it. Sorry about that.
Texture quality is really simple thing, all you need to do is to increase base model and texture size and quality :)
 
ok, I have a question. When I get near the shops the buttons slipped to the right was this made on purpose or because of the camera bounds ?

System has 2 critical flaws: Camera bounds, blizzard cliffs.
There is no easy and safe way to handle this, and because of that, you should find way around.

Bigger maps, and custom cliffs will do just fine.
 
Level 16
Joined
Mar 3, 2006
Messages
1,564
It is good IMO

System has 2 critical flaws: Camera bounds, blizzard cliffs.
There is no easy and safe way to handle this, and because of that, you should find way around.

Bigger maps, and custom cliffs will do just fine.

Then, what is wrong ?! the system IMO is cool and very useful; to have extra buttons in the screen that would be very cool, I think. Unless, you are asking for a code improvisation then I will have to remain silent cause that advanced vJASS is too big for me to handle.
 
I definitely agree with Luorax's post. In multiplayer, the difference becomes even more noticeable.

As for the system, one tip is to choose your timer frequencies wisely. For example, a timer that updates the position of the objects at a rate of 0.1 will be a lot more jittery than one that updates the position at a rate of 0.01.

Camera bounds are a tricky thing. In most maps the problem can be avoided by blocking out those camera bounds. Or you can detect when the camera has reached the bounds and then you will just fixate the positions or something like that. It takes a bit of work but it is a bit better than having the icons slide off the screen. :) Use these natives:
JASS:
constant native GetCameraBoundMinX          takes nothing returns real
constant native GetCameraBoundMinY          takes nothing returns real
constant native GetCameraBoundMaxX          takes nothing returns real
constant native GetCameraBoundMaxY          takes nothing returns real

Sadly, I can't see the code so I can't provide a whole lot of a feedback. But hopefully what I've said will help.
 
Nestharus will make a DGUI version of himself.
Hmmm,perhaps this could be useful

@Purge

[jass=]//TESH.scrollpos=147
//TESH.alwaysfold=0
//! zinc
library PeriodicLoop requires optional xebasic {
/**
* The main purpose of PeriodicLoop is to provide the user with a module that implements a fully optimized
* periodic loop for a struct. Instances that are added to the loop are stored in a doubly linked list, which improves
* the loop's efficiency and allows the removal to be just as easy as the insertion. The user is also provided with
* internal wrappers that are meant to be used when dealing with static functions, as opposed to the regular, non-static
* methods. These wrappers are implemented with the help of a dummy struct and function pointers.
*
* Note that this script was written solely for high-frequency loops, and is by default configured to loop 40 times per
* second. You can change this interval by editing PERIODIC_LOOP_INTERVAL constant found right below the documentation.
* That constant is also public, and as such should be used with all "over time" effects in order to ensure consistency,
* accuracy and portability. Neither multiple intervals nor dynamic adjustments in the interval are supported.
*
* If the xebasic library is present within the map, then the XE_ANIMATION_PERIOD constant will be used instead of
* PERIODIC_LOOP_INTERVAL. Please, do not set these constants to anything higher than 0.05, as that would result in lots
* of stuff being inaccurate and bumpy. The most commonly used values are 0.025 and 0.03125.
*
* Now, let's elaborate on the implementation of the script. As I mentioned earlier, you can utilize two "types" of API:
*
* - For the regular, module-based API, the following things need to be done:
*
* 1) Implement the "PeriodicLoop" module within your struct.
* 2) Declare a non-static method named "onPeriodicLoop". That particular method will be called every interval
* as long as there are nodes on the looping list.
* 3) When you're willing to add a node, simply call structInstance.startPeriodicLoop(), and when you're willing
* to remove it, call structInstance.stopPeriodicLoop().
* 4) Make sure that the module is implemented above all .startPeriodicLoop() calls and below the
* "onPeriodicLoop" method in order to avoid unnecessary trigger evaluations. This is very important.
* 5) Do not leave destroyed instances in the loop - always call .stopPeriodicLoop() before calling .destroy() or
* .deallocate().
*
* - Registering static functions is even easier. The API is the following:
*
* 1) RegisterPeriodicResponse takes response whichResponse returns nothing
* 2) UnregisterPeriodicResponse takes response whichResponse returns nothing
*
* In the above two functions, "response" is a function pointer (you can see its definition below), so "whichResponse"
* is the name of a function or a static method that takes and returns nothing. Akin to the "onPeriodicLoop" method, the
* passed response will be called every interval until UnregisterPeriodicResponse(response) is called.
*/
public constant real PERIODIC_LOOP_INTERVAL = 1.0/40.0;

type response extends function();

private
{
trigger mainTrigger = CreateTrigger(); // The trigger onto which the iterators will be attached.
timer mainTimer = CreateTimer(); // This timer will be used to periodically evaluate the above trigger.
integer that = 0, globalCount = 0; // The former will be used to temporarily store a node, while the
} // latter will be used to keep count of the running instances.

public module PeriodicLoop
{
private // Module-private members.
{
thistype next, previous; // These, along with the null struct, will help us build the doubly linked list.
boolean alreadyInserted, pendingRemoval; // Self-explanatory, I hope.
static triggercondition instanceIterator = null; // We will use this variable to store the struct's iterator.
static boolean threadCrashed = false; // In debug mode, this boolean will help us catch and report thread crashes.
}

private static method iterator() -> boolean
{
thistype this = thistype(0).next; // Get the first node.

debug
{
if (thistype.threadCrashed) // Warn the user if the thread had crashed during the last loop.
{
BJDebugMsg("PeriodicLoop warning: The thread had crashed during the last loop!\n" +
"Make sure you are not performing very intensive operations or using uninitialized variables!\n" +
"The name of the iterator in which the thread crashed is \"" + thistype.iterator.name + "\"");
}
thistype.threadCrashed = true;
}

while (integer(this) != 0) // Traverse the list.
{
if (this.pendingRemoval) // See if the current node should be removed.
{
this.pendingRemoval = false;

// Remove the node.
this.previous.next = this.next;
this.next.previous = this.previous;

if (this.alreadyInserted) // See if the node should be reinserted.
{
that = integer(this.next); // Temporarily store the next node.

// Reinsert it at the end of the list.
thistype(0).previous.next = this;
this.previous = thistype(0).previous;
thistype(0).previous = this;
this.next = thistype(0);

if (thistype(that) == thistype(0)) // If the next node was in fact null,
this = thistype(0).previous; // then go back to the previous one.
else
this = thistype(that); // Otherwise, go to the next node normally.
}
else
{
globalCount -= 1; // Decrement the global count.

if (globalCount == 0) // Check whether the timer should keep running.
PauseTimer(mainTimer);

if (thistype(0).next == thistype(0)) // Check if the iterator should be detached from the trigger.
TriggerRemoveCondition(mainTrigger, thistype.instanceIterator);

this = this.next; // Go to the next node.
}
}
else
{
this.onPeriodicLoop(); // Call the .onPeriodicLoop() method.
this = this.next; // Go to the next node.
}
}

debug thistype.threadCrashed = false; // If we made it here, then the thread hasn't crashed.

return false;
}

method startPeriodicLoop()
{
if (!this.alreadyInserted && integer(this) > 0) // Make sure the method was called on a valid node.
{
this.alreadyInserted = true;

if (!this.pendingRemoval) // First, see if the node was flagged for removal.
{
// And if it wasn't, insert it at the end of the linked list.
thistype(0).previous.next = this;
this.previous = thistype(0).previous;
thistype(0).previous = this;
this.next = thistype(0);

globalCount += 1; // Increment the global count.

if (globalCount == 1) // Check if the timer should be started (or resumed).
static if (LIBRARY_xebasic)
TimerStart(mainTimer, XE_ANIMATION_PERIOD, true, static method() { TriggerEvaluate(mainTrigger); });
else
TimerStart(mainTimer, PERIODIC_LOOP_INTERVAL, true, static method() { TriggerEvaluate(mainTrigger); });

if (this.previous == thistype(0)) // Check if the iterator should be (re)attached to the trigger.
thistype.instanceIterator = TriggerAddCondition(mainTrigger, Condition(static method thistype.iterator));
}
}
}

method stopPeriodicLoop()
{
if (this.alreadyInserted && integer(this) > 0) // Make sure the method was called on a valid node.
{
this.pendingRemoval = true; // Flag this node so that it would be removed during the next loop.
this.alreadyInserted = false;
}
}
}

private struct staticFunctionHelper[] // This is just a dummy struct.
{
method onPeriodicLoop()
{
response(integer(this)).evaluate();
}
module PeriodicLoop;
}

public // Below is the API for dealing with static responses.
{
function RegisterPeriodicResponse(response whichResponse)
{
staticFunctionHelper(integer(whichResponse)).startPeriodicLoop();
}

function UnregisterPeriodicResponse(response whichResponse)
{
staticFunctionHelper(integer(whichResponse)).stopPeriodicLoop();
}
}
}
//! endzinc[/code]
[jass=]//TESH.scrollpos=0
//TESH.alwaysfold=0
library Cameramap initializer cameramapInit
globals
location cameramapLoc
real array camOffset[90][90]
real mapMinX
real mapMinY
real mapMaxX
real mapMaxY
endglobals

function GetGridCamOffset takes integer ix, integer iy, integer offx, integer offy returns real
local real r
local integer ixl = ix-1
local integer ixr = ix+1
local integer iyd = iy-1
local integer iyu = iy+1
if ixl<0 then
set ixl = 0
endif
if iyd<0 then
set iyd = 0
endif
if ixr>256 then
set ixr=256
endif
if iyu>256 then
set iyu=256
endif
if offx>0 then
if offy>0 then
set r = .089696*camOffset[ixl][iyu]+ .139657*camOffset[ix][iyu]+ .097349*camOffset[ixr][iyu]
set r = r+.130989*camOffset[ixl][iy] + .099380*camOffset[ix][iy] + .139657*camOffset[ixr][iy]
set r = r+.082587*camOffset[ixl][iyd]+ .130989*camOffset[ix][iyd]+ .089696*camOffset[ixr][iyd]
elseif offy<0 then
set r = .082587*camOffset[ixl][iyu]+ .130989*camOffset[ix][iyu]+ .089696*camOffset[ixr][iyu]
set r = r+.130989*camOffset[ixl][iy] + .099380*camOffset[ix][iy] + .139657*camOffset[ixr][iy]
set r = r+.089696*camOffset[ixl][iyd]+ .139657*camOffset[ix][iyd]+ .097349*camOffset[ixr][iyd]
else
set r = .084604*camOffset[ixl][iyu]+ .134226*camOffset[ix][iyu]+ .091913*camOffset[ixr][iyu]
set r = r+.134017*camOffset[ixl][iy] + .101594*camOffset[ix][iy] + .142877*camOffset[ixr][iy]
set r = r+.084604*camOffset[ixl][iyd]+ .134226*camOffset[ix][iyd]+ .091913*camOffset[ixr][iyd]
endif
elseif offx<0 then
if offy>0 then
set r = .097349*camOffset[ixl][iyu]+ .139657*camOffset[ix][iyu]+ .089696*camOffset[ixr][iyu]
set r = r+.139657*camOffset[ixl][iy] + .099380*camOffset[ix][iy] + .130989*camOffset[ixr][iy]
set r = r+.089696*camOffset[ixl][iyd]+ .130989*camOffset[ix][iyd]+ .082587*camOffset[ixr][iyd]
elseif offy<0 then
set r = .089696*camOffset[ixl][iyu]+ .130989*camOffset[ix][iyu]+ .082587*camOffset[ixr][iyu]
set r = r+.139657*camOffset[ixl][iy] + .099380*camOffset[ix][iy] + .130989*camOffset[ixr][iy]
set r = r+.097349*camOffset[ixl][iyd]+ .139657*camOffset[ix][iyd]+ .089696*camOffset[ixr][iyd]
else
set r = .091913*camOffset[ixl][iyu]+ .134226*camOffset[ix][iyu]+ .084604*camOffset[ixr][iyu]
set r = r+.142877*camOffset[ixl][iy] + .101594*camOffset[ix][iy] + .134017*camOffset[ixr][iy]
set r = r+.091913*camOffset[ixl][iyd]+ .134226*camOffset[ix][iyd]+ .084604*camOffset[ixr][iyd]
endif
else
if offy>0 then
set r = .091913*camOffset[ixl][iyu]+ .142877*camOffset[ix][iyu]+ .091913*camOffset[ixr][iyu]
set r = r+.134226*camOffset[ixl][iy] + .101594*camOffset[ix][iy] + .134226*camOffset[ixr][iy]
set r = r+.084604*camOffset[ixl][iyd]+ .134017*camOffset[ix][iyd]+ .084604*camOffset[ixr][iyd]
elseif offy<0 then
set r = .084604*camOffset[ixl][iyu]+ .134017*camOffset[ix][iyu]+ .084604*camOffset[ixr][iyu]
set r = r+.134226*camOffset[ixl][iy] + .101594*camOffset[ix][iy] + .134226*camOffset[ixr][iy]
set r = r+.091913*camOffset[ixl][iyd]+ .142877*camOffset[ix][iyd]+ .091913*camOffset[ixr][iyd]
else
set r = .086125*camOffset[ixl][iyu]+ .136429*camOffset[ix][iyu]+ .086125*camOffset[ixr][iyu]
set r = r+.136429*camOffset[ixl][iy] + .109784*camOffset[ix][iy] + .136429*camOffset[ixr][iy]
set r = r+.086125*camOffset[ixl][iyd]+ .136429*camOffset[ix][iyd]+ .086125*camOffset[ixr][iyd]
endif
endif
return r
endfunction

function GetCamOffset takes real x, real y returns real
local integer iXLo = R2I((x-mapMinX)/512.+.5)
local integer iYLo = R2I((y-mapMinY)/512.+.5)
local integer iXHi = iXLo+1
local integer iYHi = iYLo+1
local integer iChkXLo
local integer iChkXLoOff
local integer iChkXHi
local integer iChkXHiOff
local integer iChkYLo
local integer iChkYLoOff
local integer iChkYHi
local integer iChkYHiOff
local real XLo
local real YLo
local real XHi
local real YHi
local real rX
local real rY
local real r
local real LoDX = (x-mapMinX)-(iXLo*512.-256.)
local real LoDY = (y-mapMinY)-(iYLo*512.-256.)
if LoDX<=12 then
set iChkXLo = iXLo
set iChkXLoOff = 0
set iChkXHi = iXLo
set iChkXHiOff = 1
elseif LoDX<500 then
set iChkXLo = iXLo
set iChkXLoOff = 1
set iChkXHi = iXHi
set iChkXHiOff =-1
else
set iChkXLo = iXHi
set iChkXLoOff =-1
set iChkXHi = iXHi
set iChkXHiOff = 0
endif
if LoDY<=12 then
set iChkYLo = iYLo
set iChkYLoOff = 0
set iChkYHi = iYLo
set iChkYHiOff = 1
elseif LoDY<500 then
set iChkYLo = iYLo
set iChkYLoOff = 1
set iChkYHi = iYHi
set iChkYHiOff =-1
else
set iChkYLo = iYHi
set iChkYLoOff =-1
set iChkYHi = iYHi
set iChkYHiOff = 0
endif
set XLo = iChkXLo*512.+iChkXLoOff*12.-256.
set XHi = iChkXHi*512.+iChkXHiOff*12.-256.
set YLo = iChkYLo*512.+iChkYLoOff*12.-256.
set YHi = iChkYHi*512.+iChkYHiOff*12.-256.
set rX = ((x-mapMinX)-XLo)/(XHi-XLo)
set rY = ((y-mapMinY)-YLo)/(YHi-YLo)
set r = GetGridCamOffset(iChkXHi,iChkYHi,iChkXHiOff,iChkYHiOff)*rX*rY
set r = r+GetGridCamOffset(iChkXLo,iChkYHi,iChkXLoOff,iChkYHiOff)*(1-rX)*rY
set r = r+GetGridCamOffset(iChkXHi,iChkYLo,iChkXHiOff,iChkYLoOff)*rX*(1-rY)
set r = r+GetGridCamOffset(iChkXLo,iChkYLo,iChkXLoOff,iChkYLoOff)*(1-rX)*(1-rY)
return r
endfunction

function cameramapInit_GridSub takes real x, real y returns real
local integer index
local integer iX = -6
local integer iY
local real z
local real r
local real i = 64 //9*4+12*2+4
call MoveLocation(cameramapLoc,x,y)
set z = GetLocationZ(cameramapLoc)
set r = 0.
call MoveLocation(cameramapLoc,x-128.,y)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x,y)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x+128.,y)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x-128.,y+128.)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x,y+128.)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x+128.,y+128.)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x-128.,y-128.)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x,y-128.)
set r = r+GetLocationZ(cameramapLoc)*4./i
call MoveLocation(cameramapLoc,x+128.,y-128.)
set r = r+GetLocationZ(cameramapLoc)*4./i

call MoveLocation(cameramapLoc,x-256.,y-128.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x-256.,y)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x-256.,y+128.)
set r = r+GetLocationZ(cameramapLoc)*2./i

call MoveLocation(cameramapLoc,x+256.,y-128.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x+256.,y)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x+256.,y+128.)
set r = r+GetLocationZ(cameramapLoc)*2./i

call MoveLocation(cameramapLoc,x-128.,y-256.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x,y-256.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x+128.,y-256.)
set r = r+GetLocationZ(cameramapLoc)*2./i

call MoveLocation(cameramapLoc,x-128.,y+256.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x,y+256.)
set r = r+GetLocationZ(cameramapLoc)*2./i
call MoveLocation(cameramapLoc,x+128.,y+256.)
set r = r+GetLocationZ(cameramapLoc)*2./i

call MoveLocation(cameramapLoc,x+256.,y+256.)
set r = r+GetLocationZ(cameramapLoc)*1./i
call MoveLocation(cameramapLoc,x+256.,y-256.)
set r = r+GetLocationZ(cameramapLoc)*1./i
call MoveLocation(cameramapLoc,x-256.,y+256.)
set r = r+GetLocationZ(cameramapLoc)*1./i
call MoveLocation(cameramapLoc,x-256.,y-256.)
set r = r+GetLocationZ(cameramapLoc)*1./i
return r
endfunction

function cameramapInit_DoRow takes nothing returns nothing
local real x = mapMinX+256.
local real y = mapMinY+256.
local integer iX = bj_forLoopAIndex
local integer iY = 0
loop
exitwhen y+iY*512.>mapMaxY
set camOffset[(iX+1)][iY+1] = cameramapInit_GridSub(x+iX*512.,y+iY*512.)
set iY = iY + 1
endloop
endfunction

function cameramapInit takes nothing returns nothing
local real x
local real y
local integer iX = 0
local integer iY
local rect map = GetWorldBounds()
set mapMinX = GetRectMinX(map)
set mapMinY = GetRectMinY(map)
set mapMaxX = GetRectMaxX(map)
set mapMaxY = GetRectMaxY(map)
call RemoveRect(map)
set map = null
set x = mapMinX+256.
set y = mapMinY+256.
set cameramapLoc = Location(0,0)
loop
exitwhen x+iX*512.>mapMaxX
set bj_forLoopAIndex = iX
call ExecuteFunc("cameramapInit_DoRow")
set iX = iX + 1
endloop
call RemoveLocation(cameramapLoc)
set cameramapLoc = null
endfunction
endlibrary[/code]
[jass=]//TESH.scrollpos=119
//TESH.alwaysfold=0
library ScreenUnit requires PeriodicLoop, Cameramap

globals
private hashtable hash = InitHashtable()
private unit hero = null
endglobals

struct ScreenUnit
static constant integer FLYHEIGHT_ABILITY = 'Amrf'
static constant real OFFSET = 512.0
static boolean FORCE_CAMERA_HEIGHT = true
static real forcedCameraHeight = 0.0
readonly unit u
real x = 0.0
real y = 0.0
private static real z = 0.0

private static method SetCameraZ takes real z returns nothing
set z = GetCameraField(CAMERA_FIELD_ZOFFSET) + z - GetCameraTargetPositionZ()
call SetCameraField(CAMERA_FIELD_ZOFFSET, z, -1/65.0)
call SetCameraField(CAMERA_FIELD_ZOFFSET, z, 1/65.0)
endmethod

private static real dxx = 0.0
private static real dxy = 0.0
private static real dxz = 0.0

private static real dyx = 0.0
private static real dyy = 0.0
private static real dyz = 0.0

private static real gx = 0.0
private static real gy = 0.0
private static real gz = 0.0

private static location l = Location(0.0,0.0)

private static method setupScreenData takes nothing returns nothing
local real r = GetCameraField( CAMERA_FIELD_ROLL )
local real CosRoll = GetCameraField( CAMERA_FIELD_ROTATION ) // Temporarily used for other values
local real SinRoll = GetCameraField( CAMERA_FIELD_ANGLE_OF_ATTACK ) // to avoid declaring unneeded locals.

local real CosAngle = Cos(CosRoll) // Angle.
local real SinAngle = Sin(CosRoll)
local real CosPitch = Cos(SinRoll) // Pitch.
local real SinPitch = Sin(SinRoll)
set CosRoll = Cos(r) // Roll.
set SinRoll = Sin(r)

set r = GetCameraField( CAMERA_FIELD_TARGET_DISTANCE )-OFFSET
set .gx = GetUnitX(hero)
set .gy = GetUnitY(hero)
call SetCameraPosition(.gx, .gy)
call MoveLocation(.l, .gx, .gy)
//set .gx = GetCameraTargetPositionX()-r*CosPitch*CosAngle
//set .gy = GetCameraTargetPositionY()-r*CosPitch*SinAngle
if .FORCE_CAMERA_HEIGHT then
//call .SetCameraZ(GetLocationZ(.l)+.forcedCameraHeight)
call SetCameraField(CAMERA_FIELD_ZOFFSET,GetLocationZ(.l)+.forcedCameraHeight-GetCamOffset(.gx, .gy),0.0)

set .gz = .forcedCameraHeight+GetLocationZ(.l)-r*SinPitch
else
set .gz = GetCameraField( CAMERA_FIELD_ZOFFSET )+GetLocationZ(.l)-r*SinPitch
endif
set .gx = .gx-r*CosPitch*CosAngle
set .gy = .gy-r*CosPitch*SinAngle

set .dxx = ( CosRoll*SinAngle - SinRoll*SinPitch*CosAngle )*OFFSET
set .dxy = (-CosRoll*CosAngle - SinRoll*SinPitch*SinAngle )*OFFSET
set .dxz = ( SinRoll*CosPitch )*OFFSET

set .dyx = (-SinRoll*SinAngle - CosRoll*SinPitch*CosAngle )*OFFSET
set .dyy = ( SinRoll*CosAngle - CosRoll*SinPitch*SinAngle )*OFFSET
set .dyz = ( CosRoll*CosPitch )*OFFSET
endmethod

static method onInit takes nothing returns nothing
call RegisterPeriodicResponse(thistype.setupScreenData)
set hero = CreateUnit(Player(0), 'Hpal', 0.0,0.0,0.0)
endmethod

private method onPeriodicLoop takes nothing returns nothing
local real ux=.gx+.dxx*x+.dyx*y
local real uy=.gy+.dxy*x+.dyy*y

call MoveLocation(l, ux, uy)
static if LIBRARY_BoundSentinel then
if GetUnitX(.u)!=ux then
call SetUnitX(.u, ux)
endif
if GetUnitY(.u)!=uy then
call SetUnitY(.u, uy)
endif
else
if GetUnitX(.u)!=ux or GetUnitY(.u)!=uy then
call SetUnitPosition(.u, ux, uy)
endif
endif
call SetUnitFlyHeight(.u, .gz+.dxz*x+.dyz*y-GetLocationZ(.l), 0.0)
endmethod

implement PeriodicLoop

static method create takes integer id, player p, integer unit_id, real xc, real yc, real size, code c returns thistype
local thistype this = thistype.allocate()
local trigger trig = CreateTrigger()

set this.u = CreateUnit(p, unit_id, 0,0,0)
call SetUnitPathing(this.u, false)
call SetUnitScale(this.u, size, 0,0)

call SaveInteger(hash, GetHandleId(this.u), 0, id)

if UnitAddAbility(this.u, this.FLYHEIGHT_ABILITY) then
call UnitRemoveAbility(this.u, this.FLYHEIGHT_ABILITY)
endif

if xc > 0.5 then
set x = 0.5
else
set x = xc
endif

if xc < -0.475 then
set x = -0.475
else
set x = xc
endif

if yc > 0.28 then
set y = 0.28
else
set y = yc
endif

if yc < -0.2 then
set y = -0.2
else
set y = yc
endif

call TriggerRegisterUnitEvent(trig, u, EVENT_UNIT_SELECTED)
call TriggerAddAction(trig, c)
set trig = null

call .startPeriodicLoop()
return this
endmethod

method destroy takes nothing returns nothing
call .stopPeriodicLoop()
call .deallocate()
endmethod
endstruct

function GetButtonId takes unit u returns integer
return LoadInteger(hash, GetHandleId(u), 0)
endfunction

endlibrary[/code]
[jass=]//TESH.scrollpos=7
//TESH.alwaysfold=0
library ScreenUnitTesting initializer Init requires ScreenUnit

private function Click1 takes nothing returns nothing
call SelectUnit(GetTriggerUnit(), false)
call BJDebugMsg("Click Event: private function Click1")
call BJDebugMsg("Click Event: " + GetUnitName(GetTriggerUnit()) + " : " + I2S(GetUnitTypeId(GetTriggerUnit())))
endfunction

private function Click2 takes nothing returns nothing
call SelectUnit(GetTriggerUnit(), false)
call BJDebugMsg("Click Event: private function Click2")
call BJDebugMsg("Click Event: " + GetUnitName(GetTriggerUnit()) + " : " + I2S(GetUnitTypeId(GetTriggerUnit())))
endfunction

private function Click3 takes nothing returns nothing
local unit u = GetTriggerUnit()
call SelectUnit(u, false)
call BJDebugMsg("Click Event: private function Click3")
call BJDebugMsg("Click Event: " + GetUnitName(u) + " : " + I2S(GetUnitTypeId(u)))

if GetButtonId(u) == 2 then
call SelectUnit(gg_unit_ngme_0002, true)

elseif GetButtonId(u) == 3 then
call SelectUnit(gg_unit_nmrk_0003, true)

elseif GetButtonId(u) == 5 then
call SelectUnit(gg_unit_hvlt_0001, true)
endif
endfunction

private function Init takes nothing returns nothing
local ScreenUnit s
/* id player unit_id x y size code */
/* Button Backpack */
set s = ScreenUnit.create( 1, Player(0), 'h000', 0.500, 0.28, 1.50, function Click1)
/* Button Shop 1 */
set s = ScreenUnit.create( 2, Player(0), 'h001', 0.500, -0.20, 1.50, function Click3)
/* Button Shop 2 */
set s = ScreenUnit.create( 3, Player(0), 'h002', 0.450, -0.20, 1.50, function Click3)
/* Button Bag */
set s = ScreenUnit.create( 4, Player(0), 'h003', 0.500, 0.22, 1.50, function Click2)
/* Button Shop 3 */
set s = ScreenUnit.create( 5, Player(0), 'h004', 0.400, -0.20, 1.50, function Click3)

call SetPlayerState(Player(0), PLAYER_STATE_RESOURCE_GOLD, 10000)
endfunction
endlibrary[/code]
 
Status
Not open for further replies.
Top