/* * 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); }