1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
|
|
4 | * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
8 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * the terms of the Affero GNU General Public License as published by the |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * option) any later version. |
12 | * option) any later version. |
12 | * |
13 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * GNU General Public License for more details. |
17 | * |
18 | * |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * You should have received a copy of the Affero GNU General Public License |
19 | * and the GNU General Public License along with this program. If not, see |
20 | * and the GNU General Public License along with this program. If not, see |
20 | * <http://www.gnu.org/licenses/>. |
21 | * <http://www.gnu.org/licenses/>. |
21 | * |
22 | * |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
24 | */ |
24 | |
25 | |
25 | #include <global.h> |
26 | #include <global.h> |
26 | #include <sproto.h> |
27 | #include <sproto.h> |
… | |
… | |
260 | *from = STACK_FROM_TOP; |
261 | *from = STACK_FROM_TOP; |
261 | return dm_stack_peek (pl); |
262 | return dm_stack_peek (pl); |
262 | } |
263 | } |
263 | |
264 | |
264 | /** |
265 | /** |
265 | * Actually hides specified player (obviously a DM). |
|
|
266 | * If 'silent_dm' is non zero, other players are informed of DM entering/leaving, |
|
|
267 | * else they just think someone left/entered. |
|
|
268 | */ |
|
|
269 | static void |
|
|
270 | do_wizard_hide (object *op, int silent_dm) |
|
|
271 | { |
|
|
272 | if (op->contr->hidden) |
|
|
273 | { |
|
|
274 | op->contr->hidden = 0; |
|
|
275 | op->invisible = 1; |
|
|
276 | new_draw_info (NDI_UNIQUE, 0, op, "You are no longer hidden from other players"); |
|
|
277 | op->map->players++; |
|
|
278 | new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s has entered the game.", &op->name); |
|
|
279 | |
|
|
280 | if (!silent_dm) |
|
|
281 | new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master has arrived!"); |
|
|
282 | } |
|
|
283 | else |
|
|
284 | { |
|
|
285 | op->contr->hidden = 1; |
|
|
286 | new_draw_info (NDI_UNIQUE, 0, op, "Other players will no longer see you."); |
|
|
287 | op->map->players--; |
|
|
288 | |
|
|
289 | if (!silent_dm) |
|
|
290 | new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master is gone.."); |
|
|
291 | |
|
|
292 | new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s leaves the game.", &op->name); |
|
|
293 | new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s left the game.", &op->name); |
|
|
294 | } |
|
|
295 | } |
|
|
296 | |
|
|
297 | int |
|
|
298 | command_hide (object *op, char *params) |
|
|
299 | { |
|
|
300 | do_wizard_hide (op, 0); |
|
|
301 | return 1; |
|
|
302 | } |
|
|
303 | |
|
|
304 | /** |
|
|
305 | * This finds and returns the object which matches the name or |
266 | * This finds and returns the object which matches the name or |
306 | * object nubmer (specified via num #whatever). |
267 | * object nubmer (specified via num #whatever). |
307 | */ |
268 | */ |
308 | static object * |
269 | static object * |
309 | find_object_both (char *params) |
270 | find_object_both (char *params) |
… | |
… | |
462 | { |
423 | { |
463 | new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to place summoned player."); |
424 | new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to place summoned player."); |
464 | return 1; |
425 | return 1; |
465 | } |
426 | } |
466 | |
427 | |
467 | nx += freearr_x [i]; |
428 | nx += DIRX (i); |
468 | ny += freearr_y [i]; |
429 | ny += DIRY (i); |
469 | |
430 | |
470 | if (!xy_normalise (m, nx, ny)) |
431 | if (!xy_normalise (m, nx, ny)) |
471 | { |
432 | { |
472 | new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to place summoned player."); |
433 | new_draw_info (NDI_UNIQUE, 0, op, "Can not find a free spot to place summoned player."); |
473 | return 1; |
434 | return 1; |
… | |
… | |
981 | * This adds exp to a player. We now allow adding to a specific skill. |
942 | * This adds exp to a player. We now allow adding to a specific skill. |
982 | */ |
943 | */ |
983 | int |
944 | int |
984 | command_addexp (object *op, char *params) |
945 | command_addexp (object *op, char *params) |
985 | { |
946 | { |
986 | char buf[MAX_BUF], skill[MAX_BUF]; |
947 | char buf[1024], skill[1024]; |
987 | int q; |
948 | int q; |
988 | long long i; // use sint64 and finally provide format specifiers for sint64 etc. via configure |
949 | sint64 i; |
989 | object *skillob = NULL; |
950 | object *skillob = NULL; |
990 | |
951 | |
991 | skill[0] = '\0'; |
952 | skill[0] = '\0'; |
992 | if ((params == NULL) || (strlen (params) > MAX_BUF) || ((q = sscanf (params, "%s %lld %[^\n]", buf, &i, skill)) < 2)) |
953 | if ((params == NULL) || (strlen (params) > MAX_BUF) || ((q = sscanf (params, "%1023s %" SCNd64 " %1023[^\n]", buf, &i, skill)) < 2)) |
993 | { |
954 | { |
994 | new_draw_info (NDI_UNIQUE, 0, op, "Usage: addexp <who> <how much> [<skill>]."); |
955 | new_draw_info (NDI_UNIQUE, 0, op, "Usage: addexp <who> <how much> [<skill>]."); |
995 | return 1; |
956 | return 1; |
996 | } |
957 | } |
997 | |
958 | |
… | |
… | |
1033 | /**************************************************************************/ |
994 | /**************************************************************************/ |
1034 | |
995 | |
1035 | int |
996 | int |
1036 | command_stats (object *op, char *params) |
997 | command_stats (object *op, char *params) |
1037 | { |
998 | { |
1038 | char thing[20]; |
|
|
1039 | char buf[MAX_BUF]; |
999 | char buf[MAX_BUF]; |
1040 | |
1000 | |
1041 | thing[0] = '\0'; |
1001 | if (params == NULL || params[0] == '\0') |
1042 | if (params == NULL || !sscanf (params, "%s", thing) || thing == NULL) |
|
|
1043 | { |
1002 | { |
1044 | new_draw_info (NDI_UNIQUE, 0, op, "Who?"); |
1003 | new_draw_info (NDI_UNIQUE, 0, op, "Who?"); |
1045 | return 1; |
1004 | return 1; |
1046 | } |
1005 | } |
1047 | |
1006 | |
1048 | for_all_players (pl) |
1007 | for_all_players (pl) |
1049 | if (!strcmp (&pl->ob->name, thing)) |
1008 | if (!strcmp (&pl->ob->name, params)) |
1050 | { |
1009 | { |
1051 | sprintf (buf, "Str : %-2d H.P. : %-4d MAX : %d", pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp); |
1010 | sprintf (buf, "Str : %-2d H.P. : %-4d MAX : %d", pl->ob->stats.Str, pl->ob->stats.hp, pl->ob->stats.maxhp); |
1052 | new_draw_info (NDI_UNIQUE, 0, op, buf); |
1011 | new_draw_info (NDI_UNIQUE, 0, op, buf); |
1053 | sprintf (buf, "Dex : %-2d S.P. : %-4d MAX : %d", pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp); |
1012 | sprintf (buf, "Dex : %-2d S.P. : %-4d MAX : %d", pl->ob->stats.Dex, pl->ob->stats.sp, pl->ob->stats.maxsp); |
1054 | new_draw_info (NDI_UNIQUE, 0, op, buf); |
1013 | new_draw_info (NDI_UNIQUE, 0, op, buf); |
… | |
… | |
1070 | } |
1029 | } |
1071 | |
1030 | |
1072 | int |
1031 | int |
1073 | command_abil (object *op, char *params) |
1032 | command_abil (object *op, char *params) |
1074 | { |
1033 | { |
1075 | char thing[20], thing2[20]; |
1034 | char thing[80], thing2[80]; |
1076 | int iii; |
1035 | int iii; |
1077 | char buf[MAX_BUF]; |
1036 | char buf[MAX_BUF]; |
1078 | |
1037 | |
1079 | iii = 0; |
1038 | iii = 0; |
1080 | thing[0] = '\0'; |
1039 | thing[0] = '\0'; |
1081 | thing2[0] = '\0'; |
1040 | thing2[0] = '\0'; |
1082 | if (params == NULL || !sscanf (params, "%s %s %d", thing, thing2, &iii) || thing == NULL) |
1041 | if (!params || 3 != sscanf (params, "%79s %79s %d", thing, thing2, &iii)) |
1083 | { |
1042 | { |
1084 | new_draw_info (NDI_UNIQUE, 0, op, "Who?"); |
1043 | new_draw_info (NDI_UNIQUE, 0, op, "Who?"); |
1085 | return 1; |
1044 | return 1; |
1086 | } |
1045 | } |
1087 | |
1046 | |
1088 | if (thing2 == NULL) |
1047 | if (!*thing2) |
1089 | { |
1048 | { |
1090 | new_draw_info (NDI_UNIQUE, 0, op, "You can't change that."); |
1049 | new_draw_info (NDI_UNIQUE, 0, op, "You can't change that."); |
1091 | return 1; |
1050 | return 1; |
1092 | } |
1051 | } |
1093 | |
1052 | |
… | |
… | |
1119 | new_draw_info (NDI_UNIQUE, 0, op, "No such player."); |
1078 | new_draw_info (NDI_UNIQUE, 0, op, "No such player."); |
1120 | return 1; |
1079 | return 1; |
1121 | } |
1080 | } |
1122 | |
1081 | |
1123 | int |
1082 | int |
1124 | command_nowiz (object *op, char *params) |
|
|
1125 | { /* 'nodm' is alias */ |
|
|
1126 | op->clr_flag (FLAG_WIZ); |
|
|
1127 | op->clr_flag (FLAG_WIZPASS); |
|
|
1128 | op->clr_flag (FLAG_WIZCAST); |
|
|
1129 | op->clr_flag (FLAG_WIZLOOK); |
|
|
1130 | op->contr->do_los = 1; |
|
|
1131 | |
|
|
1132 | if (op->contr->hidden) |
|
|
1133 | { |
|
|
1134 | new_draw_info (NDI_UNIQUE, 0, op, "You are no longer hidden from other players"); |
|
|
1135 | op->map->players++; |
|
|
1136 | new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, NULL, "%s has entered the game.", &op->name); |
|
|
1137 | op->contr->hidden = 0; |
|
|
1138 | op->invisible = 1; |
|
|
1139 | } |
|
|
1140 | else |
|
|
1141 | new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master is gone.."); |
|
|
1142 | |
|
|
1143 | return 1; |
|
|
1144 | } |
|
|
1145 | |
|
|
1146 | /** |
|
|
1147 | * object *op is trying to become dm. |
|
|
1148 | * pl_name is name supplied by player. Restrictive DM will make it harder |
|
|
1149 | * for socket users to become DM - in that case, it will check for the players |
|
|
1150 | * character name. |
|
|
1151 | */ |
|
|
1152 | static int |
|
|
1153 | checkdm (object *op, const char *pl_name, const char *pl_passwd, const char *pl_host) |
|
|
1154 | { |
|
|
1155 | FILE *dmfile; |
|
|
1156 | char buf[MAX_BUF]; |
|
|
1157 | char line_buf[160], name[160], passwd[160], host[160]; |
|
|
1158 | |
|
|
1159 | #ifdef RESTRICTIVE_DM |
|
|
1160 | *pl_name = op->name ? op->name : "*"; |
|
|
1161 | #endif |
|
|
1162 | |
|
|
1163 | sprintf (buf, "%s/%s", settings.confdir, DMFILE); |
|
|
1164 | if ((dmfile = fopen (buf, "r")) == NULL) |
|
|
1165 | { |
|
|
1166 | LOG (llevDebug, "Could not find DM file.\n"); |
|
|
1167 | return 0; |
|
|
1168 | } |
|
|
1169 | |
|
|
1170 | while (fgets (line_buf, 160, dmfile) != NULL) |
|
|
1171 | { |
|
|
1172 | if (line_buf[0] == '#') |
|
|
1173 | continue; |
|
|
1174 | if (sscanf (line_buf, "%[^:]:%[^:]:%s\n", name, passwd, host) != 3) |
|
|
1175 | { |
|
|
1176 | LOG (llevError, "Warning - malformed dm file entry: %s\n", line_buf); |
|
|
1177 | } |
|
|
1178 | else if ((!strcmp (name, "*") || (pl_name && !strcmp (pl_name, name))) |
|
|
1179 | && (!strcmp (passwd, "*") || !strcmp (passwd, pl_passwd)) && (!strcmp (host, "*") || !strcmp (host, pl_host))) |
|
|
1180 | { |
|
|
1181 | fclose (dmfile); |
|
|
1182 | return (1); |
|
|
1183 | } |
|
|
1184 | } |
|
|
1185 | fclose (dmfile); |
|
|
1186 | return (0); |
|
|
1187 | } |
|
|
1188 | |
|
|
1189 | static int |
|
|
1190 | do_wizard_dm (object *op, char *params, int silent) |
|
|
1191 | { |
|
|
1192 | if (!op->contr) |
|
|
1193 | return 0; |
|
|
1194 | |
|
|
1195 | if (op->flag [FLAG_WIZ]) |
|
|
1196 | { |
|
|
1197 | new_draw_info (NDI_UNIQUE, 0, op, "You are already the Dungeon Master!"); |
|
|
1198 | return 0; |
|
|
1199 | } |
|
|
1200 | |
|
|
1201 | if (checkdm (op, op->name, (params ? params : "*"), op->contr->ns->host)) |
|
|
1202 | { |
|
|
1203 | op->set_flag (FLAG_WIZ); |
|
|
1204 | op->set_flag (FLAG_WIZPASS); |
|
|
1205 | op->set_flag (FLAG_WIZCAST); |
|
|
1206 | op->set_flag (FLAG_WIZLOOK); |
|
|
1207 | op->contr->do_los = 1; |
|
|
1208 | |
|
|
1209 | new_draw_info (NDI_UNIQUE, 0, op, "Ok, you are the Dungeon Master!"); |
|
|
1210 | op->contr->write_buf[0] = '\0'; |
|
|
1211 | |
|
|
1212 | if (!silent) |
|
|
1213 | new_draw_info (NDI_UNIQUE | NDI_ALL | NDI_LT_GREEN, 1, NULL, "The Dungeon Master has arrived!"); |
|
|
1214 | |
|
|
1215 | return 1; |
|
|
1216 | } |
|
|
1217 | else |
|
|
1218 | { |
|
|
1219 | new_draw_info (NDI_UNIQUE, 0, op, "Sorry Pal, I don't think so."); |
|
|
1220 | op->contr->write_buf[0] = '\0'; |
|
|
1221 | return 0; |
|
|
1222 | } |
|
|
1223 | } |
|
|
1224 | |
|
|
1225 | /* |
|
|
1226 | * Actual command to perhaps become dm. Changed aroun a bit in version 0.92.2 |
|
|
1227 | * - allow people on sockets to become dm, and allow better dm file |
|
|
1228 | */ |
|
|
1229 | int |
|
|
1230 | command_dm (object *op, char *params) |
|
|
1231 | { |
|
|
1232 | if (!op->contr) |
|
|
1233 | return 0; |
|
|
1234 | |
|
|
1235 | do_wizard_dm (op, params, 0); |
|
|
1236 | |
|
|
1237 | return 1; |
|
|
1238 | } |
|
|
1239 | |
|
|
1240 | int |
|
|
1241 | command_invisible (object *op, char *params) |
1083 | command_invisible (object *op, char *params) |
1242 | { |
1084 | { |
1243 | if (op) |
1085 | if (op) |
1244 | { |
1086 | { |
1245 | op->invisible += 100; |
1087 | op->invisible += TIME2TICK (60); |
1246 | update_object (op, UP_OBJ_CHANGE); |
1088 | update_object (op, UP_OBJ_CHANGE); |
1247 | new_draw_info (NDI_UNIQUE, 0, op, "You turn invisible."); |
1089 | new_draw_info (NDI_UNIQUE, 0, op, "You turn invisible."); |
1248 | } |
1090 | } |
1249 | |
1091 | |
1250 | return 0; |
1092 | return 0; |
… | |
… | |
1347 | { |
1189 | { |
1348 | new_draw_info (NDI_UNIQUE, 0, op, "Which spell do you want to forget?"); |
1190 | new_draw_info (NDI_UNIQUE, 0, op, "Which spell do you want to forget?"); |
1349 | return 0; |
1191 | return 0; |
1350 | } |
1192 | } |
1351 | |
1193 | |
1352 | spell = lookup_spell_by_name (op, params); |
1194 | spell = op->find_spell (params); |
1353 | if (spell == NULL) |
1195 | if (spell == NULL) |
1354 | { |
1196 | { |
1355 | new_draw_info_format (NDI_UNIQUE, 0, op, "You do not know the spell %s.", params); |
1197 | new_draw_info_format (NDI_UNIQUE, 0, op, "You do not know the spell %s.", params); |
1356 | return 0; |
1198 | return 0; |
1357 | } |
1199 | } |
1358 | |
1200 | |
1359 | do_forget_spell (op, spell->name); |
1201 | do_forget_spell (op, spell->name); |
1360 | return 1; |
|
|
1361 | } |
|
|
1362 | |
|
|
1363 | /** |
|
|
1364 | * A players wants to become DM and hide. |
|
|
1365 | * Let's see if that's authorized. |
|
|
1366 | * Make sure to not tell anything to anyone. |
|
|
1367 | */ |
|
|
1368 | int |
|
|
1369 | command_dmhide (object *op, char *params) |
|
|
1370 | { |
|
|
1371 | if (!do_wizard_dm (op, params, 1)) |
|
|
1372 | return 0; |
|
|
1373 | |
|
|
1374 | do_wizard_hide (op, 1); |
|
|
1375 | |
|
|
1376 | return 1; |
1202 | return 1; |
1377 | } |
1203 | } |
1378 | |
1204 | |
1379 | /** |
1205 | /** |
1380 | * Pop the stack top. |
1206 | * Pop the stack top. |