Перейти к содержанию

[SRC] Atcommand Events


Fox RM

Рекомендуемые сообщения

Доброго времени суток, сразу скажу по поводу исходников, нашел мод в своем старом эмуле, соответственно мод написал [ToastOfDoom], под eAthena (в rAthena ,по моему, есть по дефолту этот скрипт.)

Мод включает в себя 3 команды, а именно:

bindatcmd (<atcmd>,<event>);

Да бы каждый раз не править src , в первой строке atcmd - вводите название команды (бинд) , во втором event - название лейбла который будет использовать скрипт нпц. Чтобы все стало понятней, ниже будет рассмотрен пример работы.

unbindatcmd(<atcmd>);

Это позволит удалить все существующие привязки к определенной atcmd.</span><br />

useatcmd(<atcmd string>);

Работает по принципу atcommand() . Более подробный принцип работы увидете ниже, в примере.

Когда atcmd перенаправляется к лейблу, параметры этого atcmd передаются следующими переменными:

. @ atcmd_command $: atcmd который используется.

. @ atcmd_numparameters: количество параметров

. @ atcmd_parameters $ [-]: Параметры, указанные в массиве

Пример:


- script atcmd_sample_inject -1,{
OnInit:
bindatcmd("warp", "atcmd_sample_inject::OnAtCmd");
end;

OnAtCmd:
if(Zeny >= 1000) {
set Zeny, Zeny - 1000;
useatcmd "@warp " + .@atcmd_parameters$[0] + " " + .@atcmd_parameters$[1] + " " + .@atcmd_parameters$[2];
} else {
dispbottom "Sorry... you need at least 1000z to use this service";
}
end;
}

Соответственно вводите в игре @warp и в работу включается лейбл OnAtCmd: ,объяснять его работу не буду, т.к все итак понятно.

Непосредственно сам код:


Index: map/atcommand.c
===================================================================
--- map/atcommand.c (revision 15268)
+++ map/atcommand.c (working copy)
@@ -9182,6 +9494,13 @@
return ( info != NULL ) ? info->level : 100; // 100: command can not be used
}

+struct Atcmd_Binding* get_atcommandbind_byname(const char* name)
+{
+ int i;
+ if( *name == atcommand_symbol || *name == charcommand_symbol ) name++; // for backwards compatibility
+ ARR_FIND( 0, ARRAYLENGTH(atcmd_binding), i, strcmp(atcmd_binding[i].command, name) == 0 );
+ return ( i < ARRAYLENGTH(atcmd_binding) ) ? &atcmd_binding[i] : NULL;
+}

/// Executes an at-command.
bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type)
@@ -9287,6 +9607,18 @@
if( sscanf(atcmd_msg, "%99s %99[^\n]", command, params) < 2 )
params[0] = '\0';

+
+ //check for atcmd events
+ if( type == 1 )
+ {
+ Atcmd_Binding * binding = get_atcommandbind_byname(command);
+ if( binding != NULL && binding->npc_event[0] )
+ { //execute event if binded
+ npc_do_atcmd_event((*atcmd_msg == atcommand_symbol) ? sd : ssd, command, params, binding->npc_event);
+ return true;
+ }
+ }
+
//Grab the command information and check for the proper GM level required to use it or if the command exists
info = get_atcommandinfo_byname(command);
if( info == NULL || info->func == NULL || ( type && ((*atcmd_msg == atcommand_symbol && pc_isGM(sd) < info->level) || (*atcmd_msg == charcommand_symbol && pc_isGM(sd) < info->level2)) ) )
Index: map/atcommand.h
===================================================================
--- map/atcommand.h (revision 15268)
+++ map/atcommand.h (working copy)
@@ -45,4 +45,16 @@
int msg_config_read(const char* cfgName);
void do_final_msg(void);

+#define MAX_ATCMD_BINDINGS 100
+
+typedef struct Atcmd_Binding {
+ char command[50];
+ char npc_event[50];
+} Atcmd_Binding;
+
+//At command events
+struct Atcmd_Binding atcmd_binding[MAX_ATCMD_BINDINGS];
+struct Atcmd_Binding* get_atcommandbind_byname(const char* name);
+
+
#endif /* _ATCOMMAND_H_ */
Index: map/npc.c
===================================================================
--- map/npc.c (revision 15268)
+++ map/npc.c (working copy)
@@ -27,6 +27,7 @@
#include "unit.h"
#include "npc.h"
#include "chat.h"
+#include "atcommand.h"

#include <stdio.h>
#include <stdlib.h>

@@ -2649,6 +2715,115 @@
clif_spawn(&nd->bl);// fade in
}

+int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const char* message, const char* eventname)
+{
+ struct event_data* ev = (struct event_data*)strdb_get(ev_db, eventname);
+ struct npc_data *nd;
+ struct script_state *st;
+ int i = 0, j = 0, k = 0;
+ char *temp;
+ temp = (char*)aMallocA(strlen(message) + 1);
+
+ nullpo_ret(sd);
+
+ if( ev == NULL || (nd = ev->nd) == NULL )
+ {
+ ShowError("npc_event: event not found [%s]\n", eventname);
+ return 0;
+ }
+
+ if( sd->npc_id != 0 )
+ { // Enqueue the event trigger.
+ int i;
+ ARR_FIND( 0, MAX_EVENTQUEUE, i, sd->eventqueue[i][0] == '\0' );
+ if( i < MAX_EVENTQUEUE )
+ {
+ safestrncpy(sd->eventqueue[i],eventname,50); //Event enqueued.
+ return 0;
+ }
+
+ ShowWarning("npc_event: player's event queue is full, can't add event '%s' !\n", eventname);
+ return 1;
+ }
+
+ if( ev->nd->sc.option&OPTION_INVISIBLE )
+ { // Disabled npc, shouldn't trigger event.
+ npc_event_dequeue(sd);
+ return 2;
+ }
+
+ st = script_alloc_state(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id);
+ setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL);
+
+ // split atcmd parameters based on spaces
+ i = 0;
+ j = 0;
+ while( message[i] != '\0' )
+ {
+ if( message[i] == ' ' && k < 127 )
+ {
+ temp[j] = '\0';
+ setd_sub(st, NULL, ".@atcmd_parameters$", k++, (void *)temp, NULL);
+ j = 0;
+ ++i;
+ }
+ else
+ temp[j++] = message[i++];
+ }
+
+ temp[j] = '\0';
+ setd_sub(st, NULL, ".@atcmd_parameters$", k++, (void *)temp, NULL);
+ setd_sub(st, NULL, ".@atcmd_numparameters", 0, (void *)k, NULL);
+ aFree(temp);
+
+ run_script_main(st);
+ return 0;
+}
+
/// Parses a function.
/// function%TAB%script%TAB%<function name>%TAB%{<code>}
static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)

