# Help with Water Slide Effect

Discussion in 'World Editor Help Zone' started by (Battleships) Speed, Mar 27, 2020 at 12:32 AM.

1. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
Hello all. I found the slide effect I am looking for that came from the map on ice terrain which I just uploaded file to this forum. I need help to build a trigger for a ship to be sailing on water to work like sliding effect. I want the sliding effects to be like those GIF videos I just uploaded to this forum. How do I do this? Please help me. Thank you!

#### Attached Files:

• ###### Banjoball v1.21D PROT.w3x
File size:
8.7 MB
Views:
2
Last edited: Mar 27, 2020 at 4:25 AM

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3
With a bit of trigger knowhow you can extract the triggers from the map itself. However below is a brief explanation as to how it is done if one wants to recreate the system from scratch.

The key mechanic behind it is the use of SetUnitX and SetUnitY functions. These functions change a unit's position without interrupting their current order or movement (a problem with the GUI move unit actions).

One creates a physics system of sorts using these functions. For example you have an X velocity and Y velocity which gets applied to offset the unit's position every tick. This accelerates towards the a target point until its magnitude is some maximum. The target point could be the point the unit is ordered to.

For this to be MUI one would keep the values in a set of arrays where each index represents a single unit. All indices could be iterated through and updated 30 times a second or so for smooth movement.

One could also add a friction factor based on the current velocity. This means no maximum is needed since as the unit's speed increases so will the deceleration from friction until a natural limit is reached.

One can set the unit to have a very low movement speed so the system is almost entirely responsible for movement. Alternatively you could track unit position independently and cancel out the native unit movement, possibly using the lost displacement to calculate an acceleration vector.

There are a lot of ways this could be implemented. On will have to experiment to find the one that best suits your needs.

Last edited: Mar 27, 2020 at 3:39 PM
4. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
Okay. I was just trying to ask you if you know how to make this trigger out of GUI. I just found the GUI for the slide effects, but I don't know how to get it connected into my map to be working on hero ships only. I really like how the slide effects created on this ice terrain, but all you showed me is a sentences, and I am not good at WC3 english. But, I still prefers to make trigger than GUI. Do you know anybody who can make trigger the way I wanted it to be?

Last edited: Mar 27, 2020 at 3:57 PM

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3
The trigger can still be made using GUI. Outside of usual leak clean-up, one needs to use the following lines of custom script to move the units.

JASS
Code (vJASS):

call SetUnitX(udg_TempUnit, udg_TempRealX)
call SetUnitY(udg_TempUnit, udg_TempRealY)

Lua
Code (Text):

SetUnitX(udg_TempUnit, udg_TempRealX)
SetUnitY(udg_TempUnit, udg_TempRealY)

TempUnit is a unit variable
TempRealX is a real variable
TempRealY is a real variable

Set the variables before calling the functions.

I think some slide systems exist in the Spells resource section. One might be able to copy these into your map.

6. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
What about the condition? I want change the condition that is only works on ice terrain in this map, but I want change this condition to be only on hero ships, you know? All of this GUI is great, but I just need to figure out how to get it into my map and change the condition to be on hero ships only.

I think this is the slide GUI.
Code (vJASS):

library Objects requires UnitZ, InstanceIterator, Vector, Boundary, UnitCollision, ObjectInit, LinkedList

struct Object //Treated as cylinders
static thistype dis
real height
real mass
Vector velocity
real lastX
real lastY
real lastZ

real movementX
real movementY
boolean moving

/*static method EnumObjectsInRange takes real x, real y, real radius, code c returns nothing

endmethod*/

implement ObjectList

static method createFilter takes unit u returns boolean
return IsUnitType(u, UNIT_TYPE_OBJECT)
endmethod

method onCreate takes nothing returns nothing
set height = GetUnitHeight(me)
set mass = GetUnitMass(me)
set velocity = Vector.create(0.00, 0.00, 0.00)
endmethod

method onDestroy takes nothing returns nothing
call stop32()
call velocity.destroy()
call listRemove()
endmethod

implement AutoCreate
implement AutoDestroy

