In response to Metamorphman
Metamorphman wrote:
I think the issue is client.mob is typecast as /mob, therefore /mob/Player values aren't going to be there. So just re-typecast:

> client/proc/test()
> var/mob/Player/m = mob
> // Do everything with m instead of mob
>

Or use the : operator instead and istype() to be safe.

I don't think you should tell him to use the : just because it's used a ton by beginner programmers.

THIS IS A BAD PRACTICE, FYI.
Because then you're completely ignoring the safe-guards in place, and can run into some really weird errors and have a hard time debugging your code down the road when it doesn't work the way you expect it to.
Um, there's nothing wrong with : if you know what you're doing. Calm down. That's why I said use istype() as well.
Of course there is, it's essentially a shortcut which gets abused way too much.

What happens if you move that variable into another mob's type? You get no warnings or errors, but the game magically breaks.
It's very hard to debug such an error until you see it in action.
I don't think the OP is a beginner.
I know what : does still i prefer not using it. OMG NAO LETS USE GOTO.
In response to Metamorphman
Metamorphman wrote:
Um, there's nothing wrong with : if you know what you're doing. Calm down. That's why I said use istype() as well.

If you're using istype() anyway, you may as well just typecast it properly and not NEED to use :.
In response to Metamorphman
Metamorphman wrote:
I don't think the OP is a beginner.

I never said that.
It's just that if you start moving variables around you won't be getting any errors from the compiler.
It's a shortcut that removes a lot of safe-guards for your production, which is why I advise again it.
"I never said that"
-> "I don't think you should tell him to use the : just because it's used a ton by beginner programmers."

"If you're using istype() anyway, you may as well just typecast it properly and not NEED to use :."
Absolutely. It was just a suggestion.

Calm down guys.
In response to Metamorphman
Metamorphman wrote:
"I never said that"
-> "I don't think you should tell him to use the : just because it's used a ton by beginner programmers."

I am simply referring to if someone looks at this page as a reference. It's teaching them bad habits.

Either way, his question was answered.
world/mob = /mob/Player; // Fixed typo. Still gives error.

client/North() {
var/mob/player/M = src.mob
if(M.IsInMainMenu) {
M.MoveOption(1);
} else {
return ..();
}
}

client/South() {
var/mob/player/M = src.mob
if(M.IsInMainMenu) {
M.MoveOption(2);
} else {
return ..();
}
}

mob/Player/proc/MoveOption(var/Direction) {
src << "Ew, i'm not done yet... [Direction]";
}

mob/Player/var
IsInMainMenu;


Any errors?
: is actually slow than .
Faster compile-time, slower runtime. You should probably never use : anyways, it's a quick way of uncovering errors where you wouldn't expect to.
In response to Flame Sage
An alternative to all of this is to create another client var that stores a reference to their mob but is declared as being the /mob/player type:

world
mob = /mob/player

mob
player
proc
test()
world << "player.test was called"

client
var
mob/player/player

New()
..()
player = mob

Center()
player.test()


You can't change the type that the client's mob var is defined as, so just define another variable that is the type you want.

Flame Sage wrote:
Metamorphman wrote:
I think the issue is client.mob is typecast as /mob, therefore /mob/Player values aren't going to be there. So just re-typecast:

> > client/proc/test()
> > var/mob/Player/m = mob
> > // Do everything with m instead of mob
> >

Or use the : operator instead and istype() to be safe.

I don't think you should tell him to use the : just because it's used a ton by beginner programmers.

THIS IS A BAD PRACTICE, FYI.
Because then you're completely ignoring the safe-guards in place, and can run into some really weird errors and have a hard time debugging your code down the road when it doesn't work the way you expect it to.

Using the colon operator is probably better here for debugging. Suppose you have this:

world
mob = /mob/player

mob
player
proc
test()
world << "player.test was called"

// Method 1:
client
Center()
mob:test()

// Method 2:
client
Center()
var/mob/player/p = mob
p.test()

Both methods give you the same error message when the client's mob is just of type /mob:

runtime error: undefined proc or verb /mob/test().

proc name: Center (/client/Center)
source file: test.dm,19
usr: the mob (/mob)
src: Guest-2845717940 (/client)
call stack:
Guest-2845717940 (/client): Center()

This makes it quite obvious that you're trying to call test() for a mob of type /mob. If you expand the second method to try to do things the "proper" way, you can run into more problems:

client
Center()
var/mob/player/p = mob
if(istype(p))
p.test()

This makes you avoid getting a runtime error when the client's mob isn't of the /mob/player type, but it also makes the proc fail silently. This will be harder to debug. For a simple case like this you're better off just using the colon operator.
Best response
Ocean King wrote:
Problem description: It says MoveOption() and IsInMainMenu undefined proc and undefined var, when they're both defined and world.mob is set to mob/Player...

If you're using this to make the arrow keys control the player or a menu, you might be better off using my Keyboard library.

The library defines the client.focus var, which is a reference to the object that will receive keypress events. This lets you do simple things like this:

mob
var
Menu/menu = new()

key_down(k)
// make the player move if they pressed an arrow key

proc
use_menu()
// now the menu's key_down proc will be called
// when you press a key
client.focus = menu

close_menu()
// make the keyboard control the player again
client.focus = src

Menu
key_down(k)
// change the selected option in the
// menu based on the key you pressed

You just need to set client.focus to change what object receives the keyboard events so you don't need to add if/else statements to client/North(), South(), etc.
In response to Metamorphman
Metamorphman wrote:
Um, there's nothing wrong with : if you know what you're doing. Calm down. That's why I said use istype() as well.

