Atrinik Server  4.0
book.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 <toolkit/packet.h>
32 #include <player.h>
33 #include <object.h>
34 #include <exp.h>
35 #include <object_methods.h>
36 #include <artifact.h>
37 
39 
44 #define BOOK_LEVEL_DIFF 12
45 
49 #define BOOK_CHANCE_EMPTY 15
50 
57 static int book_level_mod[MAX_STAT + 1] = {
58  -9,
59  -8, -7, -6, -5, -4,
60  -4, -3, -2, -2, -1,
61  0, 0, 0, 0, 0,
62  1, 1, 2, 2, 3,
63  3, 3, 4, 4, 5,
64  6, 7, 8, 9, 10
65 };
66 
73 static double book_exp_mod[MAX_STAT + 1] = {
74  -3.00f,
75  -2.00f, -1.90f, -1.80f, -1.70f, -1.60f,
76  -1.50f, -1.40f, -1.30f, -1.20f, -1.10f,
77  1.00f, 1.00f, 1.00f, 1.00f, 1.00f,
78  1.05f, 1.10f, 1.15f, 1.20f, 1.30f,
79  1.35f, 1.40f, 1.50f, 1.55f, 1.60f,
80  1.70f, 1.75f, 1.85f, 1.90f, 2.00f
81 };
82 
84 static int
85 apply_func (object *op, object *applier, int aflags)
86 {
87  HARD_ASSERT(op != NULL);
88  HARD_ASSERT(applier != NULL);
89 
90  /* Non-players cannot apply books. */
91  if (applier->type != PLAYER) {
92  return OBJECT_METHOD_OK;
93  }
94 
95  if (QUERY_FLAG(applier, FLAG_BLIND)) {
96  draw_info(COLOR_WHITE, applier, "You are unable to read while blind.");
97  return OBJECT_METHOD_OK;
98  }
99 
100  if (op->msg == NULL) {
101  draw_info_format(COLOR_WHITE, applier,
102  "You open the %s and find it empty.", op->name);
103  return OBJECT_METHOD_OK;
104  }
105 
106  /* Need a literacy skill to read stuff! */
107  if (!change_skill(applier, SK_LITERACY)) {
108  draw_info(COLOR_WHITE, applier,
109  "You are unable to decipher the strange symbols.");
110  return OBJECT_METHOD_OK;
111  }
112 
113  int lev_diff = op->level - (SK_level(applier) +
115  book_level_mod[applier->stats.Int]);
116  if (lev_diff > 0) {
117  if (lev_diff < 2) {
118  draw_info(COLOR_WHITE, applier,
119  "This book is just barely beyond your comprehension.");
120  } else if (lev_diff < 3) {
121  draw_info(COLOR_WHITE, applier,
122  "This book is slightly beyond your comprehension.");
123  } else if (lev_diff < 5) {
124  draw_info(COLOR_WHITE, applier,
125  "This book is beyond your comprehension.");
126  } else if (lev_diff < 8) {
127  draw_info(COLOR_WHITE, applier,
128  "This book is quite a bit beyond your comprehension.");
129  } else if (lev_diff < 15) {
130  draw_info(COLOR_WHITE, applier,
131  "This book is way beyond your comprehension.");
132  } else {
133  draw_info(COLOR_WHITE, applier,
134  "This book is totally beyond your comprehension.");
135  }
136 
137  return OBJECT_METHOD_OK;
138  }
139 
140  draw_info_format(COLOR_WHITE, applier,
141  "You open the %s and start reading.",
142  op->name);
143  CONTR(applier)->stat_books_read++;
144 
145  packet_struct *packet = packet_new(CLIENT_CMD_BOOK, 512, 512);
146  packet_debug_data(packet, 0, "Book interface header");
147  packet_append_string(packet, "[book]");
148  StringBuffer *sb = object_get_base_name(op, applier, NULL);
149  packet_append_string_len(packet,
150  stringbuffer_data(sb),
151  stringbuffer_length(sb));
152  stringbuffer_free(sb);
153  packet_append_string(packet, "[/book]");
154  packet_debug_data(packet, 0, "Book message");
155  packet_append_string_terminated(packet, op->msg);
156  socket_send_packet(CONTR(applier)->cs, packet);
157 
158  /* Gain xp from reading but only if not read before. */
159  if (!QUERY_FLAG(op, FLAG_NO_SKILL_IDENT)) {
160  CONTR(applier)->stat_unique_books_read++;
161 
162  /* Store original exp value. We want to keep the experience cap
163  * from calc_skill_exp() below, so we temporarily adjust the exp
164  * of the book, instead of adjusting the return value. */
165  int64_t old_exp = op->stats.exp;
166  /* Adjust the experience based on player's intelligence. */
167  op->stats.exp *= book_exp_mod[applier->stats.Int];
168 
169  if (!QUERY_FLAG(op, FLAG_IDENTIFIED)) {
170  /* Because they just identified it too. */
171  op->stats.exp *= 1.5f;
172  identify(op);
173  }
174 
175  int64_t exp_gain = calc_skill_exp(applier, op, -1);
176  add_exp(applier, exp_gain, applier->chosen_skill->stats.sp, 0);
177 
178  /* So no more exp gained from this book. */
180  /* Restore old experience value. */
181  op->stats.exp = old_exp;
182  }
183 
184  return OBJECT_METHOD_OK;
185 }
186 
188 static int
190  object **ret,
191  int difficulty,
192  treasure_affinity_t *affinity,
193  int flags)
194 {
195  HARD_ASSERT(op != NULL);
196  HARD_ASSERT(difficulty > 0);
197 
198  /* Avoid processing if the item is already special. */
199  if (process_treasure_is_special(op)) {
201  }
202 
203  /* If the book already has a message, don't overwrite it with a
204  * generated one. */
205  if (op->msg != NULL) {
206  return OBJECT_METHOD_OK;
207  }
208 
209  /* Chance for the book to be empty. */
210  if (rndm_chance(BOOK_CHANCE_EMPTY)) {
211  return OBJECT_METHOD_OK;
212  }
213 
214  /* Calculate the level. Essentially -20 below the difficulty at worst, or
215  * +20 above the difficulty at best. */
216  int level = difficulty - 20 + rndm(0, 40);
217  level = MIN(MAX(level, 1), MAXLEVEL);
218  op->level = level;
219 
220  if (!artifact_generate(op, difficulty, affinity)) {
221  tailor_readable_ob(op, -1);
222  }
223 
224  /* Adjust the value and experience gains based on the message length. */
225  size_t msg_len = op->msg != NULL ? strlen(op->msg) : 0;
226  if (msg_len != 0) {
227  int value_level = op->level > 10 ? op->level : (op->level + 1) / 2;
228  op->value *= value_level * ((msg_len / 250) + 1);
229  op->stats.exp = 105 + (msg_len / 25) + rndm(5, 15);
230  }
231 
232  return OBJECT_METHOD_OK;
233 }
234 
239 {
240  OBJECT_METHODS(BOOK)->apply_func = apply_func;
241  OBJECT_METHODS(BOOK)->process_treasure_func = process_treasure_func;
242 }
#define BOOK_CHANCE_EMPTY
Definition: book.c:49
#define BOOK_LEVEL_DIFF
Definition: book.c:44
void identify(object *op)
Definition: item.c:1364
#define BOOK
Definition: define.h:150
int64_t calc_skill_exp(object *who, object *op, int level)
Definition: skill_util.c:158
int SK_level(object *op)
Definition: skill_util.c:470
#define FLAG_BLIND
Definition: define.h:884
int64_t exp
Definition: living.h:69
#define PLAYER
Definition: define.h:122
int16_t sp
Definition: living.h:78
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
int8_t Int
Definition: living.h:112
static int process_treasure_func(object *op, object **ret, int difficulty, treasure_affinity_t *affinity, int flags)
Definition: book.c:189
int64_t add_exp(object *op, int64_t exp_gain, int skill_nr, int exact)
Definition: exp.c:304
struct obj * chosen_skill
Definition: object.h:210
StringBuffer * object_get_base_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:513
const char * name
Definition: object.h:168
#define SET_FLAG(xyz, p)
Definition: define.h:741
void tailor_readable_ob(object *book, int msg_type)
Definition: readable.c:847
int change_skill(object *who, int sk_index)
Definition: skill_util.c:340
#define OBJECT_METHOD_UNHANDLED
#define FLAG_NO_SKILL_IDENT
Definition: define.h:1194
#define MAXLEVEL
Definition: global.h:221
bool process_treasure_is_special(object *op)
living stats
Definition: object.h:481
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
bool artifact_generate(object *op, int difficulty, treasure_affinity_t *affinity)
Definition: artifact.c:541
const char * msg
Definition: object.h:183
#define OBJECT_METHOD_OK
static int apply_func(object *op, object *applier, int aflags)
Definition: book.c:85
OBJECT_TYPE_INIT_DEFINE(book)
Definition: book.c:238
static double book_exp_mod[MAX_STAT+1]
Definition: book.c:73
int8_t level
Definition: object.h:347
int64_t value
Definition: object.h:240
static int book_level_mod[MAX_STAT+1]
Definition: book.c:57
#define MAX_STAT
Definition: define.h:47
#define FLAG_IDENTIFIED
Definition: define.h:980