static method collision takes nothing returns boolean
local thistype this = dis
local thistype that
local unit f = GetFilterUnit()
local Vector d
local Vector v1
local Vector v2
local Vector v3
local Vector v4
local real l1
local real l2
if f != .me and IsUnitType(f, UNIT_TYPE_OBJECT) and RAbsBJ(GetUnitZ(.me) - GetUnitZ(f)) <= 100.0 then
set d = Vector.create(GetUnitX(f) - GetUnitX(.me), GetUnitY(f) - GetUnitY(.me), GetUnitZ(f) - GetUnitZ(.me))
set that = thistype[f]
if Vector.dotProduct(this.velocity, that.velocity) <= 0.00 then
if Vector.dotProduct(this.velocity, d) <= 0.00 then
set f = null
call d.destroy()
return false
endif
else
if Vector.dotProduct(this.velocity, d) <= 0.00 then
set l1 = this.velocity.getLength()
set l2 = that.velocity.getLength()
else
set l1 = that.velocity.getLength()
set l2 = this.velocity.getLength()
endif
if l1 >= l2 then
set f = null
call d.destroy()
return false
endif
endif
set v1 = Vector.projectionVector(that.velocity, d)
set v2 = Vector.projectionVector(this.velocity, d)
if RAbsBJ(v2.getLength() - sgn(Vector.dotProduct(v1, v2))*v1.getLength()) > PLAYER_BUMP_SFX_THRESHOLD then
call d.setLength(d.getLength()/2)
call Sfx(PLAYER_BUMP_SFX_PATH, GetUnitX(.me) + d.x, GetUnitY(.me) + d.y, GetUnitZ(.me), Atan2(d.y, d.x)*bj_RADTODEG + 180.0, 0.00, 0.7)
endif
set l1 = d.x
set d.x = -d.y
set d.y = l1
set v3 = Vector.projectionVector(this.velocity, d)
set v4 = Vector.projectionVector(that.velocity, d)

call this.velocity.destroy()
call that.velocity.destroy()
set this.velocity = v1
call this.applyVector(v3)
set that.velocity = v2
call that.applyVector(v4)

call d.destroy()
call v3.destroy()
call v4.destroy()
set f = null
endif
return false
endmethod

method iterate32 takes nothing returns nothing
local real z
local Vector v

if ((selection == 3 or selection == 4) and .moving and IsUnitType(.me, UNIT_TYPE_PLAYER)) then
if (.velocity.getLength() < PLAYER_MAX_SLIDE_SPEED) then
set v = Vector.create(PLAYER_SLIDE_SPEED_ICE * Cos(GetUnitFacing(.me) * bj_DEGTORAD), PLAYER_SLIDE_SPEED_ICE * Sin(GetUnitFacing(.me) * bj_DEGTORAD), 0.00)
call .applyVector(v)
call v.destroy()
call GroupEnumUnitsInRange(enumGroup, .movementX, .movementY, POSITION_RADIUS, Filter(function thistype.checkEnd))
endif
endif
if GetUnitFlyHeight(me) < 1.00 then
call EnableUnitCollision(me)
if velocity.getLength() > PLAYER_FRICTION_GROUND then
call .velocity.setLength(.velocity.getLength() - PLAYER_FRICTION_GROUND)
else
call SetUnitFlyHeight(.me, 0.00, 0.00)
call .velocity.setLength(0.00)
call .stop32()
return
endif
else
set .velocity.z = .velocity.z - GRAVITY_ACCELERATION
if .velocity.getLength() > PLAYER_FRICTION_AIR then
call .velocity.setLength(.velocity.getLength() - PLAYER_FRICTION_AIR)
else
call .velocity.setLength(0.00)
endif
endif
endif
if RectContainsCoords(bj_mapInitialPlayableArea , GetUnitX(.me) + .velocity.x, GetUnitY(.me) + .velocity.y) then
if GetUnitFlyHeight(.me) < 1.00 then
call SetUnitX(.me, GetUnitX(.me) + .velocity.x)
call SetUnitY(.me, GetUnitY(.me) + .velocity.y)
else
call SetUnitX(.me, .lastX + .velocity.x)
call SetUnitY(.me, .lastY + .velocity.y)
endif
endif
if (not IsPointInRegion(playable, GetUnitX(.me), GetUnitY(.me))) or (not IsTerrainWalkable(GetUnitX(.me), GetUnitY(.me))) then
call SetUnitPosition(.me, GetUnitX(.me), GetUnitY(.me))
endif
set .lastX = GetUnitX(.me)
set .lastY = GetUnitY(.me)
set z = GetUnitZ(.me) + .velocity.z
if z < GetTerrainZ(GetUnitX(.me), GetUnitY(.me)) and .velocity.z < 0.00 then
call SetUnitFlyHeight(.me, 0.00, 0.00)
if IsUnitType(me, UNIT_TYPE_PLAYER) and .velocity.z < -PLAYER_BUMP_SFX_THRESHOLD then
call Sfx(PLAYER_BUMP_SFX_PATH, GetUnitX(.me), GetUnitY(.me), 0.00, 0.00, 90, 0.7)
endif
set .velocity.z = -.velocity.z
set .velocity.z = .velocity.z - PLAYER_BUMP_SPEED_LOSS
if .velocity.z < 0.00 then
set .velocity.z = 0.00
endif
endif
else
call SetUnitZ(.me, z)
if radius > 0.00 and z >= 1.00 then
call DisableUnitCollision(me)
endif
endif
if .velocity.getLength() != 0.00 and radius > 0.00 then
set .dis = this
call GroupEnumUnitsInRange(enumGroup, GetUnitX(.me), GetUnitY(.me), 80.0, Filter(function thistype.collision))
endif
endmethod

