PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/plugins/sample.c

https://gitlab.com/evol/hercules
C | 224 lines | 130 code | 29 blank | 65 comment | 24 complexity | baa94bfd305cc62583235025f3a92997 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.0
  1. /**
  2. * This file is part of Hercules.
  3. * http://herc.ws - http://github.com/HerculesWS/Hercules
  4. *
  5. * Copyright (C) 2013-2015 Hercules Dev Team
  6. *
  7. * Hercules is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /// Sample Hercules Plugin
  21. #include "common/hercules.h" /* Should always be the first Hercules file included! (if you don't make it first, you won't be able to use interfaces) */
  22. #include "common/memmgr.h"
  23. #include "common/mmo.h"
  24. #include "common/socket.h"
  25. #include "common/strlib.h"
  26. #include "map/clif.h"
  27. #include "map/pc.h"
  28. #include "map/script.h"
  29. #include "common/HPMDataCheck.h" /* should always be the last Hercules file included! (if you don't make it last, it'll intentionally break compile time) */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. HPExport struct hplugin_info pinfo = {
  34. "Sample", // Plugin name
  35. SERVER_TYPE_CHAR|SERVER_TYPE_LOGIN|SERVER_TYPE_MAP,// Which server types this plugin works with?
  36. "0.1", // Plugin version
  37. HPM_VERSION, // HPM Version (don't change, macro is automatically updated)
  38. };
  39. ACMD(sample) {//@sample command - 5 params: const int fd, struct map_session_data* sd, const char* command, const char* message, struct AtCommandInfo *info
  40. printf("I'm being run! message -> '%s' by %s\n",message,sd->status.name);
  41. return true;
  42. }
  43. BUILDIN(sample) {//script command 'sample(num);' - 1 param: struct script_state* st
  44. int arg = script_getnum(st,2);
  45. ShowInfo("I'm being run! arg -> '%d'\n",arg);
  46. return true;
  47. }
  48. CPCMD(sample) {//console command 'sample' - 1 param: char *line
  49. ShowInfo("I'm being run! arg -> '%s'\n",line?line:"NONE");
  50. }
  51. struct sample_data_struct {
  52. struct point lastMSGPosition;
  53. unsigned int someNumber;
  54. };
  55. int my_setting;
  56. /* sample packet implementation */
  57. /* cmd 0xf3 - it is a client-server existent id, for clif_parse_GlobalMessage */
  58. /* in this sample we do nothing and simply redirect */
  59. void sample_packet0f3(int fd) {
  60. struct map_session_data *sd = sockt->session[fd]->session_data;
  61. struct sample_data_struct *data;
  62. if( !sd ) return;/* socket didn't fully log-in? this packet shouldn't do anything then! */
  63. ShowInfo("sample_packet0f3: Hello World! received 0xf3 for '%s', redirecting!\n",sd->status.name);
  64. /* sample usage of appending data to a socket_data (sockt->session[]) entry */
  65. if( !(data = getFromSession(sockt->session[fd],0)) ) {
  66. CREATE(data,struct sample_data_struct,1);
  67. data->lastMSGPosition.map = sd->status.last_point.map;
  68. data->lastMSGPosition.x = sd->status.last_point.x;
  69. data->lastMSGPosition.y = sd->status.last_point.y;
  70. data->someNumber = rand()%777;
  71. ShowInfo("Created Appended sockt->session[] data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
  72. addToSession(sockt->session[fd],data,0,true);
  73. } else {
  74. ShowInfo("Existent Appended sockt->session[] data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
  75. if( rand()%4 == 2 ) {
  76. ShowInfo("Removing Appended sockt->session[] data\n");
  77. removeFromSession(sockt->session[fd],0);
  78. }
  79. }
  80. /* sample usage of appending data to a map_session_data (sd) entry */
  81. if( !(data = getFromMSD(sd,0)) ) {
  82. CREATE(data,struct sample_data_struct,1);
  83. data->lastMSGPosition.map = sd->status.last_point.map;
  84. data->lastMSGPosition.x = sd->status.last_point.x;
  85. data->lastMSGPosition.y = sd->status.last_point.y;
  86. data->someNumber = rand()%777;
  87. ShowInfo("Created Appended map_session_data data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
  88. addToMSD(sd,data,0,true);
  89. } else {
  90. ShowInfo("Existent Appended map_session_data data, %d %d %d %d\n",data->lastMSGPosition.map,data->lastMSGPosition.x,data->lastMSGPosition.y,data->someNumber);
  91. if( rand()%4 == 2 ) {
  92. ShowInfo("Removing Appended map_session_data data\n");
  93. removeFromMSD(sd,0);
  94. }
  95. }
  96. clif->pGlobalMessage(fd,sd);
  97. }
  98. int my_pc_dropitem_storage;/* storage var */
  99. /* my custom prehook for pc_dropitem, checks if amount of item being dropped is higher than 1 and if so cap it to 1 and store the value of how much it was */
  100. int my_pc_dropitem_pre(struct map_session_data *sd,int *n,int *amount) {
  101. my_pc_dropitem_storage = 0;
  102. if( *amount > 1 ) {
  103. my_pc_dropitem_storage = *amount;
  104. *amount = 1;
  105. }
  106. return 0;
  107. }
  108. /* postHook receive retVal as the first param, allows posthook to act accordingly to whatever the original was going to return */
  109. int my_pc_dropitem_post(int retVal, struct map_session_data *sd,int *n,int *amount) {
  110. if( retVal != 1 ) return retVal;/* we don't do anything if pc_dropitem didn't return 1 (success) */
  111. if( my_pc_dropitem_storage ) {/* signs whether pre-hook did this */
  112. char output[99];
  113. safesnprintf(output,99,"[ Warning ] you can only drop 1 item at a time, capped from %d to 1",my_pc_dropitem_storage);
  114. clif->messagecolor_self(sd->fd, COLOR_RED, output);
  115. }
  116. return 1;
  117. }
  118. /*
  119. * Key is the setting name in our example it's 'my_setting' while val is the value of it.
  120. * this way you can manage more than one setting in one function instead of define multiable ones
  121. */
  122. void parse_my_setting(const char *key, const char *val) {
  123. ShowDebug("Received '%s:%s'\n",key,val);
  124. /* do anything with the var e.g. config_switch(val) */
  125. /* for our example we will save it in global variable */
  126. /* please note, battle settings can be only returned as int for scripts and other usage */
  127. if (strcmpi(key,"my_setting") == 0)
  128. my_setting = atoi(val);
  129. }
  130. /* Battle Config Settings need to have return function in-case scripts need to read it */
  131. int return_my_setting(const char *key)
  132. {
  133. /* first we check the key to know what setting we need to return with strcmpi then return it */
  134. if (strcmpi(key, "my_setting") == 0)
  135. return my_setting;
  136. return 0;
  137. }
  138. /* run when server starts */
  139. HPExport void plugin_init (void) {
  140. ShowInfo("Server type is ");
  141. switch (SERVER_TYPE) {
  142. case SERVER_TYPE_LOGIN: printf("Login Server\n"); break;
  143. case SERVER_TYPE_CHAR: printf("Char Server\n"); break;
  144. case SERVER_TYPE_MAP: printf ("Map Server\n"); break;
  145. }
  146. ShowInfo("I'm being run from the '%s' filename\n", SERVER_NAME);
  147. // Atcommands only make sense on the map server
  148. if (SERVER_TYPE == SERVER_TYPE_MAP) {
  149. /* addAtcommand("command-key",command-function) tells map server to call ACMD(sample) when "sample" command is used */
  150. /* - it will print a warning when used on a non-map-server plugin */
  151. addAtcommand("sample",sample);//link our '@sample' command
  152. }
  153. // Script commands only make sense on the map server
  154. if (SERVER_TYPE == SERVER_TYPE_MAP) {
  155. /* addScriptCommand("script-command-name","script-command-params-info",script-function) tells map server to call BUILDIN(sample) for the "sample(i)" command */
  156. /* - it will print a warning when used on a non-map-server plugin */
  157. addScriptCommand("sample","i",sample);
  158. }
  159. /* addCPCommand("console-command-name",command-function) tells server to call CPCMD(sample) for the 'this is a sample <optional-args>' console call */
  160. /* in "console-command-name" usage of ':' indicates a category, for example 'this:is:a:sample' translates to 'this is a sample',
  161. * therefore 'this -> is -> a -> sample', it can be used to aggregate multiple commands under the same category or to append commands to existing categories
  162. * categories inherit the special keyword 'help' which prints the subsequent commands, e.g. 'server help' prints all categories and commands under 'server'
  163. * therefore 'this help' would inform about 'is (category) -> a (category) -> sample (command)'*/
  164. addCPCommand("this:is:a:sample",sample);
  165. /* addPacket(packetID,packetLength,packetFunction,packetIncomingPoint) */
  166. /* adds packetID of packetLength (-1 for dynamic length where length is defined in the packet { packetID (2 Byte) , packetLength (2 Byte) , ... })
  167. * to trigger packetFunction in the packetIncomingPoint section ( available points listed in enum HPluginPacketHookingPoints within src/common/HPMi.h ) */
  168. addPacket(0xf3,-1,sample_packet0f3,hpClif_Parse);
  169. // The following hooks would show an error message where pc->dropitem doesn't exist (login or char server)
  170. if (SERVER_TYPE == SERVER_TYPE_MAP) {
  171. /* in this sample we add a PreHook to pc->dropitem */
  172. /* to identify whether the item being dropped is on amount higher than 1 */
  173. /* if so, it stores the amount on a variable (my_pc_dropitem_storage) and changes the amount to 1 */
  174. addHookPre("pc->dropitem",my_pc_dropitem_pre);
  175. /* in this sample we add a PostHook to pc->dropitem */
  176. /* if the original pc->dropitem was successful and the amount stored on my_pc_dropitem_storage is higher than 1, */
  177. /* our posthook will display a message to the user about the cap */
  178. /* - by checking whether it was successful (retVal value) it allows for the originals conditions to take place */
  179. addHookPost("pc->dropitem",my_pc_dropitem_post);
  180. }
  181. }
  182. /* triggered when server starts loading, before any server-specific data is set */
  183. HPExport void server_preinit (void) {
  184. /* makes map server listen to mysetting:value in any "battleconf" file (including imported or custom ones) */
  185. /* value is not limited to numbers, its passed to our plugins handler (parse_my_setting) as const char *,
  186. * however for battle config to be returned to our script engine we need it to be number (int) so keep use it as int only */
  187. addBattleConf("my_setting",parse_my_setting,return_my_setting);
  188. }
  189. /* run when server is ready (online) */
  190. HPExport void server_online (void) {
  191. }
  192. /* run when server is shutting down */
  193. HPExport void plugin_final (void) {
  194. ShowInfo ("%s says ~Bye world\n",pinfo.name);
  195. }