Addyt Hall manager script

Ask for help regarding any technical issue or report any bug or OS independent issues.


Post Reply
User avatar
quietlyquietly
Novice
Novice
Posts: 50
Joined: 07 Sep 2023, 09:40

Addyt Hall manager script

Post by quietlyquietly »

The following is the Addyt Hall manager script. It fails in one respect because the get() function will not fetch another player's authorization.
I seek a work around.

Also, this seeks approval of using the Addyt_GM variable for Addyt Hall manager status.
As it is an entity within the Manaworld, it may have managers that are entirely separate from the Manaworld GM's, and with none of the usual GM abilities.

BUG: This will always fetch 0, even for the current user, even right after the variable was set. It has been verified that the set worked, at least for @target_id = BL_ID.
This affects being able to see the current state in the Manager's function.
Other scripts have variations of using get(), but maybe the variable they access is somewhat "special".
Tests have shown that it will work if the var is @Addyt_GM instead, but of course that is a temporary, and not suitable for holding a permanent status.

Code: Select all

    set .@AGM, get( Addyt_GM, @target_id );

BUG:
This line will crash the server instantly and without decent error messages. You have to randomly change code to even find which line caused the crash. No script bug should ever be allowed to crash the server.

Code: Select all

     if( ! isloggedin(BL_ID))  goto L_close;

The manager click spot.

Code: Select all

// Addyt Hall

008-2,16,42,0|script|Manager#AddytHall|400
{
    // WARNING: if( ! isloggedin(BL_ID)) --> will CRASH THE SERVER
    if( ! (isloggedin(BL_ID)) ) goto L_close;

if( Addyt_GM || (GM >= G_ADMIN)  )  goto L_menu;
mes "That is the managers shelf, no snooping.";
goto L_close;

L_menu:
    mes "[Addyt Hall Manager]";
    menu
        "Manage Quest Board", L_manage_quest_board,
        "Manage Message Board", L_manage_message_board,
	"Manage Addyt_GM", L_self;

L_GM_menu:
    mes "[Addyt Hall Manager]";
    // BUG: Cannot get current value because the following line does not work (due to var type).
    // set .@AGM, get( Addyt_GM, @target_id );
    mes @who$+" : "+@target_id+" : "+if_then_else(.@AGM, "AUTHORIZED", "Not-Authorized");
    menu
        "Enable Addyt_GM", L_set_manager,
	"Disable Addyt_GM", L_clear_manager,
	"Select user", L_another,
	"Done", L_menu;

L_self:
    set @who$, "SELF";
    set @target_id, BL_ID;
    goto L_GM_menu;

L_another:
    mes "Who to authorize (name, SELF).";
    input @who$;
    if( @who$ == "SELF" ) goto L_self;
    set @target_id, getcharid(3, @who$);
    goto L_GM_menu;

L_set_manager:
    set Addyt_GM, 1, @target_id;
    goto L_GM_menu;

L_clear_manager:
    set Addyt_GM, 0, @target_id;
    goto L_GM_menu;

L_manage_quest_board:
    callfunc( "quest_board_manage" );
    goto L_menu;

L_manage_message_board:
    callfunc( "message_board_manage" );
    goto L_menu;

L_close:
    close;
}
User avatar
Hello=)
The Mana World
The Mana World
Posts: 716
Joined: 11 Jun 2009, 12:46

Re: Addyt Hall manager script

Post by Hello=) »

1) A bit strange question, but... how do you even manage to trigger this NPC event without relevant player logged in ("attached") in to invoke this event, so you need strange check (if( ! (isloggedin(BL_ID)) ) goto L_close;) right at start? I can think few exotic ways to invoke NPC from code without player really attached - but this would need some really strange custom steps explicitly doing "strange" things.

Under normal course of action, when player triggers event invoked on NPC, on one side of abstraction there's player who caused event, and on another side there's NPC that contains code handling event. So how do you get into case where triggering player NOT here, right at start of handler code? I can understand this concern if you waited input for a while or shown menu/input that needs interaction - but IIRC in that case if player is gone like that, server aborts script itself.

There're few exceptions to mentioned abstraction, but I only know 2:

  • "item script" (on use/equip) that lacks NPC side and so runs in "exotic" environment (quite easy to call some NPC if desired)
  • "detached player" mode, when you either explicitly detachrid() - or its "detached" action like npc timer that can not rely on particular player existence. E.g. battle controller code doesn't generally wants to rely on some player(s) being here. "Detached" code obviously should not try dialogs.

So how do you enter state that needs to check player attached right in start of npc handler code? I do not really understand.

2) set .@AGM, get( Addyt_GM, @target_id );
This code looks suspicious. Do you know @target_id only "locally valid" var and used by many things? To use @target_id you meant to explicitly do something that sets it "here and now", or be invoked by something that sets it and only use it "here and now". It set in various places - for various reasons - like e.g. foreach(), or OnAttack event via overriteattack(). Like that, it could e.g. even be "server-set". So its temp var on player, only guaranteed to be "locally valid" when you know there was action setting it to what you think it is, and you better not to rely on @target_id anywhere "later".

I also vaguely remember get(PermanentPlayerVar, <AnotherPlayerID>) eventually failed me. Technically, scripts very rarely need to get/set permanent var on ANOTHER player(different from attached one), so perhaps there is bug/underimplementation on server side. It could easily be me and you are 1st persons to go this far.

NB: if you need to know ID of "self" for any reason (i.e. player attached, who triggered NPC action), its what BL_ID normally is. If in doubt, try debugmes - it prints NPC ID and player ID + text (can be used to show variables, too). E.g. debugmes "my ID=" + BL_ID; would show ID of caller, ID of NPC and print what BL_ID had at this time (normally BL_ID is same as what debugmes prefix prints, so it more useful for other vars).

Also most of time you do not need to get() on "self". You can directly write e,g. if (Addyt_GM == 42) goto L_HavePrivs - like that, if attached player (one who clicked NPC) had Addyt_GM permanent var set to 42, they recognized as having privs. Like that you can implement trivial permission system by literally few lines of code. On side note there's "blunt" @setvar command so you can skip "management UI" part setting var on player as bare minimum, so that staff would need @setvar AddytGM 0 1 WhateverPlayerNick manually - but its not such a big deal, at least in initial code version - and checking rights can be virtually "oneliner". You can take a look on "minimalist ACL" like this in e.g. "bosspowers" family of spells. I.e. these want either GM >= 40 or custom permanent var set on player designating them as "eventer" who allowed to cast "overpowered" spells. Use of @setvar needs GM 80 so only few ppl can override this - by LOGGED @setvar server command (so in the end its clear who changed permissions if this needs review or something). Scripts can also write to GM logs if desired.

Post Reply