Atrinik Server  4.0
sound_ambient.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/string.h>
34 #include <object.h>
35 #include <object_methods.h>
36 #include <sound_ambient.h>
37 
43 enum {
46 };
47 
53 enum {
60 };
61 
67 enum {
73 };
74 
78 typedef struct sound_ambient_match {
80 
81  union {
83 
84  struct {
85  uint8_t type;
86 
87  uint8_t operation;
88 
89  uint16_t num;
90 
91  uint8_t operation2;
92 
93  uint16_t num2;
94  } operation;
95  } data;
96 
97  int is_group:1;
98 
99  int is_and:1;
100 } __attribute__((packed)) sound_ambient_match_t;
101 
108 static void
109 sound_ambient_match_free (sound_ambient_match_t *match)
110 {
111  HARD_ASSERT(match != NULL);
112 
113  for (sound_ambient_match_t *tmp = match, *next; tmp != NULL; tmp = next) {
114  next = tmp->next;
115 
116  if (tmp->is_group) {
117  sound_ambient_match_free(tmp->data.group);
118  }
119 
120  efree(tmp);
121  }
122 }
123 
125 static void
126 init_func (object *op)
127 {
128  HARD_ASSERT(op != NULL);
129  HARD_ASSERT(op->type == SOUND_AMBIENT);
130 
131  /* Must be on map... */
132  if (op->map == NULL) {
133  LOG(ERROR,
134  "Ambient sound effect object not on map: %s",
135  object_get_str(op));
136  return;
137  }
138 
139  if (string_isempty(op->race)) {
140  LOG(ERROR,
141  "Ambient sound effect object is missing sound effect filename: %s",
142  object_get_str(op));
143  return;
144  }
145 
146  MapSpace *msp = GET_MAP_SPACE_PTR(op->map, op->x, op->y);
147  msp->sound_ambient = op;
148  msp->sound_ambient_count = op->count;
149 }
150 
152 static void
153 deinit_func (object *op)
154 {
155  HARD_ASSERT(op != NULL);
156  HARD_ASSERT(op->type == SOUND_AMBIENT);
157 
158  if (op->custom_attrset != NULL) {
159  sound_ambient_match_free(op->custom_attrset);
160  op->custom_attrset = NULL;
161  }
162 }
163 
168 {
169  OBJECT_METHODS(SOUND_AMBIENT)->init_func = init_func;
170  OBJECT_METHODS(SOUND_AMBIENT)->deinit_func = deinit_func;
171 }
172 
184 static void
185 sound_ambient_match_print_rec (sound_ambient_match_t *match,
186  char *buf,
187  size_t size)
188 {
189  HARD_ASSERT(buf != NULL);
190 
191  for (sound_ambient_match_t *tmp = match; tmp != NULL; tmp = tmp->next) {
192  if (tmp != match) {
193  snprintfcat(buf, size, " ");
194  }
195 
196  if (tmp->is_group) {
197  snprintfcat(buf, size, "(");
198  sound_ambient_match_print_rec(tmp->data.group, buf, size);
199  snprintfcat(buf, size, ")");
200  } else {
201  switch (tmp->data.operation.type) {
202  case SA_OPER_TYPE_HOUR:
203  snprintfcat(buf, size, "hour");
204  break;
205 
206  case SA_OPER_TYPE_MINUTE:
207  snprintfcat(buf, size, "minute");
208  break;
209  }
210 
211  switch (tmp->data.operation.operation) {
212  case SA_OPER_NONE:
213  break;
214 
215  case SA_OPER_ADD:
216  snprintfcat(buf, size, " + ");
217  break;
218 
219  case SA_OPER_SUB:
220  snprintfcat(buf, size, " - ");
221  break;
222 
223  case SA_OPER_MUL:
224  snprintfcat(buf, size, " * ");
225  break;
226 
227  case SA_OPER_DIV:
228  snprintfcat(buf, size, " / ");
229  break;
230 
231  case SA_OPER_MOD:
232  snprintfcat(buf, size, " %% ");
233  break;
234  }
235 
236  if (tmp->data.operation.operation != SA_OPER_NONE) {
237  snprintfcat(buf, size, "%u", tmp->data.operation.num);
238  }
239 
240  switch (tmp->data.operation.operation2) {
241  case SA_OPER2_EQ:
242  snprintfcat(buf, size, " == ");
243  break;
244 
245  case SA_OPER2_LT:
246  snprintfcat(buf, size, " < ");
247  break;
248 
249  case SA_OPER2_GT:
250  snprintfcat(buf, size, " > ");
251  break;
252 
253  case SA_OPER2_LE:
254  snprintfcat(buf, size, " <= ");
255  break;
256 
257  case SA_OPER2_GE:
258  snprintfcat(buf, size, " >= ");
259  break;
260  }
261 
262  snprintfcat(buf, size, "%u", tmp->data.operation.num2);
263  }
264 
265  if (tmp->next != NULL) {
266  snprintfcat(buf, size, " %s", tmp->is_and ? "&&" : "||");
267  }
268  }
269 }
270 
279 static bool
280 sound_ambient_match_rec (sound_ambient_match_t *match)
281 {
282  if (match == NULL) {
283  return true;
284  }
285 
286  timeofday_t tod;
287  get_tod(&tod);
288 
289  for (sound_ambient_match_t *tmp = match; tmp != NULL; tmp = tmp->next) {
290  bool ret;
291  if (tmp->is_group) {
292  ret = sound_ambient_match_rec(tmp->data.group);
293  } else {
294  int value;
295  switch (tmp->data.operation.type) {
296  case SA_OPER_TYPE_HOUR:
297  value = tod.hour;
298  break;
299 
300  case SA_OPER_TYPE_MINUTE:
301  value = tod.minute;
302  break;
303 
304  default:
305  value = 0;
306  break;
307  }
308 
309  switch (tmp->data.operation.operation) {
310  case SA_OPER_ADD:
311  value += tmp->data.operation.num;
312  break;
313 
314  case SA_OPER_SUB:
315  value -= tmp->data.operation.num;
316  break;
317 
318  case SA_OPER_MUL:
319  value *= tmp->data.operation.num;
320  break;
321 
322  case SA_OPER_DIV:
323  value /= tmp->data.operation.num;
324  break;
325 
326  case SA_OPER_MOD:
327  value %= tmp->data.operation.num;
328  break;
329  }
330 
331  switch (tmp->data.operation.operation2) {
332  case SA_OPER2_EQ:
333  ret = value == tmp->data.operation.num2;
334  break;
335 
336  case SA_OPER2_LT:
337  ret = value < tmp->data.operation.num2;
338  break;
339 
340  case SA_OPER2_GT:
341  ret = value > tmp->data.operation.num2;
342  break;
343 
344  case SA_OPER2_LE:
345  ret = value <= tmp->data.operation.num2;
346  break;
347 
348  case SA_OPER2_GE:
349  ret = value >= tmp->data.operation.num2;
350  break;
351 
352  default:
353  ret = false;
354  break;
355  }
356  }
357 
358  if (ret && !tmp->is_and) {
359  return true;
360  } else if (!ret && tmp->is_and) {
361  return false;
362  }
363  }
364 
365  return false;
366 }
367 
377 const char *
379 {
380  HARD_ASSERT(op != NULL);
381 
382  static char buf[HUGE_BUF];
383  buf[0] = '\0';
385 
386  return buf;
387 }
388 
397 bool
399 {
400  HARD_ASSERT(op != NULL);
402 }
403 
413 void
414 sound_ambient_match_parse (object *op, const char *str)
415 {
416  HARD_ASSERT(op != NULL);
417  HARD_ASSERT(str != NULL);
418 
419  if (op->type != SOUND_AMBIENT) {
420  LOG(BUG, "Called on incorrect object type: %d", op->type);
421  return;
422  }
423 
424  if (op->custom_attrset != NULL) {
425  sound_ambient_match_free(op->custom_attrset);
426  op->custom_attrset = NULL;
427  }
428 
429  sound_ambient_match_t *match = NULL;
430  sound_ambient_match_t *match_stack[10];
431  memset(match_stack, 0, 10 * sizeof(*match_stack));
432  size_t stack_id = 0;
433  size_t group_num = 0;
434  size_t group_end_num = 0;
435  size_t word_num = 0;
436 
437  char word[64];
438  size_t pos = 0;
439  while (string_get_word(str, &pos, ' ', word, sizeof(word), 0)) {
440  char *cp = word;
441 
442  while (string_startswith(cp, "(")) {
443  cp++;
444  stack_id++;
445 
446  sound_ambient_match_t *tmp =
447  ecalloc(1, sizeof(sound_ambient_match_t));
448  tmp->is_group = 1;
449 
450  if (match_stack[stack_id - 1] != NULL) {
451  if (match_stack[stack_id - 1]->is_group &&
452  match_stack[stack_id - 1]->data.group == NULL) {
453  match_stack[stack_id - 1]->data.group = tmp;
454  } else {
455  match_stack[stack_id - 1]->next = tmp;
456  }
457  }
458 
459  match_stack[stack_id] = tmp;
460  match_stack[stack_id - 1] = tmp;
461  group_num++;
462  }
463 
464  while (string_endswith(word, ")")) {
465  word[strlen(word) - 1] = '\0';
466  group_end_num++;
467  }
468 
469  if (strcmp(cp, "&&") == 0) {
470  match_stack[stack_id]->is_and = 1;
471  match = NULL;
472  continue;
473  } else if (strcmp(cp, "||") == 0) {
474  match = NULL;
475  continue;
476  }
477 
478  if (match == NULL) {
479  match = ecalloc(1, sizeof(*match));
480  word_num = 0;
481 
482  if (op->custom_attrset == NULL) {
483  if (match_stack[0] != NULL) {
484  op->custom_attrset = match_stack[0];
485  } else {
486  op->custom_attrset = match;
487  }
488  }
489 
490  if (match_stack[stack_id] != NULL) {
491  if (match_stack[stack_id]->is_group &&
492  group_num != 0 &&
493  match_stack[stack_id]->data.group == NULL) {
494  match_stack[stack_id]->data.group = match;
495  } else {
496  match_stack[stack_id]->next = match;
497  }
498  }
499 
500  match_stack[stack_id] = match;
501  }
502 
503  if (word_num == 0) {
504  if (strcmp(cp, "hour") == 0) {
505  match->data.operation.type = SA_OPER_TYPE_HOUR;
506  } else if (strcmp(cp, "minute") == 0) {
507  match->data.operation.type = SA_OPER_TYPE_MINUTE;
508  }
509  } else if (word_num == 1) {
510  if (strcmp(cp, "+") == 0) {
511  match->data.operation.operation = SA_OPER_ADD;
512  } else if (strcmp(cp, "-") == 0) {
513  match->data.operation.operation = SA_OPER_SUB;
514  } else if (strcmp(cp, "*") == 0) {
515  match->data.operation.operation = SA_OPER_MUL;
516  } else if (strcmp(cp, "/") == 0) {
517  match->data.operation.operation = SA_OPER_DIV;
518  } else if (strcmp(cp, "%") == 0) {
519  match->data.operation.operation = SA_OPER_MOD;
520  } else {
521  word_num += 2;
522  }
523  } else if (word_num == 2) {
524  match->data.operation.num = atoi(cp);
525  }
526 
527  if (word_num == 3) {
528  if (strcmp(cp, "==") == 0) {
529  match->data.operation.operation2 = SA_OPER2_EQ;
530  } else if (strcmp(cp, "<") == 0) {
531  match->data.operation.operation2 = SA_OPER2_LT;
532  } else if (strcmp(cp, ">") == 0) {
533  match->data.operation.operation2 = SA_OPER2_GT;
534  } else if (strcmp(cp, "<=") == 0) {
535  match->data.operation.operation2 = SA_OPER2_LE;
536  } else if (strcmp(cp, ">=") == 0) {
537  match->data.operation.operation2 = SA_OPER2_GE;
538  }
539  } else if (word_num == 4) {
540  match->data.operation.num2 = atoi(cp);
541  }
542 
543  if (group_end_num != 0) {
544  if (stack_id > 0) {
545  stack_id -= group_end_num;
546  }
547 
548  group_num -= group_end_num;
549  group_end_num = 0;
550  match = NULL;
551  }
552 
553  word_num++;
554  }
555 }
uint8_t type
One of operation types.
Definition: sound_ambient.c:85
Addition.
Definition: sound_ambient.c:55
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:79
static void sound_ambient_match_print_rec(sound_ambient_match_t *match, char *buf, size_t size)
const char * race
Definition: object.h:174
void * custom_attrset
Definition: object.h:160
struct sound_ambient_match __attribute__((packed))
In-game minutes.
Definition: sound_ambient.c:45
uint8_t operation2
One of test operations.
Definition: sound_ambient.c:91
In-game hours.
Definition: sound_ambient.c:44
union sound_ambient_match::@19 data
Data about the rule.
int minute
Definition: tod.h:82
Test for equality.
Definition: sound_ambient.c:68
static bool sound_ambient_match_rec(sound_ambient_match_t *match)
Modulo.
Definition: sound_ambient.c:59
int is_group
Whether the data union points to a group of rules.
Definition: sound_ambient.c:57
void get_tod(timeofday_t *tod)
Definition: time.c:279
Test for less than.
Definition: sound_ambient.c:69
static void deinit_func(object *op)
int16_t y
Definition: object.h:276
int is_and
Whether this is an AND rule.
Definition: sound_ambient.c:99
const char * object_get_str(const object *op)
Definition: object.c:3151
OBJECT_TYPE_INIT_DEFINE(sound_ambient)
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:39
Test for less than or equal to.
Definition: sound_ambient.c:71
struct mapdef * map
Definition: object.h:139
tag_t sound_ambient_count
Definition: map.h:363
union @21 data
Data about the rule.
uint16_t num2
Arbitrary number for test operations.
Definition: sound_ambient.c:93
uint8_t operation
One of basic operations.
Definition: sound_ambient.c:87
Subtraction.
Definition: sound_ambient.c:56
Division.
Definition: sound_ambient.c:58
bool sound_ambient_match(object *op)
struct sound_ambient_match * group
Group of rules.
Definition: sound_ambient.c:82
int16_t x
Definition: object.h:273
No operation.
Definition: sound_ambient.c:54
const char * sound_ambient_match_str(object *op)
Test for greater than or equal to.
Definition: sound_ambient.c:72
uint16_t num
Arbitrary number for basic operations.
Definition: sound_ambient.c:89
tag_t count
Definition: object.h:142
Definition: tod.h:65
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
Multiplication.
Definition: sound_ambient.c:57
int hour
Definition: tod.h:79
#define SOUND_AMBIENT
Definition: define.h:300
int is_group
Whether the data union points to a group of rules.
Definition: sound_ambient.c:97
Test for greater than.
Definition: sound_ambient.c:70
static void init_func(object *op)
object * sound_ambient
Definition: map.h:348
void sound_ambient_match_parse(object *op, const char *str)