package ArcingLoot
import LinkedListModule
import TimerUtils
import Fx
constant real arc = 75 //modifies the arcing shape
constant real arcHeight = 350 //how high the arc reach at its peak
constant real travelTime = 0.9 //time it takes for the arc to reach destination
constant real convertArc = arc / 100.00 // do not touch
constant string sfx = "Objects\\InventoryItems\\TreasureChest\\treasurechest.mdl" //effect, the item chest in this case
constant real loopSpeed = 0.03 //how often the system runs its loop. Higher value equals better perfomance
constant location loc = Location(0,0)
function vec2.getZ() returns real
MoveLocation(loc, this.x, this.y)
return GetLocationZ(loc)
public class ArcingItem
use LinkedListModule
static timer t
integer id
Fx fx
angle angle
real distance
real maxDistance
real arc
real speed
effect e
vec2 pos
vec2 destination
construct(integer itemId, vec2 start, vec2 dest)
pos = start
fx = new Fx(pos, angle(0), sfx)
angle = pos.angleTo(dest)
distance = pos.distanceTo(dest)
maxDistance = distance
speed = distance / (travelTime / loopSpeed)
destination = dest
arc = distance * convertArc
id = itemId
e = fx.getDummy().addEffect("Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl", "chest")
if(t == null)
getTimer()
..startPeriodic(loopSpeed, function ArcingItem.onLoop)
static function onLoop()
thistype current = ArcingItem.first
while(current != null)
current.update()
current = current.next
function update()
pos.x = pos.x + speed * Cos(angle.radians)
pos.y = pos.y + speed * Sin(angle.radians)
distance = pos.distanceTo(destination)
real one = (4.00 * arc) / maxDistance
real two = maxDistance - distance
real three = distance / maxDistance
real four = pos.getZ()
real height = (one * two * three) + (four)
fx.getDummy().setPosFly(vec3(pos.x, pos.y, height))
if(height <= 0)
e.destr()
createItem(id, pos)
destroy fx
destroy this
package ArcingText
import LinkedListModule
import TimerUtils
// Arcing Text Tag v1.0.0.3 by Maker
// Converted to wurst by Chaosy
constant real SIZE_MIN = 0.018 // Minimum size of text
constant real SIZE_BONUS = 0.012 // Text size increase
constant real TIME_LIFE = 1.0 // How long the text lasts
constant real TIME_FADE = 0.8 // When does the text start to fade
constant real Z_OFFSET = 50 // Height above unit
constant real Z_OFFSET_BON = 50 // How much extra height the text gains
constant real VELOCITY = 2 // How fast the text move in x/y plane
timer TMR = getTimer()
public class ArcingTextTag
use LinkedListModule
private texttag tt
private real as // angle, sin component
private real ac // angle, cos component
private real ah // arc height
private real t // time
private vec3 pos
private string s // text
private function update()
real p
p = Sin(bj_PI * t)
t = t - 0.03125
pos.x = pos.x + ac
pos.y = pos.y + as
pos.z = Z_OFFSET + Z_OFFSET_BON * p
tt.setPos(pos)
tt.setText(s, (SIZE_MIN + SIZE_BONUS * p) * 434.78)
if t <= 0
destroy this
if this.next == null
TMR.pause()
private static function onLoop()
thistype current = ArcingTextTag.first
while(current != null)
current.update()
current = current.next
construct(string msg, unit u)
real a = GetRandomReal(0, 2*bj_PI)
s = msg
pos.x = GetUnitX(u)
pos.y = GetUnitY(u)
t = TIME_LIFE
as = Sin(a) * VELOCITY
ac = Cos(a) * VELOCITY
ah = 0.
if IsUnitVisible(u, GetLocalPlayer())
tt = CreateTextTag()
..setPermanent(false)
..setLifespan(TIME_LIFE)
..setFadepoint(TIME_FADE)
..setText(s, SIZE_MIN)
..setPos(pos)
if ArcingTextTag.first == this
TMR.startPeriodic(0.03125, function ArcingTextTag.onLoop)
package demo
import ObjectIdGenerator
import ChannelAbilityPreset
import UnitObjEditing
import ObjectIds
import Crafting
import ArcingLoot
import ArcingText
string onCraftEffect = "Abilities\\Spells\\Other\\Transmute\\GoldBottleMissile.mdl"
integer testUnit = compiletime(UNIT_ID_GEN.next())
@compiletime function generate()
new UnitDefinition(testUnit, 'hkni')
..setName("Witch's Cauldron")
..setModelFile("Doodads\\LordaeronSummer\\Props\\CauldronWithHeads\\CauldronWithHeads.mdl")
..setHitPointsMaximumBase(1)
..setMovementType(MovementType.None)
..setSpeedBase(0)
..setNormalAbilities("AInv,Avul")
..setArmorType(ArmorType.Unarmored)
..setDefenseBase(0)
..setAttack1DamageBase(0)
..setAttack1DamageNumberofDice(0)
..setAttack1DamageSidesperDie(0)
..setAttack1AttackType(AttackType.Unknown)
..setUnitSoundSet("")
..setScalingValue(1.5)
..setSightRadiusDay(0)
..setSightRadiusNight(0)
unit cauldron
constant string yellow = "|c00FFFF00"
constant string blue = "|c007EBFF1"
init
// Create recipe and add components
new ItemRecipe('shar')
..addComponent('whwd', 2)
..addComponent('pghe', 1)
..addComponent('phlt', 1)
// Crafting Demo
cauldron = createUnit(players[0], testUnit, vec2(0, 0), angle(0))
createUnit(players[0], 'Hpal', vec2(0, 0), angle(0))
// try to craft on esc press
CreateTrigger()
..registerPlayerEvent(players[0], EVENT_PLAYER_END_CINEMATIC)
..addAction() ->
new ArcingTextTag("|c007EBFF1" + GetUnitName(cauldron) + "|r is Crafting", cauldron)
while(cauldron.canCraft())
addEffect(onCraftEffect, cauldron.getPos()).destr()
let recipes = cauldron.craft()
for r in recipes
let id = r.craftable
cauldron.removeRecipeCompnents(r)
new ArcingItem(id, cauldron.getPos(), cauldron.getPos().polarOffset(angle(GetRandomDirectionDeg()), GetRandomReal(200, 400)))
break
print("No more items can be crafted")
CreateTrigger()
..registerAnyUnitEvent(EVENT_PLAYER_UNIT_PICKUP_ITEM)
..addAction() ->
if(GetManipulatingUnit() == cauldron)
item i = GetManipulatedItem()
new ArcingTextTag(blue + "Added: " + yellow + i.getName(), cauldron)