/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
* Copyright (©) 2002 Mark Wedel & Crossfire Development Team
* Copyright (©) 1992 Frank Tore Johansen
*
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero GNU General Public License as published by the
* Free Software Foundation, either version 3 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 Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
*
* The authors can be reached via e-mail to
*/
/* the contents of this file were create solely by peterm@soda.berkeley.edu
all of the above disclaimers apply. */
#include
#include
#include
#include
/* name of the person to resurrect and which spell was used
* to resurrect
*/
static int
resurrect_player (object *op, char *playername, object *spell)
{
FILE *deadplayer, *liveplayer;
char oldname[MAX_BUF];
char newname[MAX_BUF];
char path[MAX_BUF];
char buf[MAX_BUF];
char buf2[MAX_BUF];
const char *race = NULL;
sint64 exp;
int Con;
/* reincarnation, which changes the race */
if (spell->race)
{
treasurelist *tl = treasurelist::find (spell->race);
treasure *t;
int value;
if (!tl)
{
LOG (llevError, "resurrect_player: race set to %s, but no treasurelist of that name!\n", &spell->race);
return 0;
}
value = rndm (tl->total_chance);
for (t = tl->items; t; t = t->next)
{
value -= t->chance;
if (value < 0)
break;
}
if (!t || !t->item)
{
LOG (llevError, "resurrect_player: got null treasure from treasurelist %s!\n", &spell->race);
return 0;
}
race = t->item->archname;
}
/* set up our paths/strings... */
sprintf (path, "%s/%s/%s/%s", settings.localdir, settings.playerdir, playername, playername);
strcpy (newname, path);
strcat (newname, ".pl");
strcpy (oldname, newname);
strcat (oldname, ".dead");
if (!(deadplayer = fopen (oldname, "r")))
{
new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s cannot be reached.", playername);
return 0;
}
if (!access (newname, 0))
{
new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s has already been reborn!", playername);
fclose (deadplayer);
return 0;
}
if (!(liveplayer = fopen (newname, "w")))
{
new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s cannot be re-embodied at the moment.", playername);
LOG (llevError, "Cannot write player in resurrect_player!\n");
fclose (deadplayer);
return 0;
}
while (!feof (deadplayer))
{
fgets (buf, 255, deadplayer);
sscanf (buf, "%s", buf2);
if (!(strcmp (buf2, "exp")))
{
sscanf (buf, "%s %" SCNd64, buf2, &exp);
if (spell->stats.exp)
{
exp -= exp / spell->stats.exp;
sprintf (buf, "exp %" PRId64 "\n", exp);
}
}
if (!(strcmp (buf2, "Con")))
{
sscanf (buf, "%s %d", buf2, &Con);
Con -= spell->stats.Con;
if (Con < 1)
Con = 1;
sprintf (buf, "Con %d\n", Con);
}
if (race && !strcmp (buf2, "race"))
{
sprintf (buf, "race %s\n", race);
}
fputs (buf, liveplayer);
}
fclose (liveplayer);
fclose (deadplayer);
unlink (oldname);
new_draw_info_format (NDI_UNIQUE, 0, op, "%s lives again!", playername);
return 1;
}
static int
resurrection_fails (int levelcaster, int leveldead)
{
int chance = 9;
/* scheme: equal in level, 50% success.
* +5 % for each level below, -5% for each level above.
* minimum 20%
*/
chance += levelcaster - leveldead;
if (chance < 4)
chance = 4;
if (chance > rndm (0, 19))
return 0; /* resurrection succeeds */
return 1;
}
/* raise_dead by peterm and mehlhaff@soda.berkeley.edu
* op -- who is doing the resurrecting
* spell - spell object
* dir -- direction the spell is cast
* corpseobj - corpse to raise - can be null, in which case this function will find it
*/
int
cast_raise_dead_spell (object *op, object *caster, object *spell, int dir, const char *arg)
{
object *temp, *newob;
char name_to_resurrect[MAX_BUF];
int leveldead = 25, mflags, clevel;
sint16 sx, sy;
maptile *m;
clevel = casting_level (caster, spell);
if (spell->last_heal)
{
if (!arg)
{
new_draw_info_format (NDI_UNIQUE, 0, op, "Cast %s on who?", &spell->name);
return 0;
}
strcpy (name_to_resurrect, arg);
temp = NULL;
}
else
{
sx = op->x + freearr_x[dir];
sy = op->y + freearr_y[dir];
m = op->map;
mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
if (mflags & P_OUT_OF_MAP)
temp = NULL;
else
{
/* First we need to find a corpse, if any. */
/* If no object, temp will be set to NULL */
for (temp = GET_MAP_OB (m, sx, sy); temp != NULL; temp = temp->above)
/* If it is corpse, this must be what we want to raise */
if (temp->type == CORPSE)
break;
}
if (temp == NULL)
{
new_draw_info (NDI_UNIQUE, 0, op, "You need a body for this spell.");
return 0;
}
strcpy (name_to_resurrect, temp->name);
}
/* no matter what, we fry the corpse. */
if (temp && temp->map)
{
/* replace corpse object with a burning object */
newob = archetype::get (shstr_burnout);
if (newob)
newob->insert_at (temp, op);
leveldead = temp->level;
temp->destroy ();
}
if (resurrection_fails (clevel, leveldead))
{
if (spell->randomitems)
for (treasure *t = spell->randomitems->items; t; t = t->next)
if (t->item)
summon_hostile_monsters (op, t->nrof, t->item->archname);
return 1;
}
else
return resurrect_player (op, name_to_resurrect, spell);
}