Atrinik Server  4.0
skill_util.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 /* define the following for skills utility debugging */
31 /* #define SKILL_UTIL_DEBUG */
32 
33 #include <global.h>
34 #include <toolkit/string.h>
35 #include <plugin.h>
36 #include <arch.h>
37 #include <player.h>
38 #include <object.h>
39 #include <exp.h>
40 
42 float stat_exp_mult[MAX_STAT + 1] = {
43  0.0f, 0.01f, 0.1f, 0.3f, 0.5f,
44  0.6f, 0.7f, 0.8f, 0.85f, 0.9f,
45  0.95f, 0.96f, 0.97f, 0.98f, 0.99f,
46  1.0f, 1.01f, 1.02f, 1.03f, 1.04f,
47  1.05f, 1.07f, 1.09f, 1.12f, 1.15f,
48  1.2f, 1.3f, 1.4f, 1.5f, 1.7f,
49  2.0f
50 };
51 
55 static float lev_exp[MAXLEVEL + 1] = {
56  0.0f, 1.0f, 1.11f, 1.75f, 3.2f,
57  5.5f, 10.0f, 20.0f, 35.25f, 66.1f,
58  137.0f, 231.58f, 240.00f, 247.62f, 254.55f,
59  260.87f, 266.67f, 272.00f, 276.92f, 281.48f,
60  285.71f, 289.66f, 293.33f, 296.77f, 300.00f,
61  303.03f, 305.88f, 308.57f, 311.11f, 313.51f,
62  315.79f, 317.95f, 320.00f, 321.95f, 323.81f,
63  325.58f, 327.27f, 328.89f, 330.43f, 331.91f,
64  333.33f, 334.69f, 336.00f, 337.25f, 338.46f,
65  339.62f, 340.74f, 341.82f, 342.86f, 343.86f,
66  344.83f, 345.76f, 346.67f, 347.54f, 348.39f,
67  349.21f, 350.00f, 350.77f, 351.52f, 352.24f,
68  352.94f, 353.62f, 354.29f, 354.93f, 355.56f,
69  356.16f, 356.76f, 357.33f, 357.89f, 358.44f,
70  358.97f, 359.49f, 360.00f, 360.49f, 360.98f,
71  361.45f, 361.90f, 362.35f, 362.79f, 365.22f,
72  367.64f, 369.04f, 373.44f, 378.84f, 384.22f,
73  389.59f, 395.96f, 402.32f, 410.67f, 419.01f,
74  429.35f, 440.68f, 452.00f, 465.32f, 479.63f,
75  494.93f, 510.23f, 527.52f, 545.81f, 562.09f,
76  580.37f, 599.64f, 619.91f, 640.17f, 662.43f,
77  685.68f, 709.93f, 773.17f, 852.41f, 932.65f,
78  1013.88f, 1104.11f, 1213.35f, 1324.60f, 1431.86f,
79  1542.13f
80 };
81 
82 static int do_skill_attack(object *tmp, object *op, char *string);
83 
99 int64_t do_skill(object *op, int dir, const char *params)
100 {
101  int64_t success = 0;
102  int skill = op->chosen_skill->stats.sp;
103 
104  /* Trigger the map-wide skill event. */
105  if (op->map && op->map->events) {
106  int retval = trigger_map_event(MEVENT_SKILL_USED, op->map, op, NULL, NULL, NULL, dir);
107 
108  /* So the plugin's return value can affect the returned value. */
109  if (retval) {
110  return retval - 1;
111  }
112  }
113 
114  switch (skill) {
115  case SK_FIND_TRAPS:
116  find_traps(op, op->level);
117  break;
118 
119  case SK_REMOVE_TRAPS:
120  remove_trap(op);
121  break;
122 
123  case SK_CONSTRUCTION:
124  construction_do(op, dir);
125  return success;
126 
127  case SK_INSCRIPTION:
128  success = skill_inscription(op, params);
129  break;
130 
131  default:
132  draw_info(COLOR_WHITE, op, "This skill is not usable in this way.");
133  return 0;
134  }
135 
136  /* This is a good place to add experience for successfull use of skills.
137  * Note that add_exp() will figure out player/monster experience
138  * gain problems. */
139  if (success) {
140  add_exp(op, success, op->chosen_skill->stats.sp, 0);
141  }
142 
143  return success;
144 }
145 
158 int64_t calc_skill_exp(object *who, object *op, int level)
159 {
160  HARD_ASSERT(who != NULL);
161 
162  SOFT_ASSERT_RC(who->type == PLAYER, 0, "Called with non-player: %s, op: %s",
163  object_get_str(who), object_get_str(op));
164 
165  int who_lvl = level;
166  if (who_lvl == -1) {
167  /* The related skill level */
168  who_lvl = SK_level(who);
169  }
170 
171  int64_t op_exp;
172  int op_lvl;
173  if (op == NULL) {
174  op_lvl = who->map->difficulty < 1 ? 1 : who->map->difficulty;
175  op_exp = 0;
176  } else {
177  /* All other items/living creatures */
178  op_exp = op->stats.exp;
179  op_lvl = op->level;
180  }
181 
182  if (op_lvl < 1 || op_exp < 1) {
183  return 0;
184  }
185 
186  float max_mul;
187  if (who_lvl < 2) {
188  max_mul = 0.85f;
189  } else if (who_lvl < 3) {
190  max_mul = 0.7f;
191  } else if (who_lvl < 4) {
192  max_mul = 0.6f;
193  } else if (who_lvl < 5) {
194  max_mul = 0.45f;
195  } else if (who_lvl < 7) {
196  max_mul = 0.35f;
197  } else if (who_lvl < 8) {
198  max_mul = 0.3f;
199  } else {
200  max_mul = 0.25f;
201  }
202 
203  /* We first get a global level difference multiplier */
204  float exp_mul = calc_level_difference(who_lvl, op_lvl);
205  op_exp = (int64_t) ((float) op_exp * lev_exp[op_lvl] * exp_mul);
206  float tmp = ((float) (new_levels[who_lvl + 1] - new_levels[who_lvl]) *
207  0.1f) * max_mul;
208 
209  if ((float) op_exp > tmp) {
210  op_exp = (int64_t) tmp;
211  }
212 
213  return op_exp;
214 }
215 
220 {
221  int i;
222  archetype_t *at;
223  char buf[MAX_BUF];
224 
225  for (i = 0; i < NROFSKILLS; i++) {
226  snprintf(buf, sizeof(buf), "skill_%s", skills[i].name);
227  string_replace_char(buf, " ", '_');
228 
229  at = arch_find(buf);
230 
231  if (!at) {
232  continue;
233  }
234 
235  skills[i].at = at;
236 
237  /* Set some default values for the archetype. */
238  at->clone.stats.sp = i;
239  at->clone.stats.exp = 0;
240  }
241 }
242 
252 int check_skill_to_fire(object *op, object *weapon)
253 {
254  int skillnr;
255 
256  skillnr = -1;
257 
258  if (weapon->type == BOW) {
259  if (weapon->item_skill) {
260  skillnr = weapon->item_skill - 1;
261  } else {
262  skillnr = SK_BOW_ARCHERY;
263  }
264  } else if (weapon->type == SPELL) {
265  skillnr = SK_WIZARDRY_SPELLS;
266  } else if (weapon->type == ROD || weapon->type == WAND) {
267  skillnr = SK_MAGIC_DEVICES;
268  } else if (weapon->type == ARROW) {
269  skillnr = SK_THROWING;
270  } else if (weapon->type == SKILL) {
271  skillnr = weapon->stats.sp;
272  }
273 
274  if (skillnr == -1) {
275  return 0;
276  }
277 
278  return change_skill(op, skillnr);
279 }
280 
287 void link_player_skills(object *pl)
288 {
289  bool fix;
290  int i;
291  object *tmp;
292 
293  fix = false;
294  pl->stats.exp = 0;
295 
296  for (i = 0; i < NROFSKILLS; i++) {
297  /* Skip unused skill entries. */
298  if (!skills[i].at) {
299  continue;
300  }
301 
302  if (!CONTR(pl)->skill_ptr[i]) {
303  tmp = object_clone(&skills[i].at->clone);
304  object_insert_into(tmp, pl, 0);
305  CONTR(pl)->skill_ptr[i] = tmp;
306  fix = true;
307  }
308 
309  if (!QUERY_FLAG(CONTR(pl)->skill_ptr[i], FLAG_STAND_STILL)) {
310  pl->stats.exp += CONTR(pl)->skill_ptr[i]->stats.exp;
311 
312  if (pl->stats.exp >= (int64_t) MAX_EXPERIENCE) {
313  pl->stats.exp = MAX_EXPERIENCE;
314  }
315  }
316 
317  if (exp_lvl_adj(pl, CONTR(pl)->skill_ptr[i]) != 0) {
318  fix = true;
319  }
320  }
321 
322  if (exp_lvl_adj(pl, NULL) != 0) {
323  fix = true;
324  }
325 
326  if (fix) {
327  living_update(pl);
328  }
329 }
330 
340 int change_skill(object *who, int sk_index)
341 {
342  if (who->type != PLAYER) {
343  return 0;
344  }
345 
346  if (who->chosen_skill && who->chosen_skill->stats.sp == sk_index) {
347  return 1;
348  }
349 
350  if (CONTR(who)->skill_ptr[sk_index]) {
351  who->chosen_skill = CONTR(who)->skill_ptr[sk_index];
352  return 1;
353  }
354 
355  return 0;
356 }
357 
377 int skill_attack(object *tmp, object *pl, int dir, char *string)
378 {
379  int xt, yt;
380  mapstruct *m;
381 
382  if (!dir) {
383  dir = pl->direction;
384  }
385 
386  /* If we don't yet have an opponent, find if one exists, and attack.
387  * Legal opponents are the same as outlined in move_object() */
388  if (tmp == NULL) {
389  xt = pl->x + freearr_x[dir];
390  yt = pl->y + freearr_y[dir];
391 
392  if (!(m = get_map_from_coord(pl->map, &xt, &yt))) {
393  return 0;
394  }
395 
396  for (tmp = GET_MAP_OB(m, xt, yt); tmp; tmp = tmp->above) {
397  if ((IS_LIVE(tmp) && (tmp->head == NULL ? tmp->stats.hp > 0 : tmp->head->stats.hp > 0)) || QUERY_FLAG(tmp, FLAG_CAN_ROLL) || tmp->type == DOOR) {
398  if (pl->type == PLAYER && tmp->type == PLAYER && !pvp_area(pl, tmp)) {
399  continue;
400  }
401 
402  break;
403  }
404  }
405  }
406 
407  if (tmp != NULL) {
408  return do_skill_attack(tmp, pl, string);
409  }
410 
411  if (pl->type == PLAYER) {
412  draw_info(COLOR_WHITE, pl, "There is nothing to attack!");
413  }
414 
415  return 0;
416 }
417 
432 static int do_skill_attack(object *tmp, object *op, char *string)
433 {
434  int success;
435 
436  if (op->type == PLAYER) {
437  if (CONTR(op)->equipment[PLAYER_EQUIP_WEAPON] && CONTR(op)->equipment[PLAYER_EQUIP_WEAPON]->type == WEAPON && CONTR(op)->equipment[PLAYER_EQUIP_WEAPON]->item_skill) {
438  op->chosen_skill = CONTR(op)->skill_ptr[CONTR(op)->equipment[PLAYER_EQUIP_WEAPON]->item_skill - 1];
439  } else {
440  op->chosen_skill = CONTR(op)->skill_ptr[SK_UNARMED];
441  }
442  }
443 
444  success = attack_object(tmp, op);
445 
446  /* Print appropriate messages to the player. */
447  if (success && string != NULL) {
448  if (op->type == PLAYER) {
449  char *name = object_get_name_s(tmp, op);
450  draw_info_format(COLOR_WHITE, op, "You %s %s!", string, name);
451  efree(name);
452  } else if (tmp->type == PLAYER) {
453  char *name = object_get_name_s(op, tmp);
454  draw_info_format(COLOR_WHITE, tmp, "%s %s you!", name, string);
455  efree(name);
456  }
457  }
458 
459  return success;
460 }
461 
470 int SK_level(object *op)
471 {
472  object *head = op->head ? op->head : op;
473  int level;
474 
475  if (head->type == PLAYER && head->chosen_skill && head->chosen_skill->level != 0) {
476  level = head->chosen_skill->level;
477  } else {
478  level = head->level;
479  }
480 
481  /* Safety */
482  if (level <= 0) {
483  level = 1;
484  }
485 
486  return level;
487 }
488 
496 object *SK_skill(object *op)
497 {
498  object *head = op->head ? op->head : op;
499 
500  if (head->type == PLAYER && head->chosen_skill) {
501  return head->chosen_skill;
502  }
503 
504  return NULL;
505 }
int64_t do_skill(object *op, int dir, const char *params)
Definition: skill_util.c:99
int exp_lvl_adj(object *who, object *op)
Definition: exp.c:422
void init_new_exp_system(void)
Definition: skill_util.c:219
#define MEVENT_SKILL_USED
Definition: plugin.h:127
int64_t calc_skill_exp(object *who, object *op, int level)
Definition: skill_util.c:158
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
mapstruct * get_map_from_coord(mapstruct *m, int *x, int *y)
Definition: map.c:1869
int SK_level(object *op)
Definition: skill_util.c:470
#define WAND
Definition: define.h:445
#define BOW
Definition: define.h:174
uint8_t item_skill
Definition: object.h:378
int64_t exp
Definition: living.h:69
struct obj * above
Definition: object.h:120
#define IS_LIVE(op)
Definition: define.h:841
#define PLAYER
Definition: define.h:122
static int do_skill_attack(object *tmp, object *op, char *string)
Definition: skill_util.c:432
int16_t sp
Definition: living.h:78
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
uint64_t new_levels[MAXLEVEL+2]
Definition: exp.c:38
#define FLAG_STAND_STILL
Definition: define.h:1133
int32_t hp
Definition: living.h:72
int attack_object(object *op, object *hitter)
Definition: attack.c:260
float calc_level_difference(int who_lvl, int op_lvl)
Definition: exp.c:490
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
float stat_exp_mult[MAX_STAT+1]
Definition: skill_util.c:42
int64_t add_exp(object *op, int64_t exp_gain, int skill_nr, int exact)
Definition: exp.c:304
object * object_clone(const object *op)
Definition: object.c:2385
struct obj * chosen_skill
Definition: object.h:210
int16_t y
Definition: object.h:276
static float lev_exp[MAXLEVEL+1]
Definition: skill_util.c:55
const char * object_get_str(const object *op)
Definition: object.c:3151
int8_t direction
Definition: object.h:350
Definition: arch.h:40
#define FLAG_CAN_ROLL
Definition: define.h:950
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
struct mapdef * map
Definition: object.h:139
void construction_do(object *op, int dir)
Definition: construction.c:681
void find_traps(object *pl, int level)
Definition: skills.c:43
struct archetype * at
Definition: skills.h:123
object * SK_skill(object *op)
Definition: skill_util.c:496
#define ARROW
Definition: define.h:170
int trigger_map_event(int event_id, mapstruct *m, object *activator, object *other, object *other2, const char *text, int parm)
Definition: plugins.c:416
#define ROD
Definition: define.h:130
int change_skill(object *who, int sk_index)
Definition: skill_util.c:340
int skill_inscription(object *op, const char *params)
Definition: inscription.c:94
void link_player_skills(object *pl)
Definition: skill_util.c:287
int16_t x
Definition: object.h:273
int pvp_area(object *attacker, object *victim)
Definition: player.c:977
#define MAXLEVEL
Definition: global.h:221
struct map_event * events
Definition: map.h:583
int difficulty
Definition: map.h:650
int skill_attack(object *tmp, object *pl, int dir, char *string)
Definition: skill_util.c:377
living stats
Definition: object.h:481
int freearr_x[SIZEOFFREE]
Definition: object.c:84
#define SKILL
Definition: define.h:246
uint8_t type
Definition: object.h:360
#define WEAPON
Definition: define.h:178
int living_update(object *op)
Definition: living.c:1661
#define MAX_EXPERIENCE
Definition: global.h:224
#define DOOR
Definition: define.h:194
struct obj * head
Definition: object.h:136
int check_skill_to_fire(object *op, object *weapon)
Definition: skill_util.c:252
void remove_trap(object *op)
Definition: skills.c:115
Definition: map.h:536
skill_struct skills[NROFSKILLS]
Definition: skillist.h:62
int8_t level
Definition: object.h:347
int freearr_y[SIZEOFFREE]
Definition: object.c:99
object clone
An object from which to do object_copy().
Definition: arch.h:47
archetype_t * arch_find(const char *name)
Definition: arch.c:407
#define MAX_STAT
Definition: define.h:47
#define SPELL
Definition: define.h:210