Atrinik Client  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 <region_map.h>
32 #include <toolkit/packet.h>
33 
37 static mempool_struct *pool_object;
38 
42 void object_init(void)
43 {
44  toolkit_import(mempool);
45 
46  pool_object = mempool_create("objects", NROF_ITEMS, sizeof(object),
47  MEMPOOL_ALLOW_FREEING, NULL, NULL, NULL, NULL);
48  objects_init();
49 }
50 
54 void object_deinit(void)
55 {
57 }
58 
64 void objects_free(object *op)
65 {
66  object *next;
67 
68  while (op) {
69  if (op->itype == TYPE_SPELL) {
70  spells_remove(op);
71  } else if (op->itype == TYPE_SKILL) {
72  skills_remove(op);
73  } else if (op->itype == TYPE_FORCE || op->itype == TYPE_POISONING) {
74  widget_active_effects_remove(cur_widget[ACTIVE_EFFECTS_ID], op);
75  }
76 
77  if (op->inv) {
78  objects_free(op->inv);
79  }
80 
81  next = op->next;
82  mempool_return(pool_object, op);
83  op = next;
84  }
85 }
86 
96 object *object_find_object_inv(object *op, tag_t tag)
97 {
98  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->next) {
99  if (tmp->tag == tag) {
100  return op;
101  }
102  }
103 
104  return NULL;
105 }
106 
116 object *object_find_object(object *op, tag_t tag)
117 {
118  for ( ; op != NULL; op = op->next) {
119  if (op->tag == tag) {
120  return op;
121  } else if (op->inv != NULL) {
122  object *tmp = object_find_object(op->inv, tag);
123  if (tmp != NULL) {
124  return tmp;
125  }
126  }
127  }
128 
129  return NULL;
130 }
131 
139 object *object_find(tag_t tag)
140 {
141  /* In interface GUI. */
142  if (cpl.interface != NULL) {
143  object *op = object_find_object(cpl.interface->inv, tag);
144  if (op != NULL) {
145  return op;
146  }
147  }
148 
149  /* Below the player. */
150  if (cpl.below != NULL) {
151  object *op = object_find_object(cpl.below, tag);
152  if (op != NULL) {
153  return op;
154  }
155  }
156 
157  /* Open container. */
158  if (cpl.sack != NULL) {
159  object *op = object_find_object(cpl.sack, tag);
160  if (op != NULL) {
161  return op;
162  }
163  }
164 
165  /* Last attempt, inside the player. */
166  return object_find_object(cpl.ob, tag);
167 }
168 
174 void object_remove(object *op)
175 {
176  if (op == NULL || op == cpl.ob || op == cpl.below) {
177  return;
178  }
179 
180  if (op->itype == TYPE_SPELL) {
181  spells_remove(op);
182  } else if (op->itype == TYPE_SKILL) {
183  skills_remove(op);
184  } else if (op->itype == TYPE_FORCE || op->itype == TYPE_POISONING) {
185  widget_active_effects_remove(cur_widget[ACTIVE_EFFECTS_ID], op);
186  }
187 
188  object_redraw(op);
189 
190  if (op->inv != NULL) {
192  }
193 
194  if (op->prev != NULL) {
195  op->prev->next = op->next;
196  } else if (op->env != NULL) {
197  op->env->inv = op->next;
198  }
199 
200  if (op->next != NULL) {
201  op->next->prev = op->prev;
202  }
203 
204  if (op->itype == TYPE_REGION_MAP) {
205  region_map_fow_update(MapData.region_map);
206  minimap_redraw_flag = 1;
207  }
208 
209  mempool_return(pool_object, op);
210 }
211 
217 void object_remove_inventory(object *op)
218 {
219  if (!op) {
220  return;
221  }
222 
223  if (op == cpl.sack) {
224  cpl.sack = NULL;
225  }
226 
227  object_redraw(op);
228 
229  for (object *tmp = op->inv, *next; tmp != NULL; tmp = next) {
230  next = tmp->next;
231 
232  if (tmp == cpl.sack) {
233  continue;
234  }
235 
236  object_remove(tmp);
237  }
238 }
239 
250 static void object_add(object *env, object *op, int bflag)
251 {
252  object *tmp;
253 
254  if (!op) {
255  return;
256  }
257 
258  if (!bflag) {
259  op->next = env->inv;
260 
261  if (op->next) {
262  op->next->prev = op;
263  }
264 
265  op->prev = NULL;
266  env->inv = op;
267  op->env = env;
268  } else {
269  for (tmp = env->inv; tmp && tmp->next; tmp = tmp->next) {
270  }
271 
272  op->next = NULL;
273  op->prev = tmp;
274  op->env = env;
275 
276  if (!tmp) {
277  env->inv = op;
278  } else {
279  if (tmp->next) {
280  tmp->next->prev = op;
281  }
282 
283  tmp->next = op;
284  }
285  }
286 }
287 
295 void object_transfer_inventory(object *op, object *to)
296 {
297  for (object *tmp = op->inv, *next; tmp != NULL; tmp = next) {
298  next = tmp->next;
299 
300  if (tmp->prev != NULL) {
301  tmp->prev->next = tmp->next;
302  } else if (tmp->env != NULL) {
303  tmp->env->inv = tmp->next;
304  }
305 
306  if (tmp->next != NULL) {
307  tmp->next->prev = tmp->prev;
308  }
309 
310  object_add(to, tmp, 1);
311  }
312 }
313 
327 object *object_create(object *env, tag_t tag, int bflag)
328 {
329  object *op = mempool_get(pool_object);
330 
331  op->tag = tag;
332 
333  if (env != NULL) {
334  object_add(env, op, bflag);
335  }
336 
337  object_redraw(op);
338 
339  return op;
340 }
341 
347 void toggle_locked(object *op)
348 {
349  packet_struct *packet;
350 
351  /* If object is on the ground, don't lock it. */
352  if (!op || !op->env || op->env->tag == 0) {
353  return;
354  }
355 
356  packet = packet_new(SERVER_CMD_ITEM_LOCK, 8, 0);
357  packet_append_uint32(packet, op->tag);
358  socket_send_packet(packet);
359 }
360 
366 void object_send_mark(object *op)
367 {
368  packet_struct *packet;
369 
370  /* If object is on the ground, don't mark it. */
371  if (!op || !op->env || op->env->tag == 0) {
372  return;
373  }
374 
375  if (cpl.mark_count == op->tag) {
376  cpl.mark_count = 0;
377  } else {
378  cpl.mark_count = op->tag;
379  }
380 
381  object_redraw(op);
382 
383  packet = packet_new(SERVER_CMD_ITEM_MARK, 8, 0);
384  packet_append_uint32(packet, op->tag);
385  socket_send_packet(packet);
386 }
387 
388 void object_redraw(object *op)
389 {
390  object *env;
391 
392  HARD_ASSERT(op != NULL);
393 
394  if (op->env == NULL) {
395  return;
396  }
397 
398  env = op->env;
399 
400  if (env == cpl.sack) {
401  env = cpl.sack->env;
402  }
403 
404  if (env == cpl.interface) {
406  } else if (env == cpl.below) {
407  widget_redraw_type_id(INVENTORY_ID, "below");
408  } else {
409  widget_redraw_type_id(INVENTORY_ID, "main");
410  /* TODO: This could be more sophisticated... */
411  WIDGET_REDRAW_ALL(QUICKSLOT_ID);
412  }
413 }
414 
418 void objects_deinit(void)
419 {
422 }
423 
427 void objects_init(void)
428 {
429  cpl.ob = mempool_get(pool_object);
430  cpl.below = mempool_get(pool_object);
431 
432  cpl.below->weight = -111;
433 }
434 
442 int object_animate(object *ob)
443 {
444  bool ret = false;
445 
446  if (ob->glow_speed > 1) {
447  ob->glow_state++;
448 
449  if (ob->glow_state > ob->glow_speed) {
450  ob->glow_state = 0;
451  }
452 
453  ret = true;
454  }
455 
456  if (ob->animation_id > 0) {
458  }
459 
460  if (ob->animation_id > 0 && ob->anim_speed) {
461  ob->last_anim++;
462 
463  if (ob->last_anim >= ob->anim_speed) {
464  if (++ob->anim_state >= animations[ob->animation_id].frame) {
465  ob->anim_state = 0;
466  }
467 
468  if (ob->direction > animations[ob->animation_id].facings) {
469  ob->face = animations[ob->animation_id].faces[ob->anim_state];
470  } else {
471  ob->face = animations[ob->animation_id].faces[animations[ob->animation_id].frame * ob->direction + ob->anim_state];
472  }
473 
474  ob->last_anim = 0;
475 
476  ret = true;
477  }
478  }
479 
480  return ret;
481 }
482 
488 static void animate_inventory(object *op)
489 {
490  object *tmp;
491 
492  for (tmp = op->inv; tmp != NULL; tmp = tmp->next) {
493  if (!object_animate(tmp)) {
494  continue;
495  }
496 
497  /* Applied item inside the player, redraw the player doll -- most items
498  * that can be applied are visible in the player doll. */
499  if (op == cpl.ob && tmp->flags & CS_FLAG_APPLIED) {
500  WIDGET_REDRAW_ALL(PDOLL_ID);
501  }
502 
503  object_redraw(tmp);
504  }
505 }
506 
510 void animate_objects(void)
511 {
514 
515  if (cpl.sack != NULL) {
517  }
518 
519  if (cpl.interface != NULL) {
521  }
522 }
523 
545 void object_show_centered (SDL_Surface *surface,
546  object *tmp,
547  int x,
548  int y,
549  int w,
550  int h,
551  bool fit)
552 {
553  HARD_ASSERT(surface != NULL);
554  HARD_ASSERT(tmp != NULL);
555 
556  if (FaceList[tmp->face].sprite == NULL) {
557  return;
558  }
559 
560  /* Will be used for coordinate calculations. */
561  uint16_t face = tmp->face;
562 
563  /* If the item is animated, try to use the first animation face for
564  * coordinate calculations to prevent 'jumping' of the animation. */
565  if (tmp->animation_id > 0) {
567 
568  if (animations[tmp->animation_id].num_animations) {
569  uint16_t face_id;
570 
571  face_id = animations[tmp->animation_id].frame * tmp->direction;
572 
573  if (FaceList[animations[tmp->animation_id].faces[face_id]].sprite) {
574  face = animations[tmp->animation_id].faces[face_id];
575  }
576  }
577  }
578 
579  int border_left = FaceList[face].sprite->border_left;
580  int border_up = FaceList[face].sprite->border_up;
581  if (tmp->glow[0] != '\0') {
582  border_left -= SPRITE_GLOW_SIZE * 2;
583  border_up -= SPRITE_GLOW_SIZE * 2;
584  }
585 
586  int xlen = FaceList[face].sprite->bitmap->w - border_left -
587  FaceList[face].sprite->border_right;
588  int ylen = FaceList[face].sprite->bitmap->h - border_up -
589  FaceList[face].sprite->border_down;
590  if (tmp->glow[0] != '\0') {
591  xlen += SPRITE_GLOW_SIZE * 2;
592  ylen += SPRITE_GLOW_SIZE * 2;
593  }
594 
595  double zoom_x = 1.0, zoom_y = 1.0;
596  if (fit) {
597  int xlen2 = xlen, ylen2 = ylen;
598 
599  if (xlen2 != w) {
600  double factor = (double) w / xlen2;
601  xlen2 *= factor;
602  ylen2 *= factor;
603  }
604 
605  if (ylen2 != h) {
606  double factor = (double) h / ylen2;
607  xlen2 *= factor;
608  ylen2 *= factor;
609  }
610 
611  if (xlen2 != xlen) {
612  zoom_x = ((double) xlen2 + 0.5) / xlen;
613  xlen = xlen2;
614  border_left *= zoom_x;
615  }
616 
617  if (ylen2 != ylen) {
618  zoom_y = ((double) ylen2 + 0.5) / ylen;
619  ylen = ylen2;
620  border_up *= zoom_y;
621  }
622  }
623 
624  SDL_Rect box;
625  if (xlen > w) {
626  box.w = w;
627  int temp = (xlen - w) / 2;
628  box.x = border_left + temp;
629  border_left = 0;
630  } else {
631  box.w = xlen;
632  box.x = border_left;
633  border_left = (w - xlen) / 2;
634  }
635 
636  if (ylen > h) {
637  box.h = h;
638  int temp = (ylen - h) / 2;
639  box.y = border_up + temp;
640  border_up = 0;
641  } else {
642  box.h = ylen;
643  box.y = border_up;
644  border_up = (h - ylen) / 2;
645  }
646 
647  if (face != tmp->face) {
648  int temp = border_left - box.x;
649 
650  box.x = 0;
651  box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x;
652  border_left = temp;
653 
654  temp = border_up - box.y + (FaceList[face].sprite->bitmap->h * zoom_y -
655  FaceList[tmp->face].sprite->bitmap->h *
656  zoom_y);
657  box.y = 0;
658  box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y;
659  border_up = temp;
660 
661  if (border_left < 0) {
662  box.x = -border_left;
663  box.w = FaceList[tmp->face].sprite->bitmap->w * zoom_x +
664  border_left;
665 
666  if (box.w > w) {
667  box.w = w;
668  }
669 
670  border_left = 0;
671  } else {
672  if (box.w + border_left > w) {
673  box.w -= ((box.w + border_left) - w);
674  }
675  }
676 
677  if (border_up < 0) {
678  box.y = -border_up;
679  box.h = FaceList[tmp->face].sprite->bitmap->h * zoom_y + border_up;
680 
681  if (box.h > h) {
682  box.h = h;
683  }
684 
685  border_up = 0;
686  } else {
687  if (box.h + border_up > h) {
688  box.h -= ((box.h + border_up) - h);
689  }
690  }
691  }
692 
694  memset(&effects, 0, sizeof(effects));
695  snprintf(VS(effects.glow), "%s", tmp->glow);
696  effects.glow_speed = tmp->glow_speed;
697  effects.glow_state = tmp->glow_state;
698  effects.zoom_x = zoom_x * 100.0;
699  effects.zoom_y = zoom_y * 100.0;
700 
701  if (effects.glow[0] != '\0') {
702  BIT_SET(effects.flags, SPRITE_FLAG_DARK);
703  effects.dark_level = 0;
704  }
705 
706  surface_show_effects(surface, x + border_left, y + border_up, &box,
707  FaceList[tmp->face].sprite->bitmap, &effects);
708 }
void surface_show_effects(SDL_Surface *surface, int x, int y, SDL_Rect *srcrect, SDL_Surface *src, const sprite_effects_t *effects)
Definition: sprite.c:830
object * below
Definition: player.h:114
object * object_find_object(object *op, tag_t tag)
Definition: item.c:116
char glow[7]
Definition: item.h:109
SDL_Surface * bitmap
Definition: sprite.h:96
uint16_t animation_id
Definition: item.h:75
uint8_t glow_state
Definition: item.h:115
int16_t zoom_x
Horizontal zoom.
Definition: sprite.h:50
void animate_objects(void)
Definition: item.c:510
struct region_map * region_map
Definition: map.h:169
object * object_create(object *env, tag_t tag, int bflag)
Definition: item.c:327
void check_animation_status(int anum)
Definition: client.c:150
#define SPRITE_FLAG_DARK
Definition: sprite.h:70
int16_t face
Definition: item.h:72
uint32_t flags
Bit combination of Sprite drawing flags.
Definition: sprite.h:46
struct obj * prev
Definition: item.h:51
object * object_find_object_inv(object *op, tag_t tag)
Definition: item.c:96
int border_left
Definition: sprite.h:90
int border_down
Definition: sprite.h:87
void object_transfer_inventory(object *op, object *to)
Definition: item.c:295
int object_animate(object *ob)
Definition: item.c:442
int border_right
Definition: sprite.h:93
#define SPRITE_GLOW_SIZE
Definition: sprite.h:40
object * sack
Definition: player.h:117
uint32_t tag
Definition: item.h:63
static mempool_struct * pool_object
Definition: item.c:37
void objects_deinit(void)
Definition: item.c:418
double weight
Definition: item.h:69
uint8_t direction
Definition: item.h:106
void toggle_locked(object *op)
Definition: item.c:347
uint8_t glow_speed
Definition: item.h:112
_mapdata MapData
Definition: map.c:64
void object_send_mark(object *op)
Definition: item.c:366
tag_t mark_count
Definition: player.h:143
Client_Player cpl
Definition: client.c:50
_face_struct FaceList[MAX_FACE_TILES]
Definition: main.c:77
struct obj * env
Definition: item.h:54
#define NROF_ITEMS
Definition: item.h:34
uint16_t last_anim
Definition: item.h:84
widgetdata * cur_widget[TOTAL_SUBWIDGETS]
Definition: widget.c:75
void object_init(void)
Definition: item.c:42
static void animate_inventory(object *op)
Definition: item.c:488
object * interface
Definition: player.h:120
int border_up
Definition: sprite.h:84
uint8_t dark_level
Dark level.
Definition: sprite.h:47
struct obj * next
Definition: item.h:45
void objects_free(object *op)
Definition: item.c:64
uint16_t anim_state
Definition: item.h:81
object * object_find(tag_t tag)
Definition: item.c:139
uint16_t anim_speed
Definition: item.h:78
uint8_t itype
Definition: item.h:90
int16_t zoom_y
Vertical zoom.
Definition: sprite.h:51
void object_remove(object *op)
Definition: item.c:174
struct obj * inv
Definition: item.h:57
uint32_t flags
Definition: item.h:87
void object_show_centered(SDL_Surface *surface, object *tmp, int x, int y, int w, int h, bool fit)
Definition: item.c:545
void interface_redraw(void)
Definition: interface.c:654
void objects_init(void)
Definition: item.c:427
void object_deinit(void)
Definition: item.c:54
static effect_struct * effects
Definition: effects.c:36
object * ob
Definition: player.h:111
void object_remove_inventory(object *op)
Definition: item.c:217
static void object_add(object *env, object *op, int bflag)
Definition: item.c:250