Fox RM

[SRC] Atcommand Events

1 сообщение в этой теме

Доброго времени суток, сразу скажу по поводу исходников, нашел мод в своем старом эмуле, соответственно мод написал [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_ */

2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас