ID:1895014
 
Hey so I am trying to make this Portal, but I am trying to make it appear 1 tile away from the direction you are facing. How do I do that? Would i need to put it in the actual verb? Also When flick("portalclose",src) happens the animation of the portal closes but then right after it an animation of the portal appears for a split second. Lastly, may I have a hint to where I put the code to have where you step inside of it then it teleports you somewhere?

Code:
obj/Portal
icon = 'Witch.dmi'
density = 1
New()
flick("PortalOpening",src)
icon_state = "Open"
sleep 40
flick("PortalClose",src)
spawn(10)
loc = null


Problem description:

Dayvon64 wrote:
Hey so I am trying to make this Portal, but I am trying to make it appear 1 tile away from the direction you are facing. How do I do that? Would i need to put it in the actual verb?

To create something directly in front of you, you'd want to use get_step() to get a reference to the turf in front of your mob, then spawn the portal on that turf.

Dayvon64 wrote:
Also When flick("portalclose",src) happens the animation of the portal closes but then right after it an animation of the portal appears for a split second.

The reason behind this is that flick() only temporarily changes a state, then immediately sets it back to the state it had before. So after the closing animation, it would return to the "open" state.

As an aside, you're using spawn() incorrectly. loc = null needs to be "under" the spawn block, meaning you need to indent it over one more level. Otherwise spawn() does nothing.

Dayvon64 wrote:
Lastly, may I have a hint to where I put the code to have where you step inside of it then it teleports you somewhere?

Because the portal is an object, you need to look into Crossed() in order to "step inside of it." Handling where it sends you exactly can be simple or it could be complex, depending on whether or not the portal always sends you to the same place, or if you can select where it should send you.
proc
get_step_dist(atom/ref,dist=1,dir=0,clamp=0)
if(!dir) dir = ref.dir
if(dist==1)
return get_step(ref,dir)
else if(ref.loc)
var/x
var/y
if(dir&NORTH) y++
if(dir&SOUTH) y--
if(dir&EAST) x++
if(dir&WEST) x--
x = x*dist + ref.x
y = y*dist + ref.y
if(clamp)
x = max(min(x,world.maxx),1)
y = max(min(x,world.maxy),1)
return locate(x,y,ref.z)
else
return null


This simple function will allow you to get a turf X tiles in any direction from the mob. The clamp option prevents the distance from being off the edge of the map.

You don't have to supply dir. It will automatically pick the direction of the atom supplied if you don't specify it.
I just wanted the portal to take me to an exact point by use something like locate(x,y,z) and how exactly do I implement get_step() w
In response to Dayvon64
get_step() is a built-in procedure. The reference explains how to use it.

As for the portal thing, I'd recommend using a tag instead of the rigid locate(x, y, z) form. It becomes as simple as setting the tag variable for the turf that you want to be the exit of the portal, then sending whoever enters the portal to the location of locate(your_tag_here).
So I would use usr.Move(locate(x,y,z)) ??
Things wrong from top-to-bottom:
obj/Portal
icon = 'Witch.dmi'
density = 1 //<-- Do you really want it dense? They're going to be entering it. It's been a while since I've used Enter(). But I'd rather have it not dense
New()
flick("PortalOpening",src)
icon_state = "Open"
sleep 40 //<-- wrap in parenthesis. It's annoying me
flick("PortalClose",src)
spawn(10)
loc = null //<-- indent under spawn


After talking one-on-one for a few minutes, this was the end result:
obj/Portal
icon = 'Witch.dmi'
icon_state = "Open"
density = 1
New()
spawn()
icon_state = "Open"
flick("PortalOpening",src)
sleep(30)
icon_state = "Blank"
flick("PortalClose",src)
spawn(10)
del(src)
..()