implement II32

method setX takes real x returns nothing
call SetUnitX(me, x)
set lastX = x
endmethod

method setY takes real y returns nothing
call SetUnitY(me, y)
set lastY = y
endmethod

method setZ takes real z returns nothing
call SetUnitZ(me, z)
set lastZ = z
endmethod

method applyVector takes Vector v returns nothing
local real loss = 0.00
if IsUnitType(me, UNIT_TYPE_PLAYER) then
set loss = PLAYER_BUMP_SPEED_LOSS
endif
call BoundaryCheck(me, velocity, loss)
if start32() then
set lastX = GetUnitX(me)
set lastY = GetUnitY(me)
set lastZ = GetUnitZ(me)
endif
endmethod

method setVector takes Vector v returns nothing
set velocity.x = v.x
set velocity.y = v.y
set velocity.z = v.z
endmethod

method getVector takes nothing returns Vector
return velocity
endmethod

/*method exertForce takes Vector f returns nothing
local real l = f.getLength()
call f.setLength(f.getLength()/mass)
call applyVector(f)
call f.setLength(l)
endmethod*/

private static method checkEnd takes nothing returns boolean
local unit f = GetFilterUnit()
local real x = GetUnitX(f)
local real y = GetUnitY(f)

if (IsUnitType(f, UNIT_TYPE_PLAYER)) then
set x = Pow(thistype[f].movementX - x, 2)
set y = Pow(thistype[f].movementY - y, 2)
if (SquareRoot(x + y) <= POSITION_RADIUS) then
set thistype[f].moving = false
endif
endif
set f = null
return false
endmethod

static method isMoving takes nothing returns nothing
local unit u = GetTriggerUnit()
local string s = OrderId2String(GetIssuedOrderId())
local Ball ball = Ball.balls[0]

if IsUnitType(u, UNIT_TYPE_PLAYER) and unitActive[GetPlayerId(GetOwningPlayer(u))] then
if s == "smart" then
set thistype[u].moving = true
set thistype[u].movementX = GetOrderPointX()
set thistype[u].movementY = GetOrderPointY()
call thistype[u].start32()
else
set thistype[u].moving = false
endif
endif
set u = null
endmethod

static method onInit takes nothing returns nothing
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER, function thistype.isMoving)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, function thistype.isMoving)
call RegisterPlayerUnitEvent(EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, function thistype.isMoving)
endmethod
endstruct

endlibrary

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3
What GUI trigger are you trying to copy? I do not see any in the map provided. The provided map seems to only have vJASS triggers.

EDIT: That trigger is a vJASS library. It is not GUI.

You will need to import all its dependent libraries for it to work.

That trigger may be desync prone since it involves Z of sorts.

8. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
Oh. I mean, JASS. The GIF videos is from this map. I don't know which JASS that makes that slide effects I wanted. That's why I need somebody who know how to make trigger this way without JASS. Okay. I just need someone who knows how to make this slide effect. Maybe I am in wrong forum...

Last edited: Mar 27, 2020 at 4:27 PM

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3
You will need to explain the physics you want with the slide system. There are dozens of ways this could be implemented. For example, should it factor in unit movement speed or not?

10. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
This is why I am showing in the GIF videos. Also, for speed increases, I want it to have maximum speed conditions equal to hero ship's speed sail level, like if the speed sail level on the hero ship is level 4 and that would be 440, and the max speed is 522, then I want the speed increases goes up to 440, for until the max speed sail changes to 490 or 522, and then it goes up to 490, then go up to 522, you know? Also, I want turning the ship to be like this in the GIF videos, and when the ship stops, I want it to be like that in the GIF videos to stop the ship just like in real life. I don't know how to explain out of those GIF videos I made. But, that's what I wanted.

11. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
I found other map called "Drive" that almost works like the way I wanted slide effects to be that shown in those GIF videos above. But, I want it to be works like in those GIF videos with controlling from mouse, not keyboard, you know. Here the map file I uploaded and also all the triggers out of this map are shown below.

