Atrinik Server  4.0
spawn_point.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 <monster_guard.h>
34 #include <arch.h>
35 #include <object.h>
36 #include <exp.h>
37 #include <object_methods.h>
38 
49 static object *
50 spawn_point_generate (object *op, object *monster)
51 {
52  HARD_ASSERT(op != NULL);
53  HARD_ASSERT(monster != NULL);
54 
55  int i = map_free_spot_first(op->map, op->x, op->y, monster->arch, monster);
56  if (i == -1) {
57  return NULL;
58  }
59 
60  object *tmp = object_get();
61  monster->type = MONSTER;
62  object_copy(tmp, monster, false);
63  monster->type = SPAWN_POINT_MOB;
64 
65  tmp->x = op->x + freearr_x[i];
66  tmp->y = op->y + freearr_y[i];
67 
68  if (tmp->item_condition != 0) {
69  int level = MAX(1, MIN(tmp->level, MAXLEVEL));
70  int min, max;
71  switch (tmp->item_condition) {
73  min = level_color[op->map->difficulty].green;
74  max = level_color[op->map->difficulty].blue - 1;
75  break;
76 
78  min = level_color[op->map->difficulty].blue;
79  max = level_color[op->map->difficulty].yellow - 1;
80  break;
81 
83  min = level_color[op->map->difficulty].yellow;
84  max = level_color[op->map->difficulty].orange - 1;
85  break;
86 
88  min = level_color[op->map->difficulty].orange;
89  max = level_color[op->map->difficulty].red - 1;
90  break;
91 
93  min = level_color[op->map->difficulty].red;
94  max = level_color[op->map->difficulty].purple - 1;
95  break;
96 
98  min = level_color[op->map->difficulty].purple;
99  max = min + 1;
100  break;
101 
102  default:
103  min = level;
104  max = min;
105  }
106 
107  tmp->level = rndm(MAX(level, MIN(min, MAXLEVEL)),
108  MAX(level, MIN(max, MAXLEVEL)));
109  }
110 
111  if (tmp->randomitems != NULL) {
112  treasure_generate(tmp->randomitems, tmp, tmp->level, 0);
113  }
114 
115  return tmp;
116 }
117 
128 static bool
129 spawn_point_can_generate (object *op, object *monster)
130 {
131  HARD_ASSERT(op != NULL);
132  HARD_ASSERT(monster != NULL);
133 
134  if (op->map == NULL) {
135  return false;
136  }
137 
138  /* Check if the time is right for the monster to be spawned. */
139  shstr *spawn_time = object_get_value(monster, "spawn_time");
140  if (spawn_time != NULL) {
141  int hour, minute, hour2, minute2;
142  if (sscanf(spawn_time,
143  "%d:%d - %d:%d",
144  &hour,
145  &minute,
146  &hour2,
147  &minute2) == 4) {
148  timeofday_t tod;
149  get_tod(&tod);
150 
151  if (hour <= hour2) {
152  /* Same day. */
153  if (tod.hour < hour || tod.hour > hour2) {
154  return false;
155  }
156  } else {
157  /* Overnight. */
158  if (tod.hour < hour && tod.hour > hour2) {
159  return false;
160  }
161  }
162 
163  /* Check minutes. */
164  if ((tod.hour == hour && tod.minute < minute) ||
165  (tod.hour == hour2 && tod.minute > minute2)) {
166  return false;
167  }
168 
169  return true;
170  } else {
171  LOG(ERROR,
172  "Syntax error in spawn_time attribute: %s, monster: %s",
173  spawn_time,
174  object_get_str(monster));
175  }
176  }
177 
178  return true;
179 }
180 
182 static void
183 process_func (object *op)
184 {
185  HARD_ASSERT(op != NULL);
186 
187  /* See if the spawn point should get a chance to do its processing. */
188  if (op->last_sp != -1 && op->last_grace && !rndm_chance(op->last_grace)) {
189  return;
190  }
191 
192  /* If the spawn point already has a generated monster, check whether
193  * the generated monster is still allowed to be spawned. If not,
194  * remove it and proceed normally. */
195  if (OBJECT_VALID(op->enemy, op->enemy_count)) {
196  if (spawn_point_can_generate(op, op->enemy)) {
197  return;
198  }
199 
201  object_remove(op->enemy, 0);
202  object_destroy(op->enemy);
203  op->enemy = NULL;
204  }
205 
206  /* Calculate the total chance. */
207  int total_chance = 0;
208  FOR_INV_PREPARE(op, tmp) {
209  if (tmp->type != SPAWN_POINT_MOB) {
210  continue;
211  }
212 
213  total_chance += MAX(1, tmp->enemy_count);
214  } FOR_INV_FINISH();
215 
216  /* No total chance, this means there are no monsters in this
217  * spawn point. */
218  if (total_chance == 0) {
219  return;
220  }
221 
222  /* Decide which monster to generate. */
223  int roll = rndm(0, total_chance - 1);
224  object *spawn_monster = NULL;
225  FOR_INV_PREPARE(op, tmp) {
226  if (tmp->type != SPAWN_POINT_MOB) {
227  continue;
228  }
229 
230  roll -= MAX(1, tmp->enemy_count);
231  if (roll < 0) {
232  spawn_monster = tmp;
233  break;
234  }
235  } FOR_INV_FINISH();
236 
237  /* Didn't find any monster to generate, or it can't be generated. */
238  if (spawn_monster == NULL || !spawn_point_can_generate(op, spawn_monster)) {
239  return;
240  }
241 
242  /* Try to generate the monster. */
243  object *monster = spawn_point_generate(op, spawn_monster);
244  if (monster == NULL) {
245  return;
246  }
247 
248  SET_MULTI_FLAG(monster, FLAG_SPAWN_MOB);
249 
250  /* Link the generated monster to the spawn point. */
251  op->enemy = monster;
252  op->enemy_count = monster->count;
253 
254  op->last_sp = 0;
255 
256  /* Clone the items the base monster had in its inventory, and insert
257  * them into the generated monster. */
258  FOR_INV_PREPARE(spawn_monster, tmp) {
259  if (tmp->type == RANDOM_DROP) {
260  if (tmp->weight_limit != 0 && !rndm_chance(tmp->weight_limit)) {
261  continue;
262  }
263 
264  FOR_INV_PREPARE(tmp, tmp2) {
265  object *copy = object_get();
266  object_copy_full(copy, tmp2);
267  object_insert_into(copy, monster, 0);
268  } FOR_INV_FINISH();
269  } else {
270  object *copy = object_get();
271  object_copy_full(copy, tmp);
272  object_insert_into(copy, monster, 0);
273  }
274  } FOR_INV_FINISH();
275 
276  /* Create spawn info. */
277  object *tmp = arch_to_object(op->other_arch);
278  /* Link the spawn point to the spawn info. */
279  tmp->owner = op;
280  tmp->ownercount = op->count;
281  object_insert_into(tmp, monster, 0);
282 
283  /* Insert the generated monster into the map. */
284  monster = object_insert_map(monster, op->map, op, 0);
285  SOFT_ASSERT(monster != NULL,
286  "Failed to insert monster, spawn point: %s",
287  object_get_str(op));
288  living_update_monster(monster);
289  monster_guard_activate_gate(monster, 0);
290 }
291 
293 static int
294 trigger_func (object *op, object *cause, int state)
295 {
296  HARD_ASSERT(op != NULL);
297  HARD_ASSERT(cause != NULL);
298 
299  process_func(op);
300  return OBJECT_METHOD_OK;
301 }
302 
304 static void
305 insert_map_func (object *op)
306 {
307  HARD_ASSERT(op != NULL);
308 
309  objectlink *ol = get_objectlink();
310  ol->objlink.ob = op;
311 
313  NULL,
314  NULL,
316  ol);
317 }
318 
320 static void
321 remove_map_func (object *op)
322 {
323  HARD_ASSERT(op != NULL);
324 
325  for (objectlink *ol = op->map->linked_spawn_points;
326  ol != NULL;
327  ol = ol->next) {
328  if (ol->objlink.ob == op) {
329  objectlink_unlink(&op->map->linked_spawn_points, NULL, ol);
330  free_objectlink_simple(ol);
331  break;
332  }
333  }
334 }
335 
340 {
341  OBJECT_METHODS(SPAWN_POINT)->process_func = process_func;
342  OBJECT_METHODS(SPAWN_POINT)->trigger_func = trigger_func;
343  OBJECT_METHODS(SPAWN_POINT)->insert_map_func = insert_map_func;
344  OBJECT_METHODS(SPAWN_POINT)->remove_map_func = remove_map_func;
345 }
void object_destroy(object *ob)
Definition: object.c:1441
#define MONSTER
Definition: define.h:353
tag_t ownercount
Definition: object.h:219
Definition: object.h:488
#define FLAG_SPAWN_MOB
Definition: define.h:1279
int purple
Definition: exp.h:55
tag_t enemy_count
Definition: object.h:216
static void insert_map_func(object *op)
Definition: spawn_point.c:305
object * object_get(void)
Definition: object.c:993
void treasure_generate(treasure_list_t *treasure_list, object *op, int difficulty, int flags)
Definition: treasure.c:1641
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:1691
#define FOR_INV_FINISH()
Definition: define.h:1698
objectlink * linked_spawn_points
Definition: map.h:591
int blue
Definition: exp.h:43
int minute
Definition: tod.h:82
shstr * object_get_value(const object *op, const char *const key)
Definition: object.c:2515
struct treasure_list * randomitems
Definition: object.h:231
void object_copy(object *op, const object *src, bool no_speed)
Definition: object.c:886
int yellow
Definition: exp.h:46
int16_t last_sp
Definition: object.h:313
#define SPAWN_RELATIVE_LEVEL_BLUE
Definition: define.h:1590
#define SPAWN_RELATIVE_LEVEL_RED
Definition: define.h:1596
struct archetype * arch
Definition: object.h:225
struct obj * enemy
Definition: object.h:196
struct archetype * other_arch
Definition: object.h:228
void object_remove(object *op, int flags)
Definition: object.c:1623
void get_tod(timeofday_t *tod)
Definition: time.c:279
#define SPAWN_POINT
Definition: define.h:357
object * ob
Definition: object.h:496
int16_t y
Definition: object.h:276
const char * object_get_str(const object *op)
Definition: object.c:3151
static void process_func(object *op)
Definition: spawn_point.c:183
uint8_t item_condition
Definition: object.h:369
object * object_insert_into(object *op, object *where, int flag)
Definition: object.c:2158
struct mapdef * map
Definition: object.h:139
object * arch_to_object(archetype_t *at)
Definition: arch.c:446
int16_t last_grace
Definition: object.h:316
union oblnk::@3 objlink
int orange
Definition: exp.h:49
int red
Definition: exp.h:52
#define SPAWN_POINT_MOB
Definition: define.h:365
void living_update_monster(object *op)
Definition: living.c:1174
static int trigger_func(object *op, object *cause, int state)
Definition: spawn_point.c:294
OBJECT_TYPE_INIT_DEFINE(spawn_point)
Definition: spawn_point.c:339
int16_t x
Definition: object.h:273
object * object_insert_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1741
#define SPAWN_RELATIVE_LEVEL_ORANGE
Definition: define.h:1594
#define MAXLEVEL
Definition: global.h:221
#define RANDOM_DROP
Definition: define.h:429
int difficulty
Definition: map.h:650
#define SPAWN_RELATIVE_LEVEL_PURPLE
Definition: define.h:1598
int green
Definition: exp.h:40
#define SPAWN_RELATIVE_LEVEL_GREEN
Definition: define.h:1588
static object * spawn_point_generate(object *op, object *monster)
Definition: spawn_point.c:50
struct obj * owner
Definition: object.h:207
tag_t count
Definition: object.h:142
struct oblnk * next
Definition: object.h:500
void monster_guard_activate_gate(object *op, int state)
Definition: monster_guard.c:52
int freearr_x[SIZEOFFREE]
Definition: object.c:84
Definition: tod.h:65
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
static bool spawn_point_can_generate(object *op, object *monster)
Definition: spawn_point.c:129
int hour
Definition: tod.h:79
#define OBJECT_METHOD_OK
#define OBJECT_VALID(_ob_, _count_)
Definition: object.h:548
#define SPAWN_RELATIVE_LEVEL_YELLOW
Definition: define.h:1592
void monster_drop_arrows(object *op)
Definition: monster.c:1887
static void remove_map_func(object *op)
Definition: spawn_point.c:321
int map_free_spot_first(mapstruct *m, int x, int y, archetype_t *at, object *op)
Definition: map.c:3009
int8_t level
Definition: object.h:347
int freearr_y[SIZEOFFREE]
Definition: object.c:99
void object_copy_full(object *op, const object *src)
Definition: object.c:970