server-1.12/random_maps/monster.c

137 lines
4.4 KiB
C

/*
* static char *rcsid_monster_c =
* "$Id: monster.c 11578 2009-02-23 22:02:27Z lalo $";
*/
/*
CrossFire, A Multiplayer game for X-windows
Copyright (C) 2002 Mark Wedel & Crossfire Development Team
Copyright (C) 1992 Frank Tore Johansen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
The authors can be reached via e-mail at crossfire-devel@real-time.com
*/
/**
* @file
* Monster placement for random maps.
*/
#include <global.h>
#include <random_map.h>
#include <rproto.h>
/**
* Inserts a monster in the map.
* Some monsters are multisquare, and these guys require special
* handling.
* @param new_obj
* monster to insert. Its x and y fields must be the desired location.
* @param map
* where to insert to.
* @todo
* there probably is a function in the common library for that, so remove this one.
*/
void insert_multisquare_ob_in_map(object *new_obj, mapstruct *map) {
int x, y;
archetype *at;
object *old_seg;
object *head;
/* first insert the head */
insert_ob_in_map(new_obj, map, new_obj, INS_NO_MERGE|INS_NO_WALK_ON);
x = new_obj->x;
y = new_obj->y;
old_seg = new_obj;
head = new_obj;
for (at = new_obj->arch->more; at != NULL; at = at->more) {
object *new_seg;
new_seg = arch_to_object(at);
new_seg->x = x+at->clone.x;
new_seg->y = y+at->clone.y;
new_seg->map = old_seg->map;
insert_ob_in_map(new_seg, new_seg->map, new_seg, INS_NO_MERGE|INS_NO_WALK_ON);
new_seg->head = head;
old_seg->more = new_seg;
old_seg = new_seg;
}
old_seg->more = NULL;
}
/**
* Place some monsters into the map. Their experience is linked to difficulty to insert a
* suitable number of critters.
* @param map
* where to put monsters on.
* @param monsterstyle
* style. Can be NULL, in which case a random one is used.
* @param difficulty
* how difficult the monsters should be, and how many there should be.
* @param RP
* random map parameters.
*/
void place_monsters(mapstruct *map, char *monsterstyle, int difficulty, RMParms *RP) {
char styledirname[256];
mapstruct *style_map = NULL;
int failed_placements;
sint64 exp_per_sq, total_experience;
int number_monsters = 0;
archetype *at;
snprintf(styledirname, sizeof(styledirname), "%s", "/styles/monsterstyles");
style_map = find_style(styledirname, monsterstyle, difficulty);
if (style_map == NULL)
return;
/* fill up the map with random monsters from the monster style*/
total_experience = 0;
failed_placements = 0;
exp_per_sq = 0;
while (exp_per_sq <= level_exp(difficulty, 1.0)
&& failed_placements < 100
&& number_monsters < (RP->Xsize*RP->Ysize)/8) {
object *this_monster = pick_random_object(style_map);
int x, y, freeindex;
if (this_monster == NULL)
return; /* no monster?? */
x = RANDOM()%RP->Xsize;
y = RANDOM()%RP->Ysize;
freeindex = find_first_free_spot(this_monster, map, x, y);
if (freeindex != -1) {
object *new_monster = arch_to_object(this_monster->arch);
x += freearr_x[freeindex];
y += freearr_y[freeindex];
copy_object_with_inv(this_monster, new_monster);
new_monster->x = x;
new_monster->y = y;
insert_multisquare_ob_in_map(new_monster, map);
total_experience += this_monster->stats.exp;
for (at = new_monster->arch; at != NULL; at = at->more)
number_monsters++;
RP->total_map_hp += new_monster->stats.hp; /* a global count */
} else {
failed_placements++;
}
exp_per_sq = ((double)1000*total_experience)/(MAP_WIDTH(map)*MAP_HEIGHT(map)+1);
}
}