Atrinik Server  4.0
item.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program 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 2 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, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <player.h>
32 #include <object.h>
33 
35 static char numbers[21][20] = {
36  "",
37  "",
38  "two ",
39  "three ",
40  "four ",
41  "five ",
42  "six ",
43  "seven ",
44  "eight ",
45  "nine ",
46  "ten ",
47  "eleven ",
48  "twelve ",
49  "thirteen ",
50  "fourteen ",
51  "fifteen ",
52  "sixteen ",
53  "seventeen ",
54  "eighteen ",
55  "nineteen ",
56  "twenty "
57 };
58 
71 StringBuffer *object_get_material(const object *op, const object *caller,
72  StringBuffer *sb)
73 {
74  HARD_ASSERT(op != NULL);
75 
76  if (sb == NULL) {
77  sb = stringbuffer_new();
78  }
79 
80  /* Named objects do not show the material name. */
81  if (QUERY_FLAG(op, FLAG_IS_NAMED)) {
82  return sb;
83  }
84 
85  if (!IS_LIVE(op) && op->type != BASE_INFO &&
86  op->item_race < NROF_ITEM_RACES) {
87  stringbuffer_append_string(sb, item_races[op->item_race]);
88  }
89 
90  if (op->material_real > 0 && op->material_real < NUM_MATERIALS_REAL &&
92  stringbuffer_append_string(sb, materials_real[op->material_real].name);
93  }
94 
95  return sb;
96 }
97 
107 char *object_get_material_s(const object *op, const object *caller)
108 {
109  return stringbuffer_finish(object_get_material(op, caller, NULL));
110 }
111 
124 StringBuffer *object_get_title(const object *op, const object *caller,
125  StringBuffer *sb)
126 {
127  HARD_ASSERT(op != NULL);
128 
129  if (sb == NULL) {
130  sb = stringbuffer_new();
131  }
132 
133  switch (op->type) {
134  case CONTAINER:
135  if (op->title != NULL && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
136  stringbuffer_append_printf(sb, " %s", op->title);
137  }
138 
141  if (op->slaying != NULL) {
142  if (caller == NULL || caller->type != PLAYER) {
143  stringbuffer_append_string(sb, " (bounty of a party)");
144  } else if (CONTR(caller)->party != NULL &&
145  CONTR(caller)->party->name == op->slaying) {
146  stringbuffer_append_string(sb,
147  " (bounty of your party");
148 
149  /* A searched bounty */
150  if (QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
151  stringbuffer_append_string(sb, ", searched");
152 
153  if (op->inv == NULL) {
154  stringbuffer_append_string(sb, ", empty");
155  }
156  }
157 
158  stringbuffer_append_string(sb, ")");
159  } else {
160  /* It's a different party */
161  stringbuffer_append_string(sb,
162  " (bounty of another party)");
163  }
164  } else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
165  stringbuffer_append_string(sb, " (searched");
166 
167  if (op->inv == NULL) {
168  stringbuffer_append_string(sb, ", empty");
169  }
170 
171  stringbuffer_append_string(sb, ")");
172  }
173  }
174  } else if (op->sub_type >= ST1_CONTAINER_NORMAL_player) {
176  if (op->slaying != NULL) {
177  stringbuffer_append_printf(sb, " (bounty of %s",
178  op->slaying);
179 
180  /* A searched bounty */
181  if ((caller != NULL && caller->name == op->slaying) &&
183  stringbuffer_append_string(sb, ", searched");
184 
185  if (op->inv == NULL) {
186  stringbuffer_append_string(sb, ", empty");
187  }
188  }
189 
190  stringbuffer_append_string(sb, ")");
191  } else if (QUERY_FLAG(op, FLAG_BEEN_APPLIED)) {
192  stringbuffer_append_string(sb, " (searched");
193 
194  if (op->inv == NULL) {
195  stringbuffer_append_string(sb, ", empty");
196  }
197 
198  stringbuffer_append_string(sb, ")");
199  }
200  }
201  }
202 
203  break;
204 
205  case SCROLL:
206  case WAND:
207  case ROD:
208  case POTION:
209  case BOOK_SPELL:
210  if (QUERY_FLAG(op, FLAG_IDENTIFIED) ||
212  if (op->title == NULL) {
213  stringbuffer_append_string(sb, " of ");
214 
215  if (op->stats.sp >= 0 && op->stats.sp < NROFREALSPELLS) {
216  stringbuffer_append_string(sb, spells[op->stats.sp].name);
217  } else {
218  stringbuffer_append_string(sb, "nothing");
219  }
220  } else {
221  stringbuffer_append_printf(sb, " %s", op->title);
222  }
223 
224  if (op->type != BOOK_SPELL) {
225  stringbuffer_append_printf(sb, " (lvl %" PRId8 ")", op->level);
226  }
227  }
228 
229  break;
230 
231  case SKILL:
232  case AMULET:
233  case RING:
234  case TRINKET:
235  if (QUERY_FLAG(op, FLAG_IDENTIFIED)) {
236  /* If ring has a title, full description isn't so useful. */
237  if (op->title == NULL) {
238  stringbuffer_append_string(sb, " ");
239  size_t len = stringbuffer_length(sb);
240  sb = object_get_description(op, caller, sb);
241  if (stringbuffer_length(sb) == len) {
242  stringbuffer_seek(sb, len - 1);
243  }
244  } else {
245  stringbuffer_append_printf(sb, " %s", op->title);
246  }
247  }
248 
249  break;
250 
251  default:
252  if (op->magic != 0 && (!need_identify(op) ||
254  QUERY_FLAG(op, FLAG_IDENTIFIED))) {
255  if (!IS_LIVE(op) && op->type != BASE_INFO) {
256  stringbuffer_append_printf(sb, " %+" PRId8, op->magic);
257  }
258  }
259 
260  if (op->title != NULL && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
261  stringbuffer_append_printf(sb, " %s", op->title);
262  }
263 
264  if ((op->type == ARROW || op->type == WEAPON) && op->slaying != NULL &&
266  stringbuffer_append_printf(sb, " %s", op->slaying);
267  }
268  }
269 
270  return sb;
271 }
272 
282 char *object_get_title_s(const object *op, const object *caller)
283 {
284  return stringbuffer_finish(object_get_title(op, caller, NULL));
285 }
286 
299 StringBuffer *object_get_name(const object *op, const object *caller,
300  StringBuffer *sb)
301 {
302  HARD_ASSERT(op != NULL);
303 
304  sb = object_get_short_name(op, caller, sb);
305 
306  if (QUERY_FLAG(op, FLAG_ONE_DROP)) {
307  stringbuffer_append_string(sb, " (one-drop)");
308  } else if (QUERY_FLAG(op, FLAG_QUEST_ITEM)) {
309  stringbuffer_append_string(sb, " (quest)");
310  }
311 
312  if (QUERY_FLAG(op, FLAG_SOULBOUND)) {
313  stringbuffer_append_string(sb, " (soulbound)");
314  }
315 
316  if (QUERY_FLAG(op, FLAG_INV_LOCKED)) {
317  stringbuffer_append_string(sb, " *");
318  }
319 
320  if (op->type == CONTAINER && QUERY_FLAG(op, FLAG_APPLIED)) {
321  if (op->attacked_by != NULL && op->attacked_by->type == PLAYER) {
322  stringbuffer_append_string(sb, " (open)");
323  } else {
324  stringbuffer_append_string(sb, " (ready)");
325  }
326  }
327 
329  if (QUERY_FLAG(op, FLAG_PERM_DAMNED)) {
330  stringbuffer_append_string(sb, " (perm. damned)");
331  } else if (QUERY_FLAG(op, FLAG_DAMNED)) {
332  stringbuffer_append_string(sb, " (damned)");
333  } else if (QUERY_FLAG(op, FLAG_PERM_CURSED)) {
334  stringbuffer_append_string(sb, " (perm. cursed)");
335  } else if (QUERY_FLAG(op, FLAG_CURSED)) {
336  stringbuffer_append_string(sb, " (cursed)");
337  }
338  }
339 
341  stringbuffer_append_string(sb, " (magical)");
342  }
343 
344  if (QUERY_FLAG(op, FLAG_APPLIED)) {
345  switch (op->type) {
346  case BOW:
347  case WAND:
348  case ROD:
349  stringbuffer_append_string(sb, " (readied)");
350  break;
351 
352  case WEAPON:
353  stringbuffer_append_string(sb, " (wielded)");
354  break;
355 
356  case ARMOUR:
357  case HELMET:
358  case SHIELD:
359  case RING:
360  case BOOTS:
361  case GLOVES:
362  case AMULET:
363  case GIRDLE:
364  case BRACERS:
365  case CLOAK:
366  case PANTS:
367  case TRINKET:
368  stringbuffer_append_string(sb, " (worn)");
369  break;
370 
371  case CONTAINER:
372  stringbuffer_append_string(sb, " (active)");
373  break;
374 
375  case SKILL:
376  case SKILL_ITEM:
377  default:
378  stringbuffer_append_string(sb, " (applied)");
379  }
380  }
381 
382  if (QUERY_FLAG(op, FLAG_UNPAID)) {
383  stringbuffer_append_string(sb, " (unpaid)");
384  }
385 
386  return sb;
387 }
388 
398 char *object_get_name_s(const object *op, const object *caller)
399 {
400  return stringbuffer_finish(object_get_name(op, caller, NULL));
401 }
402 
416 StringBuffer *object_get_short_name(const object *op, const object *caller,
417  StringBuffer *sb)
418 {
419  HARD_ASSERT(op != NULL);
420 
421  if (sb == NULL) {
422  sb = stringbuffer_new();
423  }
424 
425  if (op->name == NULL) {
426  return sb;
427  }
428 
429  if (op->nrof != 0) {
430  if (op->nrof <= 20) {
431  stringbuffer_append_string(sb, numbers[op->nrof]);
432  } else {
433  stringbuffer_append_printf(sb, "%" PRIu32 " ", op->nrof);
434  }
435  }
436 
437  sb = object_get_material(op, caller, sb);
438  stringbuffer_append_string(sb, op->name);
439  sb = object_get_title(op, caller, sb);
440 
441  return sb;
442 }
443 
453 char *object_get_short_name_s(const object *op, const object *caller)
454 {
455  return stringbuffer_finish(object_get_short_name(op, caller, NULL));
456 }
457 
471 StringBuffer *object_get_material_name(const object *op, const object *caller,
472  StringBuffer *sb)
473 {
474  HARD_ASSERT(op != NULL);
475 
476  sb = object_get_material(op, caller, sb);
477  stringbuffer_append_string(sb, op->name);
478 
479  if (op->title != NULL && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
480  stringbuffer_append_printf(sb, " %s", op->title);
481  }
482 
483  return sb;
484 }
485 
495 char *object_get_material_name_s(const object *op, const object *caller)
496 {
497  return stringbuffer_finish(object_get_material_name(op, caller, NULL));
498 }
499 
513 StringBuffer *object_get_base_name(const object *op, const object *caller,
514  StringBuffer *sb)
515 {
516  HARD_ASSERT(op != NULL);
517 
518  sb = object_get_material(op, caller, sb);
519  stringbuffer_append_string(sb, op->name);
520  sb = object_get_title(op, caller, sb);
521 
522  return sb;
523 }
524 
534 char *object_get_base_name_s(const object *op, const object *caller)
535 {
536  return stringbuffer_finish(object_get_base_name(op, caller, NULL));
537 }
538 
551 StringBuffer *object_get_description_terrain(const object *op,
552  const object *caller, StringBuffer *sb)
553 {
554  HARD_ASSERT(op != NULL);
555 
556  if (sb == NULL) {
557  sb = stringbuffer_new();
558  }
559 
560  if (op->terrain_flag == 0) {
561  return sb;
562  }
563 
564  stringbuffer_append_string(sb, "(");
565  size_t old_len = stringbuffer_length(sb);
566 
567  if (op->terrain_flag & TERRAIN_AIRBREATH) {
568  stringbuffer_append_string(sb, "air breathing, ");
569  }
570 
571  if (op->terrain_flag & TERRAIN_WATERWALK) {
572  stringbuffer_append_string(sb, "water walking, ");
573  }
574 
575  if (op->terrain_flag & TERRAIN_FIREWALK) {
576  stringbuffer_append_string(sb, "fire walking, ");
577  }
578 
579  if (op->terrain_flag & TERRAIN_CLOUDWALK) {
580  stringbuffer_append_string(sb, "cloud walking, ");
581  }
582 
583  if (op->terrain_flag & TERRAIN_WATERBREATH) {
584  stringbuffer_append_string(sb, "water breathing, ");
585  }
586 
587  if (op->terrain_flag & TERRAIN_FIREBREATH) {
588  stringbuffer_append_string(sb, "fire breathing, ");
589  }
590 
592  stringbuffer_append_string(sb, "shallow water walking, ");
593  }
594 
595  size_t len = stringbuffer_length(sb);
596  if (len - old_len >= 2) {
597  stringbuffer_seek(sb, len - 2);
598  } else {
599  stringbuffer_append_string(sb, "unknown terrain");
600  }
601 
602  stringbuffer_append_string(sb, ") ");
603 
604  return sb;
605 }
606 
616 char *object_get_description_terrain_s(const object *op, const object *caller)
617 {
618  return stringbuffer_finish(object_get_description_terrain(op, caller,
619  NULL));
620 }
621 
634 StringBuffer *object_get_description_attacks(const object *op,
635  const object *caller, StringBuffer *sb)
636 {
637  HARD_ASSERT(op != NULL);
638 
639  if (sb == NULL) {
640  sb = stringbuffer_new();
641  }
642 
643  bool got_one = false;
644  for (int i = 0; i < NROFATTACKS; i++) {
645  if (op->attack[i] == 0) {
646  continue;
647  }
648 
649  if (!got_one) {
650  stringbuffer_append_string(sb, "(Attacks: ");
651  }
652 
653  if (got_one) {
654  stringbuffer_append_string(sb, ", ");
655  }
656 
657  stringbuffer_append_printf(sb, "%s +%" PRIu8 "%%", attack_name[i],
658  op->attack[i]);
659  got_one = true;
660  }
661 
662  if (got_one) {
663  stringbuffer_append_string(sb, ") ");
664  }
665 
666  return sb;
667 }
668 
678 char *object_get_description_attacks_s(const object *op, const object *caller)
679 {
680  return stringbuffer_finish(object_get_description_attacks(op, caller,
681  NULL));
682 }
683 
696 StringBuffer *object_get_description_protections(const object *op,
697  const object *caller, StringBuffer *sb)
698 {
699  HARD_ASSERT(op != NULL);
700 
701  if (sb == NULL) {
702  sb = stringbuffer_new();
703  }
704 
705  bool got_one = false;
706  for (int i = 0; i < NROFATTACKS; i++) {
707  if (op->protection[i] == 0) {
708  continue;
709  }
710 
711  if (!got_one) {
712  stringbuffer_append_string(sb, "(Protections: ");
713  }
714 
715  if (got_one) {
716  stringbuffer_append_string(sb, ", ");
717  }
718 
719  stringbuffer_append_printf(sb, "%s %+" PRId8 "%%", attack_name[i],
720  op->protection[i]);
721  got_one = true;
722  }
723 
724  if (got_one) {
725  stringbuffer_append_string(sb, ") ");
726  }
727 
728  return sb;
729 }
730 
741  const object *caller)
742 {
743  return stringbuffer_finish(object_get_description_protections(op, caller,
744  NULL));
745 }
746 
763 StringBuffer *object_get_description_path(const object *op, const
764  object *caller, const uint32_t path, const char *name, StringBuffer *sb)
765 {
766  HARD_ASSERT(op != NULL);
767 
768  if (sb == NULL) {
769  sb = stringbuffer_new();
770  }
771 
772  if (path == 0) {
773  return sb;
774  }
775 
776  stringbuffer_append_printf(sb, "(%s: ", name);
777 
778  bool got_one = false;
779  for (int i = 0; i < NRSPELLPATHS; i++) {
780  if (!(path & (1 << i))) {
781  continue;
782  }
783 
784  if (got_one) {
785  stringbuffer_append_string(sb, ", ");
786  } else {
787  got_one = true;
788  }
789 
790  stringbuffer_append_string(sb, spellpathnames[i]);
791  }
792 
793  stringbuffer_append_string(sb, ") ");
794 
795  return sb;
796 }
797 
811 char *object_get_description_path_s(const object *op, const object *caller,
812  const uint32_t path, const char *name)
813 {
814  return stringbuffer_finish(object_get_description_path(op, caller, path,
815  name, NULL));
816 }
817 
839 StringBuffer *object_get_description(const object *op, const object *caller,
840  StringBuffer *sb)
841 {
842  HARD_ASSERT(op != NULL);
843 
844  if (sb == NULL) {
845  sb = stringbuffer_new();
846  }
847 
848  size_t old_len = stringbuffer_length(sb);
849  bool identified = false, more_info = false;
850 
851  if (op->type == PLAYER) {
852  sb = object_get_description_terrain(op, caller, sb);
853 
854  if (CONTR(op)->digestion != 0) {
855  if (CONTR(op)->digestion > 0) {
856  stringbuffer_append_printf(sb, "(sustenance%+d) ",
857  CONTR(op)->digestion);
858  } else {
859  stringbuffer_append_printf(sb, "(hunger%+d) ",
860  -CONTR(op)->digestion);
861  }
862  }
863 
864  if (CONTR(op)->gen_client_hp != 0) {
865  stringbuffer_append_printf(sb, "(hp reg. %3.1f) ",
866  CONTR(op)->gen_client_hp / 10.0);
867  }
868 
869  if (CONTR(op)->gen_client_sp != 0) {
870  stringbuffer_append_printf(sb, "(mana reg. %3.1f) ",
871  CONTR(op)->gen_client_sp / 10.0);
872  }
873  } else if (QUERY_FLAG(op, FLAG_MONSTER)) {
874  sb = object_get_description_terrain(op, caller, sb);
875 
876  if (QUERY_FLAG(op, FLAG_UNDEAD)) {
877  stringbuffer_append_string(sb, "(undead) ");
878  }
879 
880  if (QUERY_FLAG(op, FLAG_CAN_PASS_THRU)) {
881  stringbuffer_append_string(sb, "(pass through doors) ");
882  }
883 
884  if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE)) {
885  stringbuffer_append_string(sb, "(see invisible) ");
886  }
887 
888  if (QUERY_FLAG(op, FLAG_USE_WEAPON)) {
889  stringbuffer_append_string(sb, "(wield weapon) ");
890  }
891 
892  if (QUERY_FLAG(op, FLAG_USE_BOW)) {
893  stringbuffer_append_string(sb, "(archer) ");
894  }
895 
896  if (QUERY_FLAG(op, FLAG_USE_ARMOUR)) {
897  stringbuffer_append_string(sb, "(wear armour) ");
898  }
899 
900  if (QUERY_FLAG(op, FLAG_CAST_SPELL)) {
901  stringbuffer_append_string(sb, "(spellcaster) ");
902  }
903 
904  if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
905  stringbuffer_append_string(sb, "(friendly) ");
906  }
907 
908  if (QUERY_FLAG(op, FLAG_UNAGGRESSIVE)) {
909  stringbuffer_append_string(sb, "(unaggressive) ");
910  }
911 
912  if (QUERY_FLAG(op, FLAG_HITBACK)) {
913  stringbuffer_append_string(sb, "(hitback) ");
914  }
915 
916  if (FABS(op->speed) > MIN_ACTIVE_SPEED) {
917  switch ((int) ((FABS(op->speed)) * 15)) {
918  case 0:
919  stringbuffer_append_string(sb, "(very slow movement) ");
920  break;
921 
922  case 1:
923  stringbuffer_append_string(sb, "(slow movement) ");
924  break;
925 
926  case 2:
927  stringbuffer_append_string(sb, "(normal movement) ");
928  break;
929 
930  case 3:
931  case 4:
932  stringbuffer_append_string(sb, "(fast movement) ");
933  break;
934 
935  case 5:
936  case 6:
937  stringbuffer_append_string(sb, "(very fast movement) ");
938  break;
939 
940  case 7:
941  case 8:
942  case 9:
943  case 10:
944  stringbuffer_append_string(sb, "(extremely fast movement) ");
945  break;
946 
947  default:
948  stringbuffer_append_string(sb, "(lightning fast movement) ");
949  break;
950  }
951  }
952  } else {
953  /* We only need calculate this once */
954  if (QUERY_FLAG(op, FLAG_IDENTIFIED) ||
956  !need_identify(op)) {
957  identified = true;
958  }
959 
960  if (identified) {
961  sb = object_get_description_terrain(op, caller, sb);
962 
963  /* Deal with special cases */
964  switch (op->type) {
965  case WAND:
966  case ROD:
967  stringbuffer_append_printf(sb, "(delay%+2.1fs) ",
968  (double) op->last_grace / MAX_TICKS);
969  break;
970 
971  /* Armour type objects */
972  case ARMOUR:
973  case HELMET:
974  case SHIELD:
975  case BOOTS:
976  case GLOVES:
977  case GIRDLE:
978  case BRACERS:
979  case CLOAK:
980  case PANTS:
981  if (ARMOUR_SPEED(op) != 0) {
982  stringbuffer_append_printf(sb, "(speed cap %1.2f) ",
983  ARMOUR_SPEED(op) / 10.0);
984  }
985 
986  if (ARMOUR_SPELLS(op) != 0) {
987  stringbuffer_append_printf(sb, "(armour mana reg %d) ",
988  -ARMOUR_SPELLS(op));
989  }
990 
991  /* Fall through */
992 
993  case WEAPON:
994  case RING:
995  case AMULET:
996  case FORCE:
997  case TRINKET:
998  more_info = 1;
999  /* Fall through */
1000 
1001  case BOW:
1002  case ARROW:
1003  if (op->type == BOW) {
1004  stringbuffer_append_printf(sb, "(delay%+2.1fs) ",
1005  (double) op->stats.sp / MAX_TICKS);
1006  } else if (op->type == ARROW) {
1007  stringbuffer_append_printf(sb, "(delay%+2.1fs) ",
1008  (double) op->last_grace / MAX_TICKS);
1009  }
1010 
1011  if (op->last_sp != 0 && !IS_ARMOR(op)) {
1012  stringbuffer_append_printf(sb, "(range%+d) ", op->last_sp);
1013  }
1014 
1015  if (op->stats.wc != 0) {
1016  stringbuffer_append_printf(sb, "(wc%+d) ", op->stats.wc);
1017  }
1018 
1019  if (op->stats.dam != 0) {
1020  stringbuffer_append_printf(sb, "(dam%+d) ", op->stats.dam);
1021  }
1022 
1023  if (op->stats.ac != 0) {
1024  stringbuffer_append_printf(sb, "(ac%+d) ", op->stats.ac);
1025  }
1026 
1027  if (op->type == WEAPON) {
1028  stringbuffer_append_printf(sb, "(%3.2f sec) ",
1029  (double) op->last_grace / MAX_TICKS);
1030 
1031  if (op->level > 0) {
1032  stringbuffer_append_printf(sb, "(improved %d/%d) ",
1033  op->last_eat, op->level);
1034  }
1035  }
1036 
1037  break;
1038 
1039  case FOOD:
1040  case FLESH:
1041  case DRINK:
1042  {
1043  stringbuffer_append_printf(sb, "(food%+d) ", op->stats.food);
1044 
1045  if (op->stats.hp != 0) {
1046  stringbuffer_append_printf(sb, "(hp%+d) ", op->stats.hp);
1047  }
1048 
1049  if (op->stats.sp != 0) {
1050  stringbuffer_append_printf(sb, "(mana%+d) ", op->stats.sp);
1051  }
1052 
1053  break;
1054  }
1055 
1056  case POTION:
1057  if (op->last_sp) {
1058  stringbuffer_append_printf(sb, "(range%+d) ", op->last_sp);
1059  }
1060 
1061  break;
1062 
1063  case BOOK:
1064  if (op->level) {
1065  stringbuffer_append_printf(sb, "(lvl %d) ", op->level);
1066  }
1067 
1068  if (op->msg != NULL) {
1069  if (QUERY_FLAG(op, FLAG_NO_SKILL_IDENT)) {
1070  stringbuffer_append_string(sb, "(read) ");
1071  } else {
1072  stringbuffer_append_string(sb, "(unread) ");
1073  }
1074  }
1075 
1076  default:
1077  return sb;
1078  }
1079 
1080  for (int attr = 0; attr < NUM_STATS; attr++) {
1081  int8_t val = get_attr_value(&op->stats, attr);
1082  if (val != 0) {
1083  stringbuffer_append_printf(sb, "(%s%+" PRId8 ") ",
1084  short_stat_name[attr], val);
1085  }
1086  }
1087  }
1088  }
1089 
1090  /* Some special info for some identified items */
1091  if (identified && more_info) {
1092  if (op->stats.sp != 0) {
1093  stringbuffer_append_printf(sb, "(mana reg.%+3.1f) ",
1094  op->stats.sp * 0.4);
1095  }
1096 
1097  if (op->stats.hp != 0) {
1098  stringbuffer_append_printf(sb, "(hp reg.%+3.1f) ",
1099  op->stats.hp * 0.4);
1100  }
1101 
1102  if (op->stats.food != 0) {
1103  if (op->stats.food > 0) {
1104  stringbuffer_append_printf(sb, "(sustenance%+d) ",
1105  op->stats.food);
1106  } else {
1107  stringbuffer_append_printf(sb, "(hunger%+d) ",
1108  -op->stats.food);
1109  }
1110  }
1111 
1112  if (op->stats.exp != 0) {
1113  stringbuffer_append_printf(sb, "(speed%+" PRId64 ") ",
1114  op->stats.exp);
1115  }
1116 
1117  if (op->block != 0) {
1118  stringbuffer_append_printf(sb, "(block%+d) ", op->block);
1119  }
1120 
1121  if (op->absorb != 0) {
1122  stringbuffer_append_printf(sb, "(absorb%+d%%) ", op->absorb);
1123  }
1124  }
1125 
1126  /* Here we deal with all the special flags */
1127  if (identified || QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER) {
1128  if (QUERY_FLAG(op, FLAG_SEE_INVISIBLE)) {
1129  stringbuffer_append_string(sb, "(see invisible) ");
1130  }
1131 
1132  if (QUERY_FLAG(op, FLAG_MAKE_ETHEREAL)) {
1133  stringbuffer_append_string(sb, "(makes ethereal) ");
1134  }
1135 
1136  if (QUERY_FLAG(op, FLAG_IS_ETHEREAL)) {
1137  stringbuffer_append_string(sb, "(ethereal) ");
1138  }
1139 
1140  if (QUERY_FLAG(op, FLAG_MAKE_INVISIBLE)) {
1141  stringbuffer_append_string(sb, "(makes invisible) ");
1142  }
1143 
1144  if (QUERY_FLAG(op, FLAG_IS_INVISIBLE)) {
1145  stringbuffer_append_string(sb, "(invisible) ");
1146  }
1147 
1148  if (QUERY_FLAG(op, FLAG_XRAYS)) {
1149  stringbuffer_append_string(sb, "(xray-vision) ");
1150  }
1151 
1152  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK)) {
1153  stringbuffer_append_string(sb, "(infravision) ");
1154  }
1155 
1156  if (QUERY_FLAG(op, FLAG_LIFESAVE)) {
1157  stringbuffer_append_string(sb, "(lifesaving) ");
1158  }
1159 
1160  if (QUERY_FLAG(op, FLAG_REFL_SPELL)) {
1161  stringbuffer_append_string(sb, "(reflect spells) ");
1162  }
1163 
1164  if (QUERY_FLAG(op, FLAG_REFL_MISSILE)) {
1165  stringbuffer_append_string(sb, "(reflect missiles) ");
1166  }
1167 
1168  if (QUERY_FLAG(op, FLAG_STEALTH)) {
1169  stringbuffer_append_string(sb, "(stealth) ");
1170  }
1171 
1172  if (QUERY_FLAG(op, FLAG_FLYING)) {
1173  stringbuffer_append_string(sb, "(flying) ");
1174  }
1175  }
1176 
1177  if (identified) {
1178  if (op->slaying != NULL) {
1179  stringbuffer_append_printf(sb, "(slay %s) ", op->slaying);
1180  }
1181 
1182  sb = object_get_description_attacks(op, caller, sb);
1183  sb = object_get_description_protections(op, caller, sb);
1184 
1185  sb = object_get_description_path(op, caller, op->path_attuned,
1186  "Attuned", sb);
1187  sb = object_get_description_path(op, caller, op->path_repelled,
1188  "Repelled", sb);
1189  sb = object_get_description_path(op, caller, op->path_denied,
1190  "Denied", sb);
1191 
1192  if (op->stats.maxhp != 0 && op->type != ROD && op->type != WAND) {
1193  stringbuffer_append_printf(sb, "(hp%+d) ", op->stats.maxhp);
1194  }
1195 
1196  if (op->stats.maxsp != 0) {
1197  stringbuffer_append_printf(sb, "(mana%+d) ", op->stats.maxsp);
1198  }
1199 
1200  if (op->item_power != 0) {
1201  stringbuffer_append_printf(sb, "(item power%+d) ", op->item_power);
1202  }
1203  }
1204 
1205  size_t len = stringbuffer_length(sb);
1206  if (len > old_len) {
1207  stringbuffer_seek(sb, len - 1);
1208  }
1209 
1210  return sb;
1211 }
1212 
1222 char *object_get_description_s(const object *op, const object *caller)
1223 {
1224  return stringbuffer_finish(object_get_description(op, caller, NULL));
1225 }
1226 
1240 StringBuffer *object_get_name_description(const object *op,
1241  const object *caller, StringBuffer *sb)
1242 {
1243  HARD_ASSERT(op != NULL);
1244 
1245  sb = object_get_name(op, caller, sb);
1246 
1247  switch (op->type) {
1248  case RING:
1249  case SKILL:
1250  case WEAPON:
1251  case ARMOUR:
1252  case BRACERS:
1253  case HELMET:
1254  case PANTS:
1255  case SHIELD:
1256  case BOOTS:
1257  case GLOVES:
1258  case AMULET:
1259  case GIRDLE:
1260  case POTION:
1261  case BOW:
1262  case ARROW:
1263  case CLOAK:
1264  case FOOD:
1265  case DRINK:
1266  case WAND:
1267  case ROD:
1268  case FLESH:
1269  case BOOK:
1270  case CONTAINER:
1271  case TRINKET:
1272  {
1273  if ((op->type != AMULET && op->type != RING && op->type != TRINKET) ||
1274  op->title != NULL) {
1275  StringBuffer *sb2 = object_get_description(op, caller, NULL);
1276  if (stringbuffer_length(sb2) > 1) {
1277  stringbuffer_append_string(sb, " ");
1278  stringbuffer_append_stringbuffer(sb, sb2);
1279  }
1280  stringbuffer_free(sb2);
1281  }
1282 
1283  break;
1284  }
1285 
1286  default:
1287  break;
1288  }
1289 
1290  return sb;
1291 }
1292 
1303 char *object_get_name_description_s(const object *op, const object *caller)
1304 {
1305  return stringbuffer_finish(object_get_name_description(op, caller, NULL));
1306 }
1307 
1315 bool need_identify(const object *op)
1316 {
1317  switch (op->type) {
1318  case RING:
1319  case WAND:
1320  case ROD:
1321  case SCROLL:
1322  case FOOD:
1323  case POTION:
1324  case BOW:
1325  case ARROW:
1326  case WEAPON:
1327  case ARMOUR:
1328  case SHIELD:
1329  case HELMET:
1330  case PANTS:
1331  case AMULET:
1332  case BOOTS:
1333  case GLOVES:
1334  case BRACERS:
1335  case GIRDLE:
1336  case CONTAINER:
1337  case DRINK:
1338  case FLESH:
1339  case INORGANIC:
1340  case CLOAK:
1341  case GEM:
1342  case JEWEL:
1343  case NUGGET:
1344  case PEARL:
1345  case POWER_CRYSTAL:
1346  case BOOK:
1347  case LIGHT_APPLY:
1348  case LIGHT_REFILL:
1349  case BOOK_SPELL:
1350  case TRINKET:
1351  case PAINTING:
1352  return true;
1353  }
1354 
1355  return false;
1356 }
1357 
1364 void identify(object *op)
1365 {
1366  if (!op) {
1367  return;
1368  }
1369 
1371 
1372  /* The shop identifies items before they hit the ground */
1373  if (op->map) {
1375  } else {
1376  esrv_send_item(op);
1377  }
1378 }
1379 
1386 void set_trapped_flag(object *op)
1387 {
1388  object *tmp;
1389  uint32_t flag;
1390 
1391  if (!op) {
1392  return;
1393  }
1394 
1395  /* Player and monsters are not marked. */
1396  if (op->type == PLAYER || op->type == MONSTER) {
1397  return;
1398  }
1399 
1400  flag = QUERY_FLAG(op, FLAG_IS_TRAPPED);
1402 
1403  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
1404  /* Must be a rune AND visible */
1405  if (tmp->type == RUNE && tmp->stats.Int <= 1) {
1407  return;
1408  }
1409  }
1410 
1411  if (QUERY_FLAG(op, FLAG_IS_TRAPPED) != flag) {
1412  if (op->env) {
1413  esrv_update_item(UPD_FLAGS, op);
1414  } else {
1416  }
1417  }
1418 }
#define SCROLL
Definition: define.h:453
StringBuffer * object_get_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:299
#define MONSTER
Definition: define.h:353
#define FLAG_HITBACK
Definition: define.h:1000
const char *const attack_name[NROFATTACKS]
Definition: attack.c:57
int16_t ac
Definition: living.h:93
#define UP_OBJ_FACE
Definition: object.h:537
#define TERRAIN_FIREWALK
Definition: define.h:684
#define PAINTING
Definition: define.h:230
char * object_get_description_terrain_s(const object *op, const object *caller)
Definition: item.c:616
char * object_get_name_description_s(const object *op, const object *caller)
Definition: item.c:1303
#define FLAG_CURSED
Definition: define.h:1154
void identify(object *op)
Definition: item.c:1364
#define ST1_CONTAINER_NORMAL_party
Definition: define.h:580
#define BOOK
Definition: define.h:150
#define FLAG_IS_TRAPPED
Definition: define.h:1239
#define JEWEL
Definition: define.h:473
#define NRSPELLPATHS
Definition: define.h:666
char name[MAX_BUF]
Definition: material.h:115
#define NROF_ITEM_RACES
Definition: race.h:72
#define NROFREALSPELLS
Definition: define.h:664
#define WAND
Definition: define.h:445
#define FLAG_FRIENDLY
Definition: define.h:926
#define GIRDLE
Definition: define.h:461
#define BOW
Definition: define.h:174
#define FLAG_CAST_SPELL
Definition: define.h:1078
char * object_get_material_name_s(const object *op, const object *caller)
Definition: item.c:495
#define SHIELD
Definition: define.h:214
StringBuffer * object_get_title(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:124
const char * slaying
Definition: object.h:180
#define FLAG_PERM_CURSED
Definition: define.h:1306
int16_t material_real
Definition: object.h:307
#define FLAG_SOULBOUND
Definition: define.h:1044
int16_t last_sp
Definition: object.h:313
#define FLAG_SEE_INVISIBLE
Definition: define.h:946
#define TERRAIN_WATERWALK
Definition: define.h:680
int64_t exp
Definition: living.h:69
#define BRACERS
Definition: define.h:433
#define FLAG_MAKE_INVISIBLE
Definition: define.h:1259
#define IS_LIVE(op)
Definition: define.h:841
#define PLAYER
Definition: define.h:122
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:305
uint32_t path_attuned
Definition: object.h:255
int16_t sp
Definition: living.h:78
static char numbers[21][20]
Definition: item.c:35
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
uint32_t path_repelled
Definition: object.h:258
uint8_t absorb
Definition: object.h:421
const char *const spellpathnames[NRSPELLPATHS]
Definition: spellist.h:349
#define FLAG_PERM_DAMNED
Definition: define.h:1310
int8_t Int
Definition: living.h:112
uint8_t attack[NROFATTACKS]
Definition: object.h:436
int16_t maxsp
Definition: living.h:81
int32_t hp
Definition: living.h:72
#define FLAG_IS_NAMED
Definition: define.h:1274
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
#define FLESH
Definition: define.h:328
char * object_get_description_protections_s(const object *op, const object *caller)
Definition: item.c:740
#define FLAG_SEE_IN_DARK
Definition: define.h:1198
StringBuffer * object_get_short_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:416
#define ARMOUR
Definition: define.h:182
#define FLAG_BEEN_APPLIED
Definition: define.h:934
material_real_t materials_real[NUM_MATERIALS_REAL]
Definition: material.c:56
const char * title
Definition: object.h:171
#define FLAG_DAMNED
Definition: define.h:1158
int32_t maxhp
Definition: living.h:75
uint32_t path_denied
Definition: object.h:261
#define FLAG_LIFESAVE
Definition: define.h:1125
void object_update(object *op, int action)
Definition: object.c:1117
#define FLAG_QUEST_ITEM
Definition: define.h:1233
char * object_get_base_name_s(const object *op, const object *caller)
Definition: item.c:534
uint8_t item_race
Definition: object.h:372
#define FLAG_STEALTH
Definition: define.h:1146
StringBuffer * object_get_base_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:513
#define FLAG_IS_ETHEREAL
Definition: define.h:892
StringBuffer * object_get_material_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:471
#define ST1_CONTAINER_NORMAL_player
Definition: define.h:575
#define POWER_CRYSTAL
Definition: define.h:530
#define FLAG_USE_WEAPON
Definition: define.h:1094
#define ST1_CONTAINER_CORPSE_party
Definition: define.h:582
char * object_get_short_name_s(const object *op, const object *caller)
Definition: item.c:453
struct mapdef * map
Definition: object.h:139
#define FLAG_IS_INVISIBLE
Definition: define.h:888
#define FLAG_UNPAID
Definition: define.h:1251
int16_t dam
Definition: living.h:87
const char * name
Definition: object.h:168
#define SET_FLAG(xyz, p)
Definition: define.h:741
struct obj * env
Definition: object.h:130
StringBuffer * object_get_description_terrain(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:551
StringBuffer * object_get_material(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:71
struct obj * below
Definition: object.h:114
#define CONTAINER
Definition: define.h:493
char * object_get_material_s(const object *op, const object *caller)
Definition: item.c:107
int16_t last_grace
Definition: object.h:316
#define ST1_CONTAINER_CORPSE_player
Definition: define.h:577
#define FLAG_CAN_PASS_THRU
Definition: define.h:1058
uint32_t nrof
Definition: object.h:264
StringBuffer * object_get_description_protections(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:696
#define BOOK_SPELL
Definition: define.h:373
bool need_identify(const object *op)
Definition: item.c:1315
int8_t item_power
Definition: object.h:442
#define FLAG_ONE_DROP
Definition: define.h:1302
#define ARROW
Definition: define.h:170
StringBuffer * object_get_description_path(const object *op, const object *caller, const uint32_t path, const char *name, StringBuffer *sb)
Definition: item.c:763
#define FLAG_FLYING
Definition: define.h:918
#define FLAG_MAKE_ETHEREAL
Definition: define.h:1263
#define GEM
Definition: define.h:296
#define ROD
Definition: define.h:130
double speed
Definition: object.h:469
char * object_get_description_attacks_s(const object *op, const object *caller)
Definition: item.c:678
const char * name
Definition: spells.h:132
#define POTION
Definition: define.h:138
#define NUGGET
Definition: define.h:477
void esrv_send_item(object *op)
Definition: item.c:703
uint8_t block
Definition: object.h:416
#define TERRAIN_FIREBREATH
Definition: define.h:686
#define FLAG_NO_SKILL_IDENT
Definition: define.h:1194
int16_t last_eat
Definition: object.h:319
#define PEARL
Definition: define.h:292
int16_t wc
Definition: living.h:90
#define LIGHT_APPLY
Definition: define.h:336
spell_struct spells[NROFREALSPELLS]
Definition: spellist.h:34
StringBuffer * object_get_name_description(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:1240
#define FLAG_APPLIED
Definition: define.h:1182
char * object_get_description_path_s(const object *op, const object *caller, const uint32_t path, const char *name)
Definition: item.c:811
int8_t protection[NROFATTACKS]
Definition: object.h:439
#define NUM_STATS
Definition: living.h:49
#define RING
Definition: define.h:320
#define FLAG_XRAYS
Definition: define.h:1110
#define FLAG_REFL_MISSILE
Definition: define.h:1024
living stats
Definition: object.h:481
void esrv_update_item(int flags, object *op)
Definition: item.c:639
#define FLAG_REFL_SPELL
Definition: define.h:1028
#define SKILL
Definition: define.h:246
uint8_t type
Definition: object.h:360
#define CLEAR_FLAG(xyz, p)
Definition: define.h:751
StringBuffer * object_get_description_attacks(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:634
#define WEAPON
Definition: define.h:178
uint16_t terrain_flag
Definition: object.h:301
#define FOOD
Definition: define.h:142
#define INORGANIC
Definition: define.h:332
const char * msg
Definition: object.h:183
#define RUNE
Definition: define.h:522
#define FLAG_MONSTER
Definition: define.h:922
#define MIN_ACTIVE_SPEED
Definition: define.h:1500
#define FLAG_USE_ARMOUR
Definition: define.h:1090
#define HELMET
Definition: define.h:218
#define TERRAIN_AIRBREATH
Definition: define.h:678
#define FLAG_IS_MAGICAL
Definition: define.h:1129
void set_trapped_flag(object *op)
Definition: item.c:1386
struct obj * inv
Definition: object.h:123
#define BOOTS
Definition: define.h:413
char * object_get_description_s(const object *op, const object *caller)
Definition: item.c:1222
#define FLAG_USE_BOW
Definition: define.h:1086
#define FLAG_UNDEAD
Definition: define.h:1012
#define GLOVES
Definition: define.h:417
#define FLAG_UNAGGRESSIVE
Definition: define.h:1020
#define DRINK
Definition: define.h:279
StringBuffer * object_get_description(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:839
#define FLAG_INV_LOCKED
Definition: define.h:1186
#define PANTS
Definition: define.h:222
#define AMULET
Definition: define.h:234
#define CLOAK
Definition: define.h:381
char * object_get_title_s(const object *op, const object *caller)
Definition: item.c:282
const char *const short_stat_name[NUM_STATS]
Definition: living.c:221
int8_t level
Definition: object.h:347
#define FORCE
Definition: define.h:465
const char * item_races[NROF_ITEM_RACES]
Definition: race.c:37
#define LIGHT_REFILL
Definition: define.h:361
int8_t magic
Definition: object.h:341
#define BASE_INFO
Definition: define.h:421
#define TERRAIN_WATERBREATH
Definition: define.h:682
#define SKILL_ITEM
Definition: define.h:271
#define TERRAIN_WATER_SHALLOW
Definition: define.h:690
struct obj * attacked_by
Definition: object.h:199
#define FLAG_IDENTIFIED
Definition: define.h:980
int16_t food
Definition: living.h:84
#define IS_ARMOR(op)
Definition: define.h:839
uint8_t sub_type
Definition: object.h:363
#define TERRAIN_CLOUDWALK
Definition: define.h:688