From 6c963b81871a8285694e1cacb5e3ef00f3519b11 Mon Sep 17 00:00:00 2001 From: Fizban Date: Thu, 4 Dec 2008 06:07:32 +0000 Subject: [PATCH] Added Player Attachable Script Code --- changelog | 2 ++ src/act.h | 1 + src/act.informative.c | 7 ++-- src/cedit.c | 11 +++++- src/config.c | 6 ++-- src/config.h | 1 + src/db.c | 3 ++ src/dg_mobcmd.c | 4 +-- src/dg_scripts.c | 25 +++++++------ src/dg_triggers.c | 4 +-- src/interpreter.c | 84 +++++++++++++++++++++++++++++++------------ src/interpreter.h | 7 ++++ src/players.c | 17 ++++++++- src/structs.h | 1 + src/utils.h | 3 ++ 15 files changed, 131 insertions(+), 45 deletions(-) diff --git a/changelog b/changelog index 1870c7f..fb70f3f 100644 --- a/changelog +++ b/changelog @@ -35,6 +35,8 @@ export (QQ's a zone into a tarball)t Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist) (lots of major bugfixes too) @ +[Dec 04 2008] - Fizban + DG Scripts are now attachable to players (cedit toggle defaults this behavior to off). [Dec 01 2008] - Fizban Now compiles warning free on GCC 4.3.2 [Oct 09 2008] - Rumble diff --git a/src/act.h b/src/act.h index 706d355..800fc42 100644 --- a/src/act.h +++ b/src/act.h @@ -274,6 +274,7 @@ ACMD(do_gmote); /** @todo should probably be moved to a more general file handler module */ void clean_llog_entries(void); /** @todo This should be moved to a more general utility file */ +int script_command_interpreter(struct char_data *ch, char *arg); room_rnum find_target_room(struct char_data *ch, char *rawroomstr); void perform_immort_vis(struct char_data *ch); void snoop_check(struct char_data *ch); diff --git a/src/act.informative.c b/src/act.informative.c index a99e84b..4a36027 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -297,9 +297,10 @@ static void list_one_char(struct char_data *i, struct char_data *ch) " is standing here." }; - if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS) && IS_NPC(i)) { + if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_SHOWVNUMS)) { + if (IS_NPC(i)) send_to_char(ch, "[%d] ", GET_MOB_VNUM(i)); - if SCRIPT(i) { + if (SCRIPT(i) && TRIGGERS(SCRIPT(i))) { if (!TRIGGERS(SCRIPT(i))->next) send_to_char(ch, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(i)))); else @@ -1624,7 +1625,7 @@ static void perform_immort_where(struct char_data *ch, char *arg) found = 1; send_to_char(ch, "M%3d. %-25s%s - [%5d] %-25s%s", ++num, GET_NAME(i), QNRM, GET_ROOM_VNUM(IN_ROOM(i)), world[IN_ROOM(i)].name, QNRM); - if (IS_NPC(i) && SCRIPT(i)) { + if (SCRIPT(i)) { if (!TRIGGERS(SCRIPT(i))->next) send_to_char(ch, "[T%d] ", GET_TRIG_VNUM(TRIGGERS(SCRIPT(i)))); else diff --git a/src/cedit.c b/src/cedit.c index da99622..72c8077 100644 --- a/src/cedit.c +++ b/src/cedit.c @@ -103,7 +103,8 @@ static void cedit_setup(struct descriptor_data *d) OLC_CONFIG(d)->play.map_option = CONFIG_MAP; OLC_CONFIG(d)->play.map_size = CONFIG_MAP_SIZE; OLC_CONFIG(d)->play.minimap_size = CONFIG_MINIMAP_SIZE; - + OLC_CONFIG(d)->play.script_players = CONFIG_SCRIPT_PLAYERS; + /* Crash Saves */ OLC_CONFIG(d)->csd.free_rent = CONFIG_FREE_RENT; OLC_CONFIG(d)->csd.max_obj_save = CONFIG_MAX_OBJ_SAVE; @@ -199,6 +200,7 @@ static void cedit_save_internally(struct descriptor_data *d) CONFIG_MAP = OLC_CONFIG(d)->play.map_option; CONFIG_MAP_SIZE = OLC_CONFIG(d)->play.map_size; CONFIG_MINIMAP_SIZE = OLC_CONFIG(d)->play.minimap_size; + CONFIG_SCRIPT_PLAYERS = OLC_CONFIG(d)->play.script_players; /* Crash Saves */ CONFIG_FREE_RENT = OLC_CONFIG(d)->csd.free_rent; @@ -363,6 +365,8 @@ int save_config( IDXTYPE nowhere ) "default_map_size = %d\n\n", CONFIG_MAP_SIZE); fprintf(fl, "* Default minimap size shown to the right of room descriptions\n" "default_minimap_size = %d\n\n", CONFIG_MINIMAP_SIZE); + fprintf(fl, "* Do you want scripts to be attachable to players?\n" + "script_players = %d\n\n", CONFIG_SCRIPT_PLAYERS); strcpy(buf, CONFIG_OK); @@ -595,6 +599,7 @@ static void cedit_disp_game_play_options(struct descriptor_data *d) "%s4%s) Map/Automap Option : %s%s\r\n" "%s5%s) Default map size : %s%d\r\n" "%s6%s) Default minimap size : %s%d\r\n" + "%s7%s) Scripts on PC's : %s%s\r\n" "%sQ%s) Exit To The Main Menu\r\n" "Enter your choice : ", grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.pk_allowed), @@ -622,6 +627,7 @@ static void cedit_disp_game_play_options(struct descriptor_data *d) grn, nrm, cyn, m_opt == 0 ? "Off" : (m_opt == 1 ? "On" : (m_opt == 2 ? "Imm-Only" : "Invalid!")), grn, nrm, cyn, OLC_CONFIG(d)->play.map_size, grn, nrm, cyn, OLC_CONFIG(d)->play.minimap_size, + grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.script_players), grn, nrm ); @@ -948,6 +954,9 @@ void cedit_parse(struct descriptor_data *d, char *arg) write_to_output(d, "Enter default mini-map size (1-12) : "); OLC_MODE(d) = CEDIT_MINIMAP_SIZE; return; + case '7': + TOGGLE_VAR(OLC_CONFIG(d)->play.script_players); + return; case 'q': case 'Q': diff --git a/src/config.c b/src/config.c index bbe6ec7..812eec0 100644 --- a/src/config.c +++ b/src/config.c @@ -38,6 +38,9 @@ /* YES / NO; TRUE / FALSE are all defined in utils.h */ +/* Can Scripts be attached to players? */ +int script_players = NO; + /* pk_allowed sets the tone of the entire game. If pk_allowed is set to NO, * then players will not be allowed to kill, summon, charm, or sleep other * players, as well as a variety of other "asshole player" protections. However, @@ -79,8 +82,7 @@ int dts_are_dumps = YES; /* Whether you want items that immortals load to appear on the ground or not. * It is most likely best to set this to 'YES' so that something else doesn't * grab the item before the immortal does, but that also means people will be - * able to carry around things like boards. That's not necessarily a bad thing, - * but this will be left at a default of 'NO' for historic reasons. */ + * able to carry around things like boards. */ int load_into_inventory = YES; /* "okay" etc. */ diff --git a/src/config.h b/src/config.h index 067f9f3..a70fed4 100644 --- a/src/config.h +++ b/src/config.h @@ -16,6 +16,7 @@ #ifndef __CONFIG_C__ /* Global variable declarations, all settable by cedit */ extern int pk_allowed; +extern int script_players; extern int pt_allowed; extern int level_can_shout; extern int holler_move_cost; diff --git a/src/db.c b/src/db.c index 4a4a05c..185451c 100644 --- a/src/db.c +++ b/src/db.c @@ -3340,6 +3340,7 @@ static void load_default_config( void ) CONFIG_MAP = map_option; CONFIG_MAP_SIZE = default_map_size; CONFIG_MINIMAP_SIZE = default_minimap_size; + CONFIG_SCRIPT_PLAYERS = script_players; /* Rent / crashsave options. */ CONFIG_FREE_RENT = free_rent; @@ -3583,6 +3584,8 @@ void load_config( void ) case 's': if (!str_cmp(tag, "siteok_everyone")) CONFIG_SITEOK_ALL = num; + else if (!str_cmp(tag, "script_players")) + CONFIG_SCRIPT_PLAYERS = num; else if (!str_cmp(tag, "start_messg")) { strncpy(buf, "Reading start message in load_config()", sizeof(buf)); if (CONFIG_START_MESSG) diff --git a/src/dg_mobcmd.c b/src/dg_mobcmd.c index 57d3266..cd73fb6 100644 --- a/src/dg_mobcmd.c +++ b/src/dg_mobcmd.c @@ -43,8 +43,7 @@ static void mob_log(char_data *mob, const char *format, ...) } /* Macro to determine if a mob is permitted to use these commands. */ -#define MOB_OR_IMPL(ch) \ - (IS_NPC(ch) && (!(ch)->desc || GET_LEVEL((ch)->desc->original)>=LVL_IMPL)) +#define MOB_OR_IMPL(ch) (GET_LEVEL(ch) > 0) /* mob commands */ /* prints the argument to all the rooms aroud the mobile */ @@ -279,6 +278,7 @@ ACMD(do_mecho) skip_spaces(&p); sub_write(p, ch, TRUE, TO_ROOM); + sub_write(p, ch, TRUE, TO_CHAR); } ACMD(do_mzoneecho) diff --git a/src/dg_scripts.c b/src/dg_scripts.c index 1f9febc..db0a3cf 100644 --- a/src/dg_scripts.c +++ b/src/dg_scripts.c @@ -969,7 +969,7 @@ ACMD(do_attach) return; } } - if (!IS_NPC(victim)) { + if (!IS_NPC(victim) && !CONFIG_SCRIPT_PLAYERS) { send_to_char(ch, "Players can't have scripts.\r\n"); return; } @@ -988,8 +988,12 @@ ACMD(do_attach) CREATE(SCRIPT(victim), struct script_data, 1); add_trigger(SCRIPT(victim), trig, loc); + if (IS_NPC(victim)) send_to_char(ch, "Trigger %d (%s) attached to %s [%d].\r\n", tn, GET_TRIG_NAME(trig), GET_SHORT(victim), GET_MOB_VNUM(victim)); + else + send_to_char(ch, "Trigger %d (%s) attached to player named %s.\r\n", + tn, GET_TRIG_NAME(trig), GET_NAME(victim)); } else if (is_abbrev(arg, "object") || is_abbrev(arg, "otr")) { @@ -1234,18 +1238,21 @@ ACMD(do_detach) } if (victim) { - if (!IS_NPC(victim)) + if (!IS_NPC(victim) && !CONFIG_SCRIPT_PLAYERS) + { send_to_char(ch, "Players don't have triggers.\r\n"); + return; + } - else if (!SCRIPT(victim)) - send_to_char(ch, "That mob doesn't have any triggers.\r\n"); - else if (!can_edit_zone(ch, real_zone_by_thing(GET_MOB_VNUM(victim)))) { + if (!SCRIPT(victim)) + send_to_char(ch, "That %s doesn't have any triggers.\r\n", IS_NPC(victim) ? "mob" : "player"); + else if (!can_edit_zone(ch, real_zone_by_thing(GET_MOB_VNUM(victim))) && IS_NPC(victim)) { send_to_char(ch, "You can only detach triggers in your own zone\r\n"); return; } else if (trigger && !str_cmp(trigger, "all")) { extract_script(victim, MOB_TRIGGER); - send_to_char(ch, "All triggers removed from %s.\r\n", GET_SHORT(victim)); + send_to_char(ch, "All triggers removed from %s.\r\n", IS_NPC(victim) ? GET_SHORT(victim) : GET_NAME(ch)); } else if (trigger && remove_trigger(SCRIPT(victim), trigger)) { @@ -1806,11 +1813,6 @@ static void process_attach(void *go, struct script_data *sc, trig_data *trig, } if (c) { - if (!IS_NPC(c)) { - script_log("Trigger: %s, VNum %d. attach invalid target: '%s'", - GET_TRIG_NAME(trig), GET_TRIG_VNUM(trig), GET_NAME(c)); - return; - } if (!SCRIPT(c)) CREATE(SCRIPT(c), struct script_data, 1); add_trigger(SCRIPT(c), newtrig, -1); @@ -2652,6 +2654,7 @@ int script_driver(void *go_adress, trig_data *trig, int type, int mode) else { switch (type) { case MOB_TRIGGER: + if (!script_command_interpreter((char_data *) go, cmd)) command_interpreter((char_data *) go, cmd); break; case OBJ_TRIGGER: diff --git a/src/dg_triggers.c b/src/dg_triggers.c index ec2b304..1ff8d14 100644 --- a/src/dg_triggers.c +++ b/src/dg_triggers.c @@ -304,7 +304,7 @@ int command_mtrigger(char_data *actor, char *cmd, char *argument) ch_next = ch->next_in_room; if (SCRIPT_CHECK(ch, MTRIG_COMMAND) && !AFF_FLAGGED(ch, AFF_CHARM) && - (actor!=ch)) { + ((actor!=ch) || CONFIG_SCRIPT_PLAYERS)) { for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) { if (!TRIGGER_CHECK(t, MTRIG_COMMAND)) continue; @@ -344,7 +344,7 @@ void speech_mtrigger(char_data *actor, char *str) ch_next = ch->next_in_room; if (SCRIPT_CHECK(ch, MTRIG_SPEECH) && AWAKE(ch) && - !AFF_FLAGGED(ch, AFF_CHARM) && (actor!=ch)) + !AFF_FLAGGED(ch, AFF_CHARM) && ((actor!=ch) || CONFIG_SCRIPT_PLAYERS)) for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) { if (!TRIGGER_CHECK(t, MTRIG_SPEECH)) continue; diff --git a/src/interpreter.c b/src/interpreter.c index 0f786f6..cec8c58 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -333,30 +333,62 @@ cpp_extern const struct command_info cmd_info[] = { { "zcheck" , "zcheck" , POS_DEAD , do_zcheck , LVL_GOD, 0 }, { "zpurge" , "zpurge" , POS_DEAD , do_zpurge , LVL_BUILDER, 0 }, - /* DG trigger commands. minimum_level should be set to -1. */ - { "masound" , "masound" , POS_DEAD , do_masound , -1, 0 }, - { "mkill" , "mkill" , POS_STANDING, do_mkill , -1, 0 }, - { "mjunk" , "mjunk" , POS_SITTING , do_mjunk , -1, 0 }, - { "mdamage" , "mdamage" , POS_DEAD , do_mdamage , -1, 0 }, - { "mdoor" , "mdoor" , POS_DEAD , do_mdoor , -1, 0 }, - { "mecho" , "mecho" , POS_DEAD , do_mecho , -1, 0 }, - { "mrecho" , "mrecho" , POS_DEAD , do_mrecho , -1, 0 }, - { "mechoaround", "mechoaround", POS_DEAD, do_mechoaround, -1, 0 }, - { "msend" , "msend" , POS_DEAD , do_msend , -1, 0 }, - { "mload" , "mload" , POS_DEAD , do_mload , -1, 0 }, - { "mpurge" , "mpurge" , POS_DEAD , do_mpurge , -1, 0 }, - { "mgoto" , "mgoto" , POS_DEAD , do_mgoto , -1, 0 }, - { "mat" , "mat" , POS_DEAD , do_mat , -1, 0 }, - { "mteleport", "mteleport", POS_DEAD , do_mteleport, -1, 0 }, - { "mforce" , "mforce" , POS_DEAD , do_mforce , -1, 0 }, - { "mhunt" , "mhunt" , POS_DEAD , do_mhunt , -1, 0 }, - { "mremember", "mremember", POS_DEAD , do_mremember, -1, 0 }, - { "mforget" , "mforget" , POS_DEAD , do_mforget , -1, 0 }, - { "mtransform", "mtransform", POS_DEAD , do_mtransform,-1, 0 }, - { "mzoneecho", "mzoneecho", POS_DEAD , do_mzoneecho, -1, 0 }, - { "mfollow" , "mfollow" , POS_DEAD , do_mfollow , -1, 0 }, + { "\n", "zzzzzzz", 0, 0, 0, 0 } }; /* this must be last */ + + + /* Thanks to Melzaren for this change to allow DG Scripts to be attachable + *to player's while still disallowing them to manually use the DG-Commands. */ + const struct mob_script_command_t mob_script_commands[] = { - { "\n", "zzzzzzz", 0, 0, 0, 0 } }; /* this must be last */ + /* DG trigger commands. minimum_level should be set to -1. */ + { "masound" , do_masound , 0 }, + { "mkill" , do_mkill , 0 }, + { "mjunk" , do_mjunk , 0 }, + { "mdamage" , do_mdamage , 0 }, + { "mdoor" , do_mdoor , 0 }, + { "mecho" , do_mecho , 0 }, + { "mrecho" , do_mrecho , 0 }, + { "mechoaround", do_mechoaround , 0 }, + { "msend" , do_msend , 0 }, + { "mload" , do_mload , 0 }, + { "mpurge" , do_mpurge , 0 }, + { "mgoto" , do_mgoto , 0 }, + { "mat" , do_mat , 0 }, + { "mteleport", do_mteleport, 0 }, + { "mforce" , do_mforce , 0 }, + { "mhunt" , do_mhunt , 0 }, + { "mremember", do_mremember, 0 }, + { "mforget" , do_mforget , 0 }, + { "mtransform", do_mtransform , 0 }, + { "mzoneecho", do_mzoneecho, 0 }, + { "mfollow" , do_mfollow , 0 }, + { "\n" , do_not_here , 0 } }; + +int script_command_interpreter(struct char_data *ch, char *arg) { + /* DG trigger commands */ + + int i; + char first_arg[MAX_INPUT_LENGTH]; + char *line; + + skip_spaces(&arg); + if (!*arg) + return 0; + + line = any_one_arg(arg, first_arg); + + for (i = 0; *mob_script_commands[i].command_name != '\n'; i++) + if (!str_cmp(first_arg, mob_script_commands[i].command_name)) + break; // NB - only allow full matches. + + if (*mob_script_commands[i].command_name == '\n') + return 0; // no matching commands. + + /* Poiner to the command? */ + ((*mob_script_commands[i].command_pointer) (ch, line, 0, + mob_script_commands[i].subcmd)); + return 1; // We took care of execution. Let caller know. +} const char *fill[] = { @@ -443,6 +475,12 @@ void command_interpreter(struct char_data *ch, char *argument) if (cont) return; /* yes, command trigger took over */ } + /* Allow IMPLs to switch into mobs to test the commands. */ + if (IS_NPC(ch) && ch->desc && GET_LEVEL(ch->desc->original) >= LVL_IMPL) { + if (script_command_interpreter(ch, argument)) + return; + } + for (length = strlen(arg), cmd = 0; *complete_cmd_info[cmd].command != '\n'; cmd++) if(complete_cmd_info[cmd].command_pointer != do_action && !strncmp(complete_cmd_info[cmd].command, arg, length)) diff --git a/src/interpreter.h b/src/interpreter.h index 194c13d..010445d 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -62,6 +62,13 @@ struct command_info { int subcmd; }; +struct mob_script_command_t { + const char *command_name; + void (*command_pointer) + (struct char_data *ch, char *argument, int cmd, int subcmd); + int subcmd; +}; + struct alias_data { char *alias; char *replacement; diff --git a/src/players.c b/src/players.c index 5bc56f3..ca4a094 100644 --- a/src/players.c +++ b/src/players.c @@ -203,7 +203,9 @@ int load_char(const char *name, struct char_data *ch) char filename[40]; char buf[128], buf2[128], line[MAX_INPUT_LENGTH + 1], tag[6]; char f1[128], f2[128], f3[128], f4[128]; - + trig_data *t = NULL; + trig_rnum t_rnum = NOTHING; + if ((id = get_ptable_by_name(name)) < 0) return (-1); else { @@ -416,6 +418,14 @@ int load_char(const char *name, struct char_data *ch) else if (!strcmp(tag, "Thr4")) GET_SAVE(ch, 3) = atoi(line); else if (!strcmp(tag, "Thr5")) GET_SAVE(ch, 4) = atoi(line); else if (!strcmp(tag, "Titl")) GET_TITLE(ch) = strdup(line); + else if (!strcmp(tag, "Trig") && CONFIG_SCRIPT_PLAYERS) { + if ((t_rnum = real_trigger(atoi(line))) != NOTHING) { + t = read_trigger(t_rnum); + if (!SCRIPT(ch)) + CREATE(SCRIPT(ch), struct script_data, 1); + add_trigger(SCRIPT(ch), t, -1); + } + } break; case 'V': @@ -457,6 +467,7 @@ void save_char(struct char_data * ch) int i, id, save_index = FALSE; struct affected_type *aff, tmp_aff[MAX_AFFECT]; struct obj_data *char_eq[NUM_WEARS]; + trig_data *t; if (IS_NPC(ch) || GET_PFILEPOS(ch) < 0) return; @@ -623,6 +634,10 @@ void save_char(struct char_data * ch) } if (GET_QUEST(ch) != PFDEF_CURRQUEST) fprintf(fl, "Qcur: %d\n", GET_QUEST(ch)); + if (SCRIPT(ch)) { + for (t = TRIGGERS(SCRIPT(ch)); t; t = t->next) + fprintf(fl, "Trig: %d\n",GET_TRIG_VNUM(t)); +} /* Save skills */ if (GET_LEVEL(ch) < LVL_IMMORT) { diff --git a/src/structs.h b/src/structs.h index de12f89..5190386 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1234,6 +1234,7 @@ struct game_data int map_option; /**< MAP_ON, MAP_OFF or MAP_IMM_ONLY */ int map_size; /**< Default size for map command */ int minimap_size; /**< Default size for mini-map (automap) */ + int script_players; /**< Is attaching scripts to players allowed? */ char *OK; /**< When player receives 'Okay.' text. */ char *NOPERSON; /**< 'No one by that name here.' */ diff --git a/src/utils.h b/src/utils.h index 6b4f245..42af0bf 100644 --- a/src/utils.h +++ b/src/utils.h @@ -866,6 +866,9 @@ void char_from_furniture(struct char_data *ch); #define CONFIG_MAP_SIZE config_info.play.map_size #define CONFIG_MINIMAP_SIZE config_info.play.minimap_size +/* DG Script Options */ +#define CONFIG_SCRIPT_PLAYERS config_info.play.script_players + /* Crash Saves */ /** Get free rent setting. */ #define CONFIG_FREE_RENT config_info.csd.free_rent