As written in the sticky post at the top of this forum, advising use of the : operator is a bad idea. The problem is, lots of people don't know what they're doing well enough to be careful. In this case, the OP isn't really a newbie as such but he was caught off-guard by a typecasting issue, hence he's not in a position to use : safely yet.

One very good reason to avoid : in these situations is that this post basically points to a common design flaw, which is defining too many procs under a more specific type rather than a more general type when the latter usually makes more sense. Relying on the . operator highlights this flaw, and many others, which makes it an ideal choice for catching problems before they manifest at runtime.
It's a pretty safe bet that client.mob is of the /mob/player type here, making this a fine place to use the : operator. The problem here is that BYOND defines the mob var so even though you can force a client's mob to be a certain type, you can't change the definition of the var to indicate that type. As I mentioned earlier, the simplest solution is to define your own client var that is of the /mob/player type.

If everybody is so scared of the colon operator that they never tell anyone to use it, how will people learn to use it safely? (switch two words in that last sentence and you've got the start of an anti-abstinence speech)
I tend to agree it's a safe bet here, but the fact that the question came up at all kind of undermines that safety. Like I said, the . operator highlighted what amounts to a common design flaw, and that's a good thing.

Your argument makes sense though, in that sometimes the : operator is just plain simpler as an alternative, and knowing when is an important part of transitioning to an intermediate user. I've used it myself quite a lot--but not in these kinds of situations. I think usr and client.mob and other "natural type" vars make it a good idea to stick any procs under /mob directly that would possibly need to be called that way. Where I've tended to use : is in situations like an omnibus routine that handles several different types but where typecasting might become overly verbose. There are also some highly abstract situations where it's outright necessary, though they don't come up much.
In response to Forum_account
Forum_account wrote:
Ocean King wrote:
Problem description: It says MoveOption() and IsInMainMenu undefined proc and undefined var, when they're both defined and world.mob is set to mob/Player...

If you're using this to make the arrow keys control the player or a menu, you might be better off using my Keyboard library.

The library defines the client.focus var, which is a reference to the object that will receive keypress events. This lets you do simple things like this:

> mob
> var
> Menu/menu = new()
>
> key_down(k)
> // make the player move if they pressed an arrow key
>
> proc
> use_menu()
> // now the menu's key_down proc will be called
> // when you press a key
> client.focus = menu
>
> close_menu()
> // make the keyboard control the player again
> client.focus = src
>
> Menu
> key_down(k)
> // change the selected option in the
> // menu based on the key you pressed
>

You just need to set client.focus to change what object receives the keyboard events so you don't need to add if/else statements to client/North(), South(), etc.

I've been looking wondering if this is fine...

Menu
var
CurrentOption = 1;
mob/Player/Player;
list/Elements = list();

New(mob/Player/Caller) {
Player = Caller;
MainMenu();
}


proc
MainMenu() {
var/obj/Main_Menu/Black_Background_Top/TopScreen = new;
var/obj/Main_Menu/Black_Background_Bottom/BottomScreen = new;
TopScreen.screen_loc = "1,1";
BottomScreen.screen_loc = "BottomScreen:1,1";
Player.client.screen += BottomScreen;
Player.client.screen += TopScreen;
if(fexists("Save Data/Save.dat")) {
var/obj/Main_Menu/Button/Continue = new;
Continue.screen_loc = "2,5:25";
Player.client.screen += Continue;
Continue.icon = 'Selected.dmi';
} else {
var/obj/Main_Menu/Button/NewGame = new;
NewGame.screen_loc = "2,5:25";
Player.client.screen += NewGame;
NewGame.icon = 'Selected.dmi';
}
var/obj/Main_Menu/Button/MysteryGift = new;
MysteryGift.screen_loc = "2,4:30";
Player.client.screen += MysteryGift;

var/obj/Main_Menu/Button/PokemonNetwork = new;
PokemonNetwork.screen_loc = "2,3:35";
Player.client.screen += PokemonNetwork;

for(var/obj/Main_Menu/Button/Button in Player.client.screen) {
if(!Button.type == typesof(/obj/Main_Menu/Button/)) {
continue;
}
Elements += Button;
}
}

key_down(key, client/client) {
if(key == "north") {
if(CurrentOption == 1) {
CurrentOption = 1;
return;
}
var/obj/Main_Menu/Button = Elements[CurrentOption];
Button.icon = 'Button.png';
Button = Elements[CurrentOption-1];
Button.icon = 'Selected.dmi';
src.CurrentOption = CurrentOption-1;
} else {
if(key == "south") {
if(CurrentOption == 3) {
CurrentOption = 3;
return;
}
var/obj/Main_Menu/Button = Elements[CurrentOption];
Button.icon = 'Button.png';
Button = Elements[CurrentOption+1];
Button.icon = 'Selected.dmi';
src.CurrentOption = CurrentOption+1;
}
}
}

In response to Ocean King
It looks like you should be updating the value of CurrentOption in the key_down proc. Something like this:

Menu
key_down(key, client/client)
if(key == "north")
CurrentOption -= 1

if(CurrentOption <= 1)
CurrentOption = 1
return

// do the rest of the stuff

else if(key == "south")
CurrentOption += 1

if(CurrentOption >= 3)
CurrentOption = 3
return

// do the rest of the stuff

The Keyboard library comes with an example of how to switch the focus to an icon state selection menu. It's not the same purpose you're using a menu for here, but its the same idea.
That's done at the bottom of the function o:
Page: 1 2 3