ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_misc.C
Revision: 1.62
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.61: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
4 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Crossfire TRT is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
24 #include <global.h>
25 #include <loader.h>
26 #include <sproto.h>
27
28 /* Handles misc. input request - things like hash table, malloc, maps, etc */
29
30 int
31 command_motd (object *op, char *params)
32 {
33 display_motd (op);
34 return 1;
35 }
36
37 #ifdef DEBUG_MALLOC_LEVEL
38 int
39 command_malloc_verify (object *op, char *parms)
40 {
41 extern int malloc_verify (void);
42
43 if (!malloc_verify ())
44 new_draw_info (NDI_UNIQUE, 0, op, "Heap is corrupted.");
45 else
46 new_draw_info (NDI_UNIQUE, 0, op, "Heap checks out OK.");
47 return 1;
48 }
49 #endif
50
51 int
52 command_whereabouts (object *op, char *params)
53 {
54 //TODO: should obviously not waste space in struct region for this.
55 /*
56 * reset the counter on the region, then use it to store the number of
57 * players there.
58 * I don't know how thread-safe this would be, I suspect not very....
59 */
60 for_all_regions (rgn)
61 rgn->counter = 0;
62
63 for_all_players (pl)
64 if (pl->ob->map)
65 ++pl->ob->region ()->counter;
66
67 /* we only want to print out by places with a 'longname' field... */
68 for_all_regions (rgn)
69 {
70 if (!rgn->longname && rgn->counter > 0)
71 {
72 if (rgn->parent)
73 {
74 rgn->parent->counter += rgn->counter;
75 rgn->counter = 0;
76 }
77 else /*uh oh, we shouldn't be here. */
78 LOG (llevError, "command_whereabouts() Region %s with no longname has no parent", &rgn->name);
79 }
80 }
81
82 new_draw_info_format (NDI_UNIQUE, 0, op, "In the world currently there are:");
83
84 for_all_regions (rgn)
85 if (rgn->counter)
86 new_draw_info_format (NDI_UNIQUE, 0, op, "%u players %s", rgn->counter, &rgn->longname);
87
88 return 1;
89 }
90
91 typedef struct
92 {
93 char namebuf[MAX_BUF];
94 int login_order;
95 } chars_names;
96
97 int
98 command_time (object *op, char *params)
99 {
100 print_tod (op);
101 return 1;
102 }
103
104 int
105 command_weather (object *op, char *params)
106 {
107 #if 0
108 int wx, wy, temp, sky;
109 char buf[MAX_BUF];
110
111 if (settings.dynamiclevel < 1)
112 return 1;
113
114 if (op->map == NULL)
115 return 1;
116
117 if (worldmap_to_weathermap (op->x, op->y, &wx, &wy, op->map) != 0)
118 return 1;
119
120 if (QUERY_FLAG (op, FLAG_WIZ))
121 {
122 /* dump the weather, Dm style! Yo! */
123 new_draw_info_format (NDI_UNIQUE, 0, op, "Real temp: %d", real_world_temperature (op->x, op->y, op->map));
124 new_draw_info_format (NDI_UNIQUE, 0, op, "Base temp: %d", weathermap[wx][wy].temp);
125 new_draw_info_format (NDI_UNIQUE, 0, op, "Humid: %d", weathermap[wx][wy].humid);
126 new_draw_info_format (NDI_UNIQUE, 0, op, "Wind: dir=%d speed=%d", weathermap[wx][wy].winddir, weathermap[wx][wy].windspeed);
127 new_draw_info_format (NDI_UNIQUE, 0, op, "Pressure: %d", weathermap[wx][wy].pressure);
128 new_draw_info_format (NDI_UNIQUE, 0, op, "Avg Elevation: %d", weathermap[wx][wy].avgelev);
129 new_draw_info_format (NDI_UNIQUE, 0, op, "Rainfall: %d Water: %d", weathermap[wx][wy].rainfall, weathermap[wx][wy].water);
130 }
131
132 temp = real_world_temperature (op->x, op->y, op->map);
133 new_draw_info_format (NDI_UNIQUE, 0, op, "It's currently %d degrees " "Centigrade out.", temp);
134
135 /* humid */
136 if (weathermap[wx][wy].humid < 20)
137 new_draw_info (NDI_UNIQUE, 0, op, "It is very dry.");
138 else if (weathermap[wx][wy].humid < 40)
139 new_draw_info (NDI_UNIQUE, 0, op, "It is very comfortable today.");
140 else if (weathermap[wx][wy].humid < 60)
141 new_draw_info (NDI_UNIQUE, 0, op, "It is a bit muggy.");
142 else if (weathermap[wx][wy].humid < 80)
143 new_draw_info (NDI_UNIQUE, 0, op, "It is muggy.");
144 else
145 new_draw_info (NDI_UNIQUE, 0, op, "It is uncomfortably muggy.");
146
147 /* wind */
148 switch (weathermap[wx][wy].winddir)
149 {
150 case 1:
151 sprintf (buf, "north");
152 break;
153 case 2:
154 sprintf (buf, "northeast");
155 break;
156 case 3:
157 sprintf (buf, "east");
158 break;
159 case 4:
160 sprintf (buf, "southeast");
161 break;
162 case 5:
163 sprintf (buf, "south");
164 break;
165 case 6:
166 sprintf (buf, "southwest");
167 break;
168 case 7:
169 sprintf (buf, "west");
170 break;
171 case 8:
172 sprintf (buf, "northwest");
173 break;
174 }
175 if (weathermap[wx][wy].windspeed < 5)
176 new_draw_info_format (NDI_UNIQUE, 0, op, "There is a mild breeze " "coming from the %s.", buf);
177 else if (weathermap[wx][wy].windspeed < 10)
178 new_draw_info_format (NDI_UNIQUE, 0, op, "There is a strong breeze " "coming from the %s.", buf);
179 else if (weathermap[wx][wy].windspeed < 15)
180 new_draw_info_format (NDI_UNIQUE, 0, op, "There is a light wind " "coming from the %s.", buf);
181 else if (weathermap[wx][wy].windspeed < 25)
182 new_draw_info_format (NDI_UNIQUE, 0, op, "There is a strong wind " "coming from the %s.", buf);
183 else if (weathermap[wx][wy].windspeed < 35)
184 new_draw_info_format (NDI_UNIQUE, 0, op, "There is a heavy wind " "coming from the %s.", buf);
185 else
186 new_draw_info_format (NDI_UNIQUE, 0, op, "The wind from the %s is " "incredibly strong!", buf);
187
188 sky = weathermap[wx][wy].sky;
189 if (temp <= 0 && sky > SKY_OVERCAST && sky < SKY_FOG)
190 sky += 10; /*let it snow */
191 switch (sky)
192 {
193 case SKY_CLEAR:
194 new_draw_info (NDI_UNIQUE, 0, op, "There isn''t a cloud in the sky.");
195 break;
196 case SKY_LIGHTCLOUD:
197 new_draw_info (NDI_UNIQUE, 0, op, "There are a few light clouds in the sky.");
198 break;
199 case SKY_OVERCAST:
200 new_draw_info (NDI_UNIQUE, 0, op, "The sky is cloudy and dreary.");
201 break;
202 case SKY_LIGHT_RAIN:
203 new_draw_info (NDI_UNIQUE, 0, op, "It is raining softly.");
204 break;
205 case SKY_RAIN:
206 new_draw_info (NDI_UNIQUE, 0, op, "It is raining.");
207 break;
208 case SKY_HEAVY_RAIN:
209 new_draw_info (NDI_UNIQUE, 0, op, "It is raining heavily.");
210 break;
211 case SKY_HURRICANE:
212 new_draw_info (NDI_UNIQUE, 0, op, "There is a heavy storm! You should go inside!");
213 break;
214 case SKY_FOG:
215 new_draw_info (NDI_UNIQUE, 0, op, "It''s foggy and miserable.");
216 break;
217 case SKY_HAIL:
218 new_draw_info (NDI_UNIQUE, 0, op, "It''s hailing out! Take cover!");
219 break;
220 case SKY_LIGHT_SNOW:
221 new_draw_info (NDI_UNIQUE, 0, op, "Snow is gently falling from the sky.");
222 break;
223 case SKY_SNOW:
224 new_draw_info (NDI_UNIQUE, 0, op, "It''s snowing out.");
225 break;
226 case SKY_HEAVY_SNOW:
227 new_draw_info (NDI_UNIQUE, 0, op, "The snow is falling very heavily now.");
228 break;
229 case SKY_BLIZZARD:
230 new_draw_info (NDI_UNIQUE, 0, op, "A full blown blizzard is in effect. You might want to take cover!");
231 break;
232 }
233 #endif
234 return 1;
235 }
236
237 int
238 command_hiscore (object *op, char *params)
239 {
240 display_high_score (op, op == NULL ? 9999 : 50, params);
241 return 1;
242 }
243
244 int
245 command_debug (object *op, char *params)
246 {
247 int i;
248 char buf[MAX_BUF];
249
250 if (params == NULL || !sscanf (params, "%d", &i))
251 {
252 sprintf (buf, "Global debug level is %d.", settings.debug);
253 new_draw_info (NDI_UNIQUE, 0, op, buf);
254 return 1;
255 }
256
257 settings.debug = i;
258
259 sprintf (buf, "Set debug level to %d.", i);
260 new_draw_info (NDI_UNIQUE, 0, op, buf);
261 return 1;
262 }
263
264
265 /*
266 * Those dumps should be just one dump with good parser
267 */
268
269 int
270 command_dumpbelow (object *op, char *params)
271 {
272 if (op && op->below)
273 {
274 char *dump = dump_object (op->below);
275 new_draw_info (NDI_UNIQUE, 0, op, dump);
276 free (dump);
277 /* Let's push that item on the dm's stack */
278 dm_stack_push (op->contr, op->below->count);
279 }
280 return 0;
281 }
282
283 int
284 command_dumpfriendlyobjects (object *op, char *params)
285 {
286 dump_friendly_objects ();
287 return 0;
288 }
289
290 int
291 command_printlos (object *op, char *params)
292 {
293 if (op)
294 print_los (op);
295 return 0;
296 }
297
298
299 int
300 command_version (object *op, char *params)
301 {
302 version (op);
303 return 0;
304 }
305
306 #ifndef BUG_LOG
307 # define BUG_LOG "bug_log"
308 #endif
309 void
310 bug_report (const char *reportstring)
311 {
312 FILE *fp;
313
314 if ((fp = fopen (BUG_LOG, "a")) != NULL)
315 {
316 fprintf (fp, "%s\n", reportstring);
317 fclose (fp);
318 }
319 else
320 {
321 LOG (llevError, "Cannot write bugs file %s: %s\n", BUG_LOG, strerror (errno));
322 }
323 }
324
325 /* Prints out some useful information for the character. Everything we print
326 * out can be determined by the docs, so we aren't revealing anything extra -
327 * rather, we are making it convenient to find the values. params have
328 * no meaning here.
329 */
330 int
331 command_statistics (object *pl, char *params)
332 {
333 if (!pl->contr)
334 return 1;
335 new_draw_info_format (NDI_UNIQUE, 0, pl, " Experience: %" PRId64, pl->stats.exp);
336 new_draw_info_format (NDI_UNIQUE, 0, pl, " Next Level: %" PRId64, level_exp (pl->level + 1, pl->expmul));
337 new_draw_info (NDI_UNIQUE, 0, pl, "\nStat Nat/Real/Max");
338
339 new_draw_info_format (NDI_UNIQUE, 0, pl, "Str %2d/ %3d/%3d",
340 pl->contr->orig_stats.Str, pl->stats.Str, 20 + pl->arch->stats.Str);
341 new_draw_info_format (NDI_UNIQUE, 0, pl, "Dex %2d/ %3d/%3d",
342 pl->contr->orig_stats.Dex, pl->stats.Dex, 20 + pl->arch->stats.Dex);
343 new_draw_info_format (NDI_UNIQUE, 0, pl, "Con %2d/ %3d/%3d",
344 pl->contr->orig_stats.Con, pl->stats.Con, 20 + pl->arch->stats.Con);
345 new_draw_info_format (NDI_UNIQUE, 0, pl, "Int %2d/ %3d/%3d",
346 pl->contr->orig_stats.Int, pl->stats.Int, 20 + pl->arch->stats.Int);
347 new_draw_info_format (NDI_UNIQUE, 0, pl, "Wis %2d/ %3d/%3d",
348 pl->contr->orig_stats.Wis, pl->stats.Wis, 20 + pl->arch->stats.Wis);
349 new_draw_info_format (NDI_UNIQUE, 0, pl, "Pow %2d/ %3d/%3d",
350 pl->contr->orig_stats.Pow, pl->stats.Pow, 20 + pl->arch->stats.Pow);
351 new_draw_info_format (NDI_UNIQUE, 0, pl, "Cha %2d/ %3d/%3d",
352 pl->contr->orig_stats.Cha, pl->stats.Cha, 20 + pl->arch->stats.Cha);
353 new_draw_info_format (NDI_UNIQUE, 0, pl, "\nAttack Mode: %s", pl->contr->peaceful ? "Peaceful" : "Hostile");
354
355 /* Can't think of anything else to print right now */
356 return 0;
357 }
358
359 int
360 command_fix_me (object *op, char *params)
361 {
362 sum_weight (op);
363 op->update_stats ();
364 new_draw_info (NDI_UNIQUE, 0, op, "Your character was fixed.");
365
366 return 1;
367 }
368
369 int
370 command_logs (object *op, char *params)
371 {
372 new_draw_info (NDI_UNIQUE, 0, op, "Nobody is currently logging kills.");
373
374 return 1;
375 }
376
377 int
378 command_bowmode (object *op, char *params)
379 {
380 bowtype_t oldtype = op->contr->bowtype;
381 static const char *const types[] = { "normal", "threewide", "spreadshot", "firenorth",
382 "firene", "fireeast", "firese", "firesouth",
383 "firesw", "firewest", "firenw", "bestarrow"
384 };
385 char buf[MAX_BUF];
386 int i, found;
387
388 if (!params)
389 {
390 new_draw_info_format (NDI_UNIQUE, 0, op, "bowmode is set to %s", types[op->contr->bowtype]);
391 return 1;
392 }
393
394 for (i = 0, found = 0; i <= bow_bestarrow; i++)
395 {
396 if (!strcmp (params, types[i]))
397 {
398 found++;
399 op->contr->bowtype = (bowtype_t) i;
400 break;
401 }
402 }
403
404 if (!found)
405 {
406 sprintf (buf, "bowmode: Unknown options %s, valid options are:", params);
407 for (i = 0; i <= bow_bestarrow; i++)
408 {
409 strcat (buf, " ");
410 strcat (buf, types[i]);
411 if (i < bow_nw)
412 strcat (buf, ",");
413 else
414 strcat (buf, ".");
415 }
416 new_draw_info_format (NDI_UNIQUE, 0, op, buf);
417 return 0;
418 }
419
420 new_draw_info_format (NDI_UNIQUE, 0, op, "bowmode %s set to %s", (oldtype == op->contr->bowtype ? "" : "now"), types[op->contr->bowtype]);
421 return 1;
422 }
423
424 int
425 command_showpets (object *op, char *params)
426 {
427 objectlink *obl, *next;
428 int counter = 0, target = 0;
429 int have_shown_pet = 0;
430
431 if (params != NULL)
432 target = atoi (params);
433 for (obl = first_friendly_object; obl != NULL; obl = next)
434 {
435 object *ob = obl->ob;
436
437 next = obl->next;
438 if (ob->owner == op)
439 {
440 if (target == 0)
441 {
442 if (counter == 0)
443 new_draw_info (NDI_UNIQUE, 0, op, "Pets:");
444 new_draw_info_format (NDI_UNIQUE, 0, op, "%d %s - level %d", ++counter, &ob->name, ob->level);
445 }
446 else if (!have_shown_pet && ++counter == target)
447 {
448 new_draw_info_format (NDI_UNIQUE, 0, op, "level %d %s", ob->level, &ob->name);
449 new_draw_info_format (NDI_UNIQUE, 0, op, "%d/%d HP, %d/%d SP", ob->stats.hp, ob->stats.maxhp, ob->stats.sp, ob->stats.maxsp);
450 /* this is not a nice way to do this, it should be made to be more like the statistics command */
451 new_draw_info_format (NDI_UNIQUE, 0, op, "Str %d", ob->stats.Str);
452 new_draw_info_format (NDI_UNIQUE, 0, op, "Dex %d", ob->stats.Dex);
453 new_draw_info_format (NDI_UNIQUE, 0, op, "Con %d", ob->stats.Con);
454 new_draw_info_format (NDI_UNIQUE, 0, op, "Int %d", ob->stats.Int);
455 new_draw_info_format (NDI_UNIQUE, 0, op, "Wis %d", ob->stats.Wis);
456 new_draw_info_format (NDI_UNIQUE, 0, op, "Cha %d", ob->stats.Cha);
457 new_draw_info_format (NDI_UNIQUE, 0, op, "Pow %d", ob->stats.Pow);
458 new_draw_info_format (NDI_UNIQUE, 0, op, "wc %d damage %d ac %d ", ob->stats.wc, ob->stats.dam, ob->stats.ac);
459 have_shown_pet = 1;
460 }
461 }
462 }
463 if (counter == 0)
464 new_draw_info (NDI_UNIQUE, 0, op, "you have no pets.");
465 else if (target != 0 && have_shown_pet == 0)
466 new_draw_info (NDI_UNIQUE, 0, op, "no such pet.");
467 return 0;
468 }
469
470 int
471 command_resistances (object *op, char *params)
472 {
473 int i;
474
475 if (!op)
476 return 0;
477
478 for (i = 0; i < NROFATTACKS; i++)
479 {
480 if (i == ATNR_INTERNAL)
481 continue;
482
483 new_draw_info_format (NDI_UNIQUE, 0, op, "%-20s %+5d", attacktype_desc[i], op->resist[i]);
484 }
485
486 /* If dragon player, let's display natural resistances */
487 if (is_dragon_pl (op))
488 {
489 int attack;
490 object *tmp;
491
492 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
493 {
494 if ((tmp->type == FORCE) && (strcmp (tmp->arch->archname, "dragon_skin_force") == 0))
495 {
496 new_draw_info (NDI_UNIQUE, 0, op, "\nNatural skin resistances:");
497 for (attack = 0; attack < NROFATTACKS; attack++)
498 {
499 if (atnr_is_dragon_enabled (attack))
500 {
501 new_draw_info_format (NDI_UNIQUE, 0, op, "%s: %d", change_resist_msg[attack], tmp->resist[attack]);
502 }
503 }
504 break;
505 }
506 }
507 }
508
509 return 0;
510 }
511
512 /*
513 * Actual commands.
514 * Those should be in small separate files (c_object.c, c_wiz.c, cmove.c,...)
515 */
516
517 int
518 onoff_value (const char *line)
519 {
520 int i;
521
522 if (sscanf (line, "%d", &i))
523 return (i != 0);
524 switch (line[0])
525 {
526 case 'o':
527 switch (line[1])
528 {
529 case 'n':
530 return 1; /* on */
531 default:
532 return 0; /* o[ff] */
533 }
534 case 'y': /* y[es] */
535 case 'k': /* k[ylla] */
536 case 's':
537 case 'd':
538 return 1;
539 case 'n': /* n[o] */
540 case 'e': /* e[i] */
541 case 'u':
542 default:
543 return 0;
544 }
545 }
546
547 int
548 command_title (object *op, char *params)
549 {
550 char buf[MAX_BUF];
551
552 if (settings.set_title == FALSE)
553 {
554 new_draw_info (NDI_UNIQUE, 0, op, "You cannot change your title.");
555 return 1;
556 }
557
558 /* dragon players cannot change titles */
559 if (is_dragon_pl (op))
560 {
561 new_draw_info (NDI_UNIQUE, 0, op, "Dragons cannot change titles.");
562 return 1;
563 }
564
565 if (params == NULL)
566 {
567 if (op->contr->own_title[0] == '\0')
568 sprintf (buf, "Your title is '%s'.", op->contr->title);
569 else
570 sprintf (buf, "Your title is '%s'.", op->contr->own_title);
571 new_draw_info (NDI_UNIQUE, 0, op, buf);
572 return 1;
573 }
574 if (strcmp (params, "clear") == 0 || strcmp (params, "default") == 0)
575 {
576 if (op->contr->own_title[0] == '\0')
577 new_draw_info (NDI_UNIQUE, 0, op, "Your title is the default title.");
578 else
579 new_draw_info (NDI_UNIQUE, 0, op, "Title set to default.");
580 op->contr->own_title[0] = '\0';
581 return 1;
582 }
583
584 if ((int) strlen (params) >= MAX_NAME)
585 {
586 new_draw_info (NDI_UNIQUE, 0, op, "Title too long.");
587 return 1;
588 }
589 strcpy (op->contr->own_title, params);
590 return 1;
591 }
592
593 int
594 command_kill_pets (object *op, char *params)
595 {
596 objectlink *obl, *next;
597 int counter = 0, removecount = 0;
598
599 if (!params)
600 {
601 terminate_all_pets (op);
602 new_draw_info (NDI_UNIQUE, 0, op, "Your pets have been killed.");
603 }
604 else
605 {
606 int target = atoi (params);
607
608 for (obl = first_friendly_object; obl; obl = next)
609 {
610 object *ob = obl->ob;
611
612 next = obl->next;
613
614 if (ob->owner == op)
615 if (++counter == target || (target == 0 && !strcasecmp (ob->name, params)))
616 {
617 ob->destroy ();
618 removecount++;
619 }
620 }
621
622 if (removecount != 0)
623 new_draw_info_format (NDI_UNIQUE, 0, op, "killed %d pets.\n", removecount);
624 else
625 new_draw_info (NDI_UNIQUE, 0, op, "Couldn't find any suitable pets to kill.\n");
626 }
627
628 return 0;
629 }