As for spawning it in front of you:
mob/verb/SpawnPortal()
var/xOffset = 0
var/yOffset = 0
switch(src.dir)
if(NORTH)
yOffset = 1
if(EAST)
xOffset = 1
if(SOUTH)
yOffset = -1
if(WEST)
xOffset = -1
if(NORTHWEST)
xOffset = -1
yOffset = 1
if(SOUTHWEST)
xOffset = -1
yOffset = -1
if(NORTHEAST)
xOffset = 1
yOffset = 1
if(SOUTHEAST)
xOffset = 1
yOffset = -1

var/obj/o = new/obj/Portal
o.loc = locate(src.x + xOffset, src.y + yOffset, src.z)


Just posting this for anyone who comes across it.
mob/verb/SpawnPortal()
var/xOffset = 0
var/yOffset = 0
switch(src.client.dir)
if("NORTH")
yOffset = 1
if("EAST")
xOffset = 1
if("SOUTH")
yOffset = -1
if("EAST")
xOffset = -1
if("NORTHWEST")
xOffset = -1
yOffset = 1
if("SOUTHWEST")
xOffset = -1
yOffset = -1
if("NORTHEAST")
xOffset = 1
yOffset = 1
if("SOUTHEAST")
xOffset = 1
yOffset = -1

var/obj/o = new/obj/Portal
o.loc = locate(src.x + xOffset, src.y + yOffset, src.z)


Why not this:
new/obj/Portal(get_step(src,src.dir))


Second, client.dir is not the same thing as mob.dir.

Next, don't manually delete objects:

del(src)


Instead send them to null and make sure to clean any references:

src.loc = null


They will automatically clean themselves up if they are unused.
In response to Ter13
Already cleaned it up, Ter.

As for src.loc = null, didn't we have a talk that del() will still send it to the garbage collector? It just prevents a buildup of objects at location null. If not, then by all means, he can change it back.

Also, the get_step() approach is better because you can determine if they're facing a dense object and deny them the ability to spawn the portal. I knew someone would mention it as well. I just wanted to see who would be the first to do so.

obj/Portal
icon = 'Witch.dmi'
icon_state = "Open"
density = 1
New(var/newLoc)
loc = newLoc
spawn()
icon_state = "Open"
flick("PortalOpening",src)
sleep(30)
icon_state = "Blank"
flick("PortalClose",src)
spawn(10)
src.loc = null
..()

mob/verb/Portal()
new/obj/Portal(get_step(src,src.dir))


There. Not even sure if this is the correct way of doing it anyways since I didn't throw it in DM. But, testing, debugging, etc shouldn't be hard after you have the general concept.

*disappears*
As for src.loc = null, didn't we have a talk that del() will still send it to the garbage collector? It just prevents a buildup of objects at location null. If not, then by all means, he can change it back.

BYOND has automatic garbage collection if the refcount of an object reaches zero. If you have been managing your references correctly, you should never have to manually delete an object.

Manually calling delete on an object in the best case scenario costs you TONS of cpu usage while the engine searches every variable of every object and every position of every list in memory. In the worst case scenario, it not only does all of that, but prevents you from addressing bad design habits.

Further, manually deleting objects leaves null references in lists, rather than removing the item from the list. This can cause errors later on in code by making list sizes inaccurate.

See this thread to demonstrate the horrors of manual garbage collection vs automatic collection through reference freeing:

http://www.byond.com/forum/?post=1549601#comment9708540
To be fair, the very best-case scenario with del() is that if there are any other references, they're found quickly. The garbage collector will bail out in the event that the last reference is removed. If an object's only reference is its loc, then del() is mostly harmless because the act of moving it to a null location is enough to take care of it. But it's not good design to rely on that and hope for the best.
But it's not good design to rely on that and hope for the best.

Managing references is something that really should be better understood. Almost all BYOND games leak like a seive because of failure to manage references.

This is why I use C-style destructors in almost everything I work on, because by using circular references I can actually manually ensure that all references are cleaned after I send the object to null.

I've done stress testing of the garbage collector in best and worst case scenarios, and the worst case scenario resulted in over 40 minutes to clean up a million objects with just a handful of references each, while manually tracking and clearing references took 4.6 seconds for a million objects.