• Ini
• Events
• Map initialization
• Conditions
• Actions
• Game - Display to (All players) for 0.00 seconds the text: Press 'Esc' to chan...
• Visibility - Disable fog of war
• Visibility - Disable black mask
• Set VariableSet zLoc = (Point(0.00, 0.00))
• Item - Create Cheese at zLoc
• Set VariableSet pitem = (Last created item)
• Set VariableSet minX = (Min X of (Playable map area))
• Set VariableSet maxX = (Max X of (Playable map area))
• Set VariableSet minY = (Min Y of (Playable map area))
• Set VariableSet maxY = (Max Y of (Playable map area))
• For each (Integer i) from 1 to 12, do (Actions)
• Loop - Actions
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• ((Player(i)) slot status) Equal to Is playing
• Then - Actions
• -------- Speed will be increased by this value per timestep --------
• Set VariableSet acceleration[i] = 0.50
• -------- A small ammount of speed will be lost every timestep --------
• Set VariableSet friction[i] = (985.00 / 1000.00)
• -------- Turn 5 degrees per timestep --------
• Set VariableSet turnRate[i] = 1.00
• Unit - Create 1 Siege Engine for (Player(i)) at zLoc facing (Random angle) degrees
• Set VariableSet driver[i] = (Last created unit)
• Set VariableSet angle[i] = (Facing of driver[i])
• Set VariableSet forwards[i] = False
• Set VariableSet backwards[i] = False
• Set VariableSet left[i] = False
• Set VariableSet right[i] = False
• Set VariableSet camMode[i] = 1
• Camera - Lock camera target for (Player(i)) to driver[i], offset by (0.00, 0.00) using The unit's rotation
• Trigger - Add to ForwardsPress <gen> the event (Player - (Player(i)) Presses the Up Arrow key)
• Trigger - Add to BackwardsPress <gen> the event (Player - (Player(i)) Presses the Down Arrow key)
• Trigger - Add to LeftPress <gen> the event (Player - (Player(i)) Presses the Left Arrow key)
• Trigger - Add to RightPress <gen> the event (Player - (Player(i)) Presses the Right Arrow key)
• Trigger - Add to ForwardsRelease <gen> the event (Player - (Player(i)) Releases the Up Arrow key)
• Trigger - Add to BackwardsRelease <gen> the event (Player - (Player(i)) Releases the Down Arrow key)
• Trigger - Add to LeftRelease <gen> the event (Player - (Player(i)) Releases the Left Arrow key)
• Trigger - Add to RightRelease <gen> the event (Player - (Player(i)) Releases the Right Arrow key)
• Trigger - Add to ChangeCam <gen> the event (Player - (Player(i)) skips a cinematic sequence)
• Else - Actions

• Loop
• Events
• Time - Every 0.03 seconds of game time
• Conditions
• Actions
• For each (Integer i) from 1 to 12, do (Actions)
• Loop - Actions
• Set VariableSet u = driver[i]
• Unit - Make u face angle[i] over 0.00 seconds
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• forwards[i] Equal to True
• Then - Actions
• Set VariableSet speedX[i] = (speedX[i] + (acceleration[i] x (Cos(angle[i]))))
• Set VariableSet speedY[i] = (speedY[i] + (acceleration[i] x (Sin(angle[i]))))
• Else - Actions
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• backwards[i] Equal to True
• Then - Actions
• Set VariableSet speedX[i] = (speedX[i] - (acceleration[i] x (Cos(angle[i]))))
• Set VariableSet speedY[i] = (speedY[i] - (acceleration[i] x (Sin(angle[i]))))
• Else - Actions
• If (left[i] Equal to True) then do (Set VariableSet angle[i] = (angle[i] + turnRate[i])) else do (-------- Do Nothing --------)
• If (right[i] Equal to True) then do (Set VariableSet angle[i] = (angle[i] - turnRate[i])) else do (-------- Do Nothing --------)
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• camMode[i] Equal to 0
• Then - Actions
• Camera - Set (Player(i))'s camera Rotation to angle[i] over 0.00 seconds
• Else - Actions
• Custom script: set udg_x = GetUnitX(udg_u)
• Custom script: set udg_y = GetUnitY(udg_u)
• Set VariableSet speedX[i] = (speedX[i] x friction[i])
• Set VariableSet speedY[i] = (speedY[i] x friction[i])
• Set VariableSet x = (x + speedX[i])
• Set VariableSet y = (y + speedY[i])
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• x Less than maxX
• x Greater than minX
• y Less than maxY
• y Greater than minY
• Then - Actions
• Custom script: call SetItemPosition(udg_pitem, udg_x, udg_y)
• Custom script: call SetItemVisible(udg_pitem, false)
• Custom script: if RAbsBJ(udg_x - GetWidgetX(udg_pitem) + udg_y - GetWidgetY(udg_pitem)) <= 10.0 then
• Custom script: call SetUnitX(udg_u, udg_x)
• Custom script: call SetUnitY(udg_u, udg_y)
• Custom script: else
• Set VariableSet speedX[i] = 0.00
• Set VariableSet speedY[i] = 0.00
• Custom script: endif
• Else - Actions
• Set VariableSet speedX[i] = 0.00
• Set VariableSet speedY[i] = 0.00

