SHOW:
|
|
- or go back to the newest paste.
1 | diff --git a/src/custom/script.inc b/src/custom/script.inc | |
2 | index 839b990cb..624cecb8a 100644 | |
3 | --- a/src/custom/script.inc | |
4 | +++ b/src/custom/script.inc | |
5 | @@ -17,3 +17,227 @@ | |
6 | // script_pushint(st,1); | |
7 | // return 0; | |
8 | //} | |
9 | + | |
10 | +/*========================================== | |
11 | + * Duplicate any npc on live server | |
12 | + * duplicatenpc "<Source NPC name>","<New NPC shown name>","<New NPC hidden name>","<mapname>",<map_x>,<map_y>,<dir>{, spriteid{, map_xs, map_ys}}}; | |
13 | + *------------------------------------------*/ | |
14 | +BUILDIN_FUNC(duplicatenpc) | |
15 | +{ | |
16 | + int map_x = script_getnum(st, 6); | |
17 | + int map_y = script_getnum(st, 7); | |
18 | + int dir = script_getnum(st, 8); | |
19 | + int spriteid, map_xs = -1, map_ys = -1, sourceid, type, mapid, i; | |
20 | + const char *sourcename = script_getstr(st, 2); | |
21 | + const char *new_shown_name = script_getstr(st, 3); | |
22 | + const char *new_hidden_name = script_getstr(st, 4); | |
23 | + const char *mapname = script_getstr(st, 5); | |
24 | + | |
25 | + char new_npc_name[24] = ""; | |
26 | + struct npc_data *nd_source, *nd_target; | |
27 | + | |
28 | + if(script_hasdata(st, 10)) | |
29 | + map_xs = (script_getnum(st, 10) < -1) ? -1 : script_getnum(st, 10); | |
30 | + | |
31 | + if(script_hasdata(st, 11)) | |
32 | + map_ys = (script_getnum(st, 11) < -1) ? -1 : script_getnum(st, 10); | |
33 | + | |
34 | + if(map_xs == -1 && map_ys != -1) | |
35 | + map_xs = 0; | |
36 | + | |
37 | + if(map_xs != - 1 && map_ys == -1) | |
38 | + map_ys = 0; | |
39 | + | |
40 | + if(strlen(new_shown_name) + strlen(new_hidden_name) > NAME_LENGTH) { | |
41 | + ShowError("buildin_duplicatenpc: New NPC shown name + New NPC hidden name is too long (max %d chars). (%s)\n", sourcename, NAME_LENGTH); | |
42 | + script_pushint(st, 0); | |
43 | + return SCRIPT_CMD_FAILURE; | |
44 | + } | |
45 | + | |
46 | + nd_source = npc_name2id(sourcename); | |
47 | + | |
48 | + if(script_hasdata(st, 9)) | |
49 | + spriteid = (script_getnum(st, 9) < -1) ? -1 : script_getnum(st, 9); | |
50 | + else | |
51 | + spriteid = nd_source->class_; | |
52 | + | |
53 | + if(nd_source == NULL) { | |
54 | + ShowError("buildin_duplicatenpc: original npc not found for duplicate. (%s)\n", sourcename); | |
55 | + script_pushint(st, 0); | |
56 | + return SCRIPT_CMD_FAILURE; | |
57 | + } | |
58 | + | |
59 | + sourceid = nd_source->bl.id; | |
60 | + type = nd_source->subtype; | |
61 | + mapid = map_mapname2mapid(mapname); | |
62 | + | |
63 | + if(mapid < 0) { | |
64 | + ShowError("buildin_duplicatenpc: target map not found. (%s)\n", mapname); | |
65 | + script_pushint(st, 0); | |
66 | + return SCRIPT_CMD_FAILURE; | |
67 | + } | |
68 | + | |
69 | + CREATE(nd_target, struct npc_data, 1); | |
70 | + | |
71 | + strcat(new_npc_name, new_shown_name); | |
72 | + strncat(new_npc_name, "#", 1); | |
73 | + strncat(new_npc_name, new_hidden_name, strlen(new_hidden_name)); | |
74 | + | |
75 | + safestrncpy(nd_target->name, new_npc_name , sizeof(nd_target->name)); | |
76 | + safestrncpy(nd_target->exname, new_npc_name, sizeof(nd_target->exname)); | |
77 | + | |
78 | + nd_target->bl.prev = nd_target->bl.next = NULL; | |
79 | + nd_target->bl.m = mapid; | |
80 | + nd_target->bl.x = map_x; | |
81 | + nd_target->bl.y = map_y; | |
82 | + nd_target->bl.id = npc_get_new_npc_id(); | |
83 | + nd_target->class_ = spriteid; | |
84 | + nd_target->speed = 200; | |
85 | + nd_target->src_id = sourceid; | |
86 | + nd_target->bl.type = BL_NPC; | |
87 | + nd_target->subtype = (enum npc_subtype)type; | |
88 | + | |
89 | + switch(type) { | |
90 | + case NPCTYPE_SCRIPT: | |
91 | + nd_target->u.scr.xs = map_xs; | |
92 | + nd_target->u.scr.ys = map_ys; | |
93 | + nd_target->u.scr.script = nd_source->u.scr.script; | |
94 | + nd_target->u.scr.label_list = nd_source->u.scr.label_list; | |
95 | + nd_target->u.scr.label_list_num = nd_source->u.scr.label_list_num; | |
96 | + break; | |
97 | + case NPCTYPE_SHOP: | |
98 | + case NPCTYPE_CASHSHOP: | |
99 | + case NPCTYPE_ITEMSHOP: | |
100 | + case NPCTYPE_POINTSHOP: | |
101 | + case NPCTYPE_MARKETSHOP: | |
102 | + nd_target->u.shop.shop_item = nd_source->u.shop.shop_item; | |
103 | + nd_target->u.shop.count = nd_source->u.shop.count; | |
104 | + break; | |
105 | + case NPCTYPE_WARP: | |
106 | + if( !battle_config.warp_point_debug ) | |
107 | + nd_target->class_ = JT_WARPNPC; | |
108 | + else | |
109 | + nd_target->class_ = JT_GUILD_FLAG; | |
110 | + nd_target->u.warp.xs = map_xs; | |
111 | + nd_target->u.warp.ys = map_ys; | |
112 | + nd_target->u.warp.mapindex = nd_source->u.warp.mapindex; | |
113 | + nd_target->u.warp.x = nd_source->u.warp.x; | |
114 | + nd_target->u.warp.y = nd_source->u.warp.y; | |
115 | + nd_target->trigger_on_hidden = nd_source->trigger_on_hidden; | |
116 | + break; | |
117 | + } | |
118 | + | |
119 | + map_addnpc(mapid, nd_target); | |
120 | + status_change_init(&nd_target->bl); | |
121 | + unit_dataset(&nd_target->bl); | |
122 | + nd_target->ud.dir = dir; | |
123 | + npc_setcells(nd_target); | |
124 | + map_addblock(&nd_target->bl); | |
125 | + | |
126 | + if(spriteid >= 0) { | |
127 | + status_set_viewdata(&nd_target->bl, nd_target->class_); | |
128 | + clif_spawn(&nd_target->bl); | |
129 | + } | |
130 | + | |
131 | + strdb_put(npcname_db, nd_target->exname, nd_target); | |
132 | + | |
133 | + if(type == NPCTYPE_SCRIPT) { | |
134 | + for (i = 0; i < nd_target->u.scr.label_list_num; i++) { | |
135 | + char* lname = nd_target->u.scr.label_list[i].name; | |
136 | + int pos = nd_target->u.scr.label_list[i].pos; | |
137 | + | |
138 | + if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { | |
139 | + struct event_data* ev; | |
140 | + char buf[NAME_LENGTH*2+3]; | |
141 | + snprintf(buf, ARRAYLENGTH(buf), "%s::%s", nd_target->exname, lname); | |
142 | + | |
143 | + CREATE(ev, struct event_data, 1); | |
144 | + ev->nd = nd_target; | |
145 | + ev->pos = pos; | |
146 | + if(strdb_put(ev_db, buf, ev)) | |
147 | + ShowWarning("npc_parse_duplicate : duplicate event %s (%s)\n", buf, nd_target->name); | |
148 | + } | |
149 | + } | |
150 | + | |
151 | + for (i = 0; i < nd_target->u.scr.label_list_num; i++) { | |
152 | + int t = 0, k = 0; | |
153 | + char *lname = nd_target->u.scr.label_list[i].name; | |
154 | + int pos = nd_target->u.scr.label_list[i].pos; | |
155 | + if (sscanf(lname, "OnTimer%d%n", &t, &k) == 1 && lname[k] == '\0') { | |
156 | + struct npc_timerevent_list *te = nd_target->u.scr.timer_event; | |
157 | + int j, k = nd_target->u.scr.timeramount; | |
158 | + if (te == NULL) | |
159 | + te = (struct npc_timerevent_list *)aMalloc(sizeof(struct npc_timerevent_list)); | |
160 | + else | |
161 | + te = (struct npc_timerevent_list *)aRealloc( te, sizeof(struct npc_timerevent_list) * (k+1) ); | |
162 | + for (j = 0; j < k; j++) { | |
163 | + if (te[j].timer > t) { | |
164 | + memmove(te+j+1, te+j, sizeof(struct npc_timerevent_list)*(k-j)); | |
165 | + break; | |
166 | + } | |
167 | + } | |
168 | + te[j].timer = t; | |
169 | + te[j].pos = pos; | |
170 | + nd_target->u.scr.timer_event = te; | |
171 | + nd_target->u.scr.timeramount++; | |
172 | + } | |
173 | + } | |
174 | + nd_target->u.scr.timerid = INVALID_TIMER; | |
175 | + } | |
176 | + | |
177 | + script_pushint(st, 1); | |
178 | + return SCRIPT_CMD_SUCCESS; | |
179 | +} | |
180 | + | |
181 | +/*========================================== | |
182 | + * Remove any npc duplicate on live server | |
183 | + * duplicateremove "<NPC name>"; | |
184 | + *------------------------------------------*/ | |
185 | +BUILDIN_FUNC(duplicateremove) | |
186 | +{ | |
187 | + struct npc_data *nd; | |
188 | + | |
189 | + if(script_hasdata(st, 2)) { | |
190 | + nd = npc_name2id(script_getstr(st, 2)); | |
191 | + if(nd == NULL) { | |
192 | + script_pushint(st, -1); | |
193 | + return SCRIPT_CMD_FAILURE; | |
194 | + } | |
195 | + } else | |
196 | + nd = (struct npc_data *)map_id2bl(st->oid); | |
197 | + | |
198 | + if(!nd->src_id) | |
199 | + npc_unload_duplicates(nd); | |
200 | + else | |
201 | + npc_unload(nd,true); | |
202 | + | |
203 | + script_pushint(st, 1); | |
204 | + return SCRIPT_CMD_SUCCESS; | |
205 | +} | |
206 | + | |
207 | diff --git a/src/custom/script_def.inc b/src/custom/script_def.inc | |
208 | index 886399273..ed7956a7f 100644 | |
209 | --- a/src/custom/script_def.inc | |
210 | +++ b/src/custom/script_def.inc | |
211 | @@ -9,3 +9,6 @@ | |
212 | **/ | |
213 | ||
214 | //BUILDIN_DEF(example,""), | |
215 | +BUILDIN_DEF(duplicatenpc, "ssssiii???"), | |
216 | +BUILDIN_DEF(duplicateremove, "?"), | |
217 | diff --git a/src/map/npc.cpp b/src/map/npc.cpp | |
218 | index 558c019fe..ce9e5f039 100644 | |
219 | --- a/src/map/npc.cpp | |
220 | +++ b/src/map/npc.cpp | |
221 | @@ -85,13 +85,8 @@ int npc_get_new_npc_id(void) { | |
222 | } | |
223 | } | |
224 | ||
225 | -static DBMap* ev_db; // const char* event_name -> struct event_data* | |
226 | -static DBMap* npcname_db; // const char* npc_name -> struct npc_data* | |
227 | - | |
228 | -struct event_data { | |
229 | - struct npc_data *nd; | |
230 | - int pos; | |
231 | -}; | |
232 | +DBMap* ev_db; // const char* event_name -> struct event_data* | |
233 | +DBMap* npcname_db; // const char* npc_name -> struct npc_data* | |
234 | ||
235 | static struct eri *timer_event_ers; //For the npc timer data. [Skotlex] | |
236 | ||
237 | @@ -2136,7 +2131,7 @@ static int npc_unload_ev(DBKey key, DBData *data, va_list ap) | |
238 | ||
239 | //Chk if npc matches src_id, then unload. | |
240 | //Sub-function used to find duplicates. | |
241 | -static int npc_unload_dup_sub(struct npc_data* nd, va_list args) | |
242 | +int npc_unload_dup_sub(struct npc_data* nd, va_list args) | |
243 | { | |
244 | int src_id; | |
245 | ||
246 | diff --git a/src/map/npc.hpp b/src/map/npc.hpp | |
247 | index af71f3507..c2a1817de 100644 | |
248 | --- a/src/map/npc.hpp | |
249 | +++ b/src/map/npc.hpp | |
250 | @@ -107,6 +107,14 @@ struct npc_data { | |
251 | struct eri; | |
252 | extern struct eri *npc_sc_display_ers; | |
253 | ||
254 | +extern DBMap* ev_db; // const char* event_name -> struct event_data* | |
255 | +extern DBMap* npcname_db; // const char* npc_name -> struct npc_data* | |
256 | + | |
257 | +struct event_data { | |
258 | + struct npc_data *nd; | |
259 | + int pos; | |
260 | +}; | |
261 | + | |
262 | #define START_NPC_NUM 110000000 | |
263 | ||
264 | enum e_job_types | |
265 | @@ -1206,6 +1214,8 @@ int npc_instanceinit(struct npc_data* nd); | |
266 | int npc_instancedestroy(struct npc_data* nd); | |
267 | int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amount, int points); | |
268 | ||
269 | +int npc_unload_dup_sub(struct npc_data *nd, va_list args); | |
270 | + | |
271 | void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, int cost[2], bool display); | |
272 | ||
273 | extern struct npc_data* fake_nd; |