Atrinik Server  4.0
sign.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 
32 #include <global.h>
33 #include <toolkit/packet.h>
34 #include <plugin.h>
35 #include <player.h>
36 #include <object.h>
37 #include <object_methods.h>
38 #include <check_inv.h>
39 
41 static int
42 apply_func (object *op, object *applier, int aflags)
43 {
44  HARD_ASSERT(op != NULL);
45  HARD_ASSERT(applier != NULL);
46 
47  /* No point in non-players applying signs. */
48  if (applier->type != PLAYER) {
49  return OBJECT_METHOD_OK;
50  }
51 
52  shstr *notification_msg = object_get_value(op, "notification_message");
53  if (op->msg == NULL &&
54  op->title == NULL &&
55  notification_msg == NULL &&
56  !HAS_EVENT(op, EVENT_SAY)) {
57  draw_info(COLOR_WHITE, applier, "Nothing is written on it.");
58  return OBJECT_METHOD_OK;
59  }
60 
61  if (op->stats.food != 0) {
62  if (op->last_eat >= op->stats.food) {
63  if (!QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
64  draw_info(COLOR_WHITE, applier, "You cannot read it anymore.");
65  }
66 
67  return OBJECT_METHOD_OK;
68  }
69 
70  op->last_eat++;
71  }
72 
73  if (QUERY_FLAG(applier, FLAG_BLIND) && !QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
74  draw_info(COLOR_WHITE, applier, "You are unable to read while blind.");
75  return OBJECT_METHOD_OK;
76  }
77 
78  if (op->slaying != NULL || op->stats.hp != 0 || op->race != NULL) {
79  object *match = check_inv(op, applier);
80 
81  if ((match != NULL && op->last_sp != 0) ||
82  (match == NULL && op->last_sp == 0)) {
83  if (!QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
84  draw_info(COLOR_WHITE, applier,
85  "You are unable to decipher the strange symbols.");
86  }
87 
88  return OBJECT_METHOD_OK;
89  }
90  }
91 
92  if (op->direction != 0 && QUERY_FLAG(op, FLAG_SYS_OBJECT)) {
93  if (applier->direction != absdir(op->direction + 4) &&
94  !(QUERY_FLAG(op, FLAG_SPLITTING) &&
95  (applier->direction == absdir(op->direction - 5) ||
96  applier->direction == absdir(op->direction + 5)))) {
97  return OBJECT_METHOD_OK;
98  }
99  }
100 
101  /* Handle the 'say' event. */
102  if (trigger_event(EVENT_SAY, applier, op, NULL, NULL, 0, 0, 0, 0)) {
103  return OBJECT_METHOD_OK;
104  }
105 
106  if (op->title != NULL) {
107  play_sound_player_only(CONTR(applier),
108  CMD_SOUND_EFFECT,
109  op->title,
110  0,
111  0,
112  0,
113  0);
114  }
115 
116  if (op->msg != NULL) {
117  draw_info(COLOR_NAVY, applier, op->msg);
118  }
119 
120  /* Add notification message, if any. */
121  if (notification_msg != NULL) {
122  shstr *notification_action =
123  object_get_value(op, "notification_action");
124  shstr *notification_shortcut =
125  object_get_value(op, "notification_shortcut");
126  shstr *notification_delay =
127  object_get_value(op, "notification_delay");
128 
129  packet_struct *packet = packet_new(CLIENT_CMD_NOTIFICATION, 256, 512);
130 
131  packet_debug_data(packet, 0, "\nNotification command type");
132  packet_append_uint8(packet, CMD_NOTIFICATION_TEXT);
133  packet_debug_data(packet, 0, "Text");
134  packet_append_string_terminated(packet, notification_msg);
135 
136  if (notification_action != NULL) {
137  packet_debug_data(packet, 0, "\nNotification command type");
138  packet_append_uint8(packet, CMD_NOTIFICATION_ACTION);
139  packet_debug_data(packet, 0, "Action");
140  packet_append_string_terminated(packet, notification_action);
141  }
142 
143  if (notification_shortcut != NULL) {
144  packet_debug_data(packet, 0, "\nNotification command type");
145  packet_append_uint8(packet, CMD_NOTIFICATION_SHORTCUT);
146  packet_debug_data(packet, 0, "Shortcut");
147  packet_append_string_terminated(packet, notification_shortcut);
148  }
149 
150  if (notification_delay != NULL) {
151  packet_debug_data(packet, 0, "\nNotification command type");
152  packet_append_uint8(packet, CMD_NOTIFICATION_DELAY);
153  packet_debug_data(packet, 0, "Delay");
154  packet_append_uint32(packet, atoi(notification_delay));
155  }
156 
157  socket_send_packet(CONTR(applier)->cs, packet);
158  }
159 
160  return OBJECT_METHOD_OK;
161 }
162 
164 static int
165 move_on_func (object *op, object *victim, object *originator, int state)
166 {
167  HARD_ASSERT(op != NULL);
168  HARD_ASSERT(victim != NULL);
169 
170  return apply_func(op, victim, 0);
171 }
172 
174 static int
175 trigger_func (object *op, object *cause, int state)
176 {
177  HARD_ASSERT(op != NULL);
178  HARD_ASSERT(cause != NULL);
179 
180  /* If the event is caused by a move-off and the object that caused
181  * the event is a player, return immediately. This is done because
182  * events are asynchronous, so when this code runs because of the
183  * move-off, it means the player that caused the event was removed
184  * from the map (temporarily, to be inserted immediately afterwards,
185  * but the event is caused by the removal), and also from the linked
186  * list of map's players, thus even if we proceeded as normal, the
187  * activator would not get the message/music/etc data from the sign
188  * object, only other nearby players. */
189  if (state == 0 && cause->type == PLAYER) {
190  return OBJECT_METHOD_OK;
191  }
192 
193  if (op->stats.food != 0) {
194  if (op->last_eat >= op->stats.food) {
195  return OBJECT_METHOD_OK;
196  }
197 
198  op->last_eat++;
199  }
200 
201  if (op->title != NULL) {
202  play_sound_map(op->map,
203  CMD_SOUND_EFFECT,
204  op->title,
205  op->x,
206  op->y,
207  0,
208  0);
209  }
210 
211  if (op->msg != NULL) {
212  draw_info_map(CHAT_TYPE_GAME,
213  NULL,
214  COLOR_NAVY,
215  op->map,
216  op->x,
217  op->y,
219  NULL,
220  NULL,
221  op->msg);
222  }
223 
224  return OBJECT_METHOD_OK;
225 }
226 
231 {
232  OBJECT_METHODS(SIGN)->apply_func = apply_func;
233  OBJECT_METHODS(SIGN)->move_on_func = move_on_func;
234  OBJECT_METHODS(SIGN)->trigger_func = trigger_func;
235 }
#define FLAG_SYS_OBJECT
Definition: define.h:1243
const char * race
Definition: object.h:174
int trigger_event(int event_type, object *const activator, object *const me, object *const other, const char *msg, int parm1, int parm2, int parm3, int flags)
Definition: plugins.c:510
OBJECT_TYPE_INIT_DEFINE(sign)
Definition: sign.c:230
shstr * object_get_value(const object *op, const char *const key)
Definition: object.c:2515
const char * slaying
Definition: object.h:180
int16_t last_sp
Definition: object.h:313
#define FLAG_BLIND
Definition: define.h:884
#define HAS_EVENT(ob, event)
Definition: plugin.h:179
static int absdir(int d)
Definition: define.h:1838
#define PLAYER
Definition: define.h:122
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
int32_t hp
Definition: living.h:72
const char * title
Definition: object.h:171
int16_t y
Definition: object.h:276
int8_t direction
Definition: object.h:350
#define MAP_INFO_NORMAL
Definition: global.h:83
static int trigger_func(object *op, object *cause, int state)
Definition: sign.c:175
#define FLAG_SPLITTING
Definition: define.h:996
struct mapdef * map
Definition: object.h:139
void play_sound_player_only(player *pl, int type, const char *filename, int x, int y, int loop, int volume)
Definition: sounds.c:66
#define EVENT_SAY
Definition: plugin.h:85
#define SIGN
Definition: define.h:409
int16_t x
Definition: object.h:273
int16_t last_eat
Definition: object.h:319
object * check_inv(object *op, object *ob)
Definition: check_inv.c:49
static int apply_func(object *op, object *applier, int aflags)
Definition: sign.c:42
void play_sound_map(mapstruct *map, int type, const char *filename, int x, int y, int loop, int volume)
Definition: sounds.c:159
living stats
Definition: object.h:481
void draw_info_map(uint8_t type, const char *name, const char *color, mapstruct *map, int x, int y, int dist, object *op, object *op2, const char *buf)
Definition: info.c:195
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
const char * msg
Definition: object.h:183
#define OBJECT_METHOD_OK
static int move_on_func(object *op, object *victim, object *originator, int state)
Definition: sign.c:165
int16_t food
Definition: living.h:84