• ChangeCam
• Events
• Conditions
• Actions
• Set VariableSet i = (Player number of (Triggering player))
• Set VariableSet camMode[i] = ((camMode[i] + 1) mod 3)
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• camMode[i] Equal to 0
• Then - Actions
• Camera - Lock camera target for (Player(i)) to driver[i], offset by (0.00, 0.00) using The unit's rotation
• Camera - Set (Player(i))'s camera Angle of attack to 350.00 over 0.00 seconds
• Camera - Set (Player(i))'s camera Distance to target to 330.00 over 0.00 seconds
• Camera - Set (Player(i))'s camera Height Offset to 100.00 over 0.00 seconds
• Else - Actions
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• camMode[i] Equal to 1
• Then - Actions
• Camera - Reset camera for (Triggering player) to standard game-view over 0.00 seconds
• Camera - Lock camera target for (Player(i)) to driver[i], offset by (0.00, 0.00) using The unit's rotation
• Else - Actions
• If (All Conditions are True) then do (Then Actions) else do (Else Actions)
• If - Conditions
• camMode[i] Equal to 2
• Then - Actions
• Camera - Reset camera for (Triggering player) to standard game-view over 0.00 seconds
• Else - Actions
• Custom script: call DisplayTimedTextToPlayer(GetTriggerPlayer(), 0, 0, 60, "Cam mode: " + I2S(udg_camMode[udg_i]))

ForwardsPress
Events
Conditions
Actions
Set VariableSet forwards[(Player number of (Triggering player))] = True
[/trigger]

• ForwardsRelease
• Events
• Conditions
• Actions
• Set VariableSet forwards[(Player number of (Triggering player))] = False

• BackwardsPress
• Events
• Conditions
• Actions
• Set VariableSet backwards[(Player number of (Triggering player))] = True

• BackwardsRelease
• Events
• Conditions
• Actions
• Set VariableSet backwards[(Player number of (Triggering player))] = False

• LeftPress
• Events
• Conditions
• Actions
• Set VariableSet left[(Player number of (Triggering player))] = True

• LeftRelease
• Events
• Conditions
• Actions
• Set VariableSet left[(Player number of (Triggering player))] = False

• RightPress
• Events
• Conditions
• Actions
• Set VariableSet right[(Player number of (Triggering player))] = True

• RightRelease
• Events
• Conditions
• Actions
• Set VariableSet right[(Player number of (Triggering player))] = False

File size:
31.4 KB
Views:
0
12. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
@Dr Super Good
I found the perfect map I am looking for that match the water slide effect I needed! Here the link of the map I just found: RigidBody Physics v1.3. But, just two problems are... I want the speed to be increasing slow up to the maximum speed of ship's max speed, you know? And, I want the slide effect system to be work with the water terrain, not the ice texture.

And, also for this slide trigger, I want it to be with the speed maximum to be broken from the speed trigger called "MoveSpeedX." Speed limit broken like this.

Last edited: Mar 27, 2020 at 8:23 PM

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3

If it is faster than maximum movement speed how is it meant to know what the maximum movement speed should be? Or do you want it to have a maximum of some multiple of the base movement speed? Or is it an ability with some table of maximum speed values?

Last edited: Mar 28, 2020 at 1:31 AM
14. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
The ship will have 6 levels of speed engine.

### Spell Reviewer

Joined:
Jan 18, 2005
Messages:
25,926
Resources:
3
Maps:
1
Spells:
2
Resources:
3
Which does what? In your previous description of the ability you did not make it clear that the ability enables the slide or not, or that it exceeds the normal speed limit or not. Does the ability allow ships to slide, or does it just improve how they slide?

Currently if I was to try and code something for you chances are it will not be what you want because I am not too sure what you want.

16. ### (Battleships) Speed

Joined:
Jun 26, 2019
Messages:
194
Resources:
0
Resources:
0
All good! I figured it out! I was frustrated, but now I am relieved. I got all fixed now. Here the link below that I had it all worked out so far with Stry.

Help with Editing Abyss tile

Last edited: Mar 28, 2020 at 6:34 AM