ID:1664982
 
(See the best response by LordAndrew.)
Code:
turf
icon = 'turfs.dmi'
cave
cave_floor
cave_floor_1
icon_state = "cave floor 1"
cave_floor_1_button //opens the secret door in the cave
icon_state = "cave floor 1 button"
Entered(mob/hero/M)
M << "*click!* You hear a rolling in the distance..."
var/turf/cave/cave_floor/secret_door/D
for(D in world)
D.icon_state = "cave floor 1"
D.density = 0
secret_door
icon_state = "cave wall"
density = 1


Problem description:
I have two questions:

1) Is using a for loop to find the secret door a bad idea? Certainly there must be better ways. If anyone has any suggestions I'd like to hear them.

2) I'm still quite new to DM, so I don't quite understand how everything works yet.
Particularly, I am often thrown off by what arguments to pass into procedures.

In the Entered() proc, for example, what I think I am doing (and what I want to do) is make it so the procedure only executes (correct terminology?) when the hero (the player's character) steps on the button. However, when ANY mob (like a wandering monster) steps on it, the procedure is called.

How do I pass in arguments to Entered() so that only the player(/mob/hero) can open the secret door?

And another question...

code
mob/hero/verb
fireball(mob/monster/M in oview())
usr << "You hurl a massive fireball at [M]!"
missile(/obj/magic/fireball, usr, M)

obj/magic
density = 1
icon = 'magic.dmi
Bump(atom/O)
if(ismob(O))
Damage()


problem description

As it is now, when I use missile() and shoot a fireball at a target, the target is damaged immediately (before the missile actually hits it). I want to use Bump() so that damage calculation doesn't take place until the missile reaches its target. The code which I provided, never actually calls Bump().

Also, I don't know if it's okay to ask multiple questions in one post, or not. I don't have regular access to the internet, so I try to save up my questions and post them when I can. Also, I didn't want to clutter up the board with multiple posts. Please let me know which method is the most appropriate.

Thank you
Best response
1. Generally, you don't want to loop through everything in the world unless you have to. If only one instance of /turf/cave/cave_floor/secret_door exists on the map, then you're better off using locate() in order to find it.

mob/verb/FindSecretDoor()
set name = "Find Secret Door"
var turf/cave/cave_floor/secret_door/t = locate() in world

if (t)
world << "Found it!"

else
world << "Ain't found it."

2. Entered() accepts something of type /atom/movable as its first argument (AKA either a /mob or /obj), so even if you typecast the argument you still need to typecheck what's being passed in. You can very easily do:

turf/dungeon/Entered(mob/hero/M)
// Shorthand use of istype(). Checks if M is the same type that it was typecasted as.
if (istype(M))
world << "The hero [M] enters the dungeon!"

else
world << "Boo, [M] can't enter the dungeon."

3. missile() is a purely visual effect that doesn't actually create a new object or use the movement stack. If you want Bump() to be called, then you're going to have to create an instance of /obj/magic/fireball and send it at the target using something from the step_*() or walk_*() families of procedures.
LordAndrew beat me to it, but he pretty much explained how to solve each of your issues.

I wanted to tackle the first question regardless because on the off chance that you end up adding content and having more buttons or levers that open/shut pathways ( such as a door ), you'll have a lot of duplicated code. Duplicated code, especially when it's something you'll have to keep copy/pasting for content updates, will eventually become time consuming for something so basic.

Takai Desu wrote:
1) Is using a for loop to find the secret door a bad idea? Certainly there must be better ways. If anyone has any suggestions I'd like to hear them.

I'd honestly make use of the map editor for what you want. Let's just use your code for our example. On that note, I wouldn't use /turf for what you want, but let's go ahead and use your code anyway.

turf
cave_floor_button
var/tag_search = "" // We will want to edit this per New Instance
Entered(atom/movable/a) // Called when a movable atom enters /turf/button
if(ismob(a)) // if it's a mob
var/turf/secret_door/d = locate(tag_search) // we'll use locate(Tag), in this case Tag is our var tag_search
if(d)
world << "Found!"
else
world << "Cannot Find!"


In the map editor, you'll want to create a New Instance of /turf/cave_floor_button. Set it's var tag_search to a string -- in this example we'll go with "SecretDoor1" -- and place it on the map.

Now you'll want to create a New Instance of /turf/secret_door. Set it's var tag to match the tag_search var of the /turf/cave_floor_button you wish to activate it. Place it on the map as well.

Now when you want to add more hidden doors that are activated from buttons, you just make a New Instance and edit the vars accordingly.

For more information on the map editor and instancing, you should read Learning to love the map editor.
Thank you guys for the great information. I'll work on it a bit more and try and update on my progress tomorrow.

*EDIT*

Hello again,

You'll have to forgive me Lige, but I can't seem to get the code you provide to work.

Using...

turf
cave_floor_button
var/tag_search = ""
Entered(atom/movable/a)
if(ismob(a))
var/turf/secret_door/d = locate(tag_search)
if(d)
world << "Found"
else
world << "Not found


Gives me an error and a warning...

"error: d: undefined type: d
warning: d: variable defined but not used"