Index: map/npc.h
===================================================================
--- map/npc.h (revision 15268)
+++ map/npc.h (working copy)
@@ -153,7 +164,12 @@

int npc_duplicate4instance(struct npc_data *snd, int m);
int npc_cashshop_buy(struct map_session_data* sd, unsigned int nameid, int amount, int points);

extern struct npc_data* fake_nd;

+// @commands (script-based)
+int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const char* message, const char* eventname);
+
+
#endif /* _NPC_H_ */
Index: map/script.c
===================================================================
--- map/script.c (revision 15268)
+++ map/script.c (working copy)
@@ -3821,9 +3823,18 @@

int script_reload()
{
+ int i;
userfunc_db->clear(userfunc_db,do_final_userfunc_sub);
scriptlabel_db->clear(scriptlabel_db, NULL);

+
+ // clear atcmd bindings
+ for( i = 0; i < MAX_ATCMD_BINDINGS; i++ )
+ {
+ safestrncpy(atcmd_binding[i].command, "", 50);
+ safestrncpy(atcmd_binding[i].npc_event, "", 50);
+ }
+
if(sleep_db) {
struct linkdb_node *n = (struct linkdb_node *)sleep_db;
while(n) {
@@ -15417,7 +16577,301 @@
return 0;
}

+BUILDIN_FUNC(bindatcmd)
+{
+ const char* atcmd;
+ const char* eventName;
+ int i = 0;
+
+ atcmd = script_getstr(st,2);
+ eventName = script_getstr(st,3);
+
+ // check if event is already binded
+ ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command,atcmd) == 0);
+ if( i < MAX_ATCMD_BINDINGS )
+ safestrncpy(atcmd_binding[i].npc_event, eventName, 50);
+ else
+ { // make new binding
+ ARR_FIND(0, MAX_ATCMD_BINDINGS, i, atcmd_binding[i].command[0] == '\0');
+ if( i < MAX_ATCMD_BINDINGS )
+ {
+ safestrncpy(atcmd_binding[i].command, atcmd, 50);
+ safestrncpy(atcmd_binding[i].npc_event, eventName, 50);
+ }
+ }
+
+ return 0;
+}
+
+BUILDIN_FUNC(unbindatcmd)
+{
+ const char* atcmd;
+ int i = 0;
+
+ atcmd = script_getstr(st, 2);
+
+ ARR_FIND(0, MAX_ATCMD_BINDINGS, i, strcmp(atcmd_binding[i].command, atcmd) == 0);
+ if( i < MAX_ATCMD_BINDINGS )
+ {
+ safestrncpy(atcmd_binding[i].command, "", 50);
+ safestrncpy(atcmd_binding[i].npc_event, "", 50);
+ }
+
+ return 0;
+}
+
+BUILDIN_FUNC(useatcmd)
+{
+ TBL_PC dummy_sd;
+ TBL_PC* sd;
+ int fd;
+ const char* cmd;
+
+ cmd = script_getstr(st,2);
+
+ if( st->rid )
+ {
+ sd = script_rid2sd(st);
+ fd = sd->fd;
+ }
+ else
+ { // Use a dummy character.
+ sd = &dummy_sd;
+ fd = 0;
+
+ memset(&dummy_sd, 0, sizeof(TBL_PC));
+ if( st->oid )
+ {
+ struct block_list* bl = map_id2bl(st->oid);
+ memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
+ if( bl->type == BL_NPC )
+ safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
+ }
+ }
+
+ // compatibility with previous implementation (deprecated!)
+ if( cmd[0] != atcommand_symbol )
+ {
+ cmd += strlen(sd->status.name);
+ while( *cmd != atcommand_symbol && *cmd != 0 )
+ cmd++;
+ }
+
+ is_atcommand(fd, sd, cmd, 2);
+ return 0;
+}

@@ -15834,5 +17330,23 @@
BUILDIN_DEF(checkquest, "i?"),
BUILDIN_DEF(changequest, "ii"),
BUILDIN_DEF(showevent, "ii"),
+ BUILDIN_DEF(bindatcmd, "ss"),
+ BUILDIN_DEF(unbindatcmd, "s"),
+ BUILDIN_DEF(useatcmd, "s"),
+
{NULL,NULL,NULL},
};
Index: map/script.h
===================================================================
--- map/script.h (revision 15268)
+++ map/script.h (working copy)
@@ -181,5 +182,8 @@
int add_str(const char* p);
const char* get_str(int id);
int script_reload(void);
+//At command events [ToastOfDoom]
+void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct linkdb_node **ref);

#endif /* _SCRIPT_H_ */

  • Upvote 2
Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...
Яндекс.Метрика