ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/resurrection.C
Revision: 1.16
Committed: Wed Jan 3 02:30:52 2007 UTC (17 years, 5 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.15: +3 -2 lines
Log Message:
implemented proper support for empty treasures, which
sadly occur in empty treasure lists. fixing treasurelists
to have no entries at all would be even more complicated,
but even when this is fixed, the current changes only make the
server more crash robust to bad treasures.
Also removed the 'NONE' specialcase for treasure lists. Developers
should use 'none' instead now.

File Contents

# Content
1 /*
2 CrossFire, A Multiplayer game for X-windows
3
4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5 Copyright (C) 1992 Frank Tore Johansen
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 The authors can be reached via e-mail at <crossfire@schmorp.de>
22 */
23
24 /* the contents of this file were create solely by peterm@soda.berkeley.edu
25 all of the above disclaimers apply. */
26
27 #include <global.h>
28 #include <sproto.h>
29 #include <spells.h>
30 #include <errno.h>
31
32 extern char **classname;
33 extern object *objects;
34
35 /* name of the person to resurrect and which spell was used
36 * to resurrect
37 */
38 static int
39 resurrect_player (object *op, char *playername, object *spell)
40 {
41 FILE *deadplayer, *liveplayer;
42
43 char oldname[MAX_BUF];
44 char newname[MAX_BUF];
45 char path[MAX_BUF];
46 char buf[MAX_BUF];
47 char buf2[MAX_BUF];
48 const char *race = NULL;
49 sint64 exp;
50 int Con;
51
52 /* reincarnation, which changes the race */
53 if (spell->race)
54 {
55 treasurelist *tl = find_treasurelist (spell->race);
56 treasure *t;
57 int value;
58
59 if (!tl)
60 {
61 LOG (llevError, "resurrect_player: race set to %s, but no treasurelist of that name!\n", &spell->race);
62 return 0;
63 }
64 value = RANDOM () % tl->total_chance;
65 for (t = tl->items; t; t = t->next)
66 {
67 value -= t->chance;
68 if (value < 0)
69 break;
70 }
71 if (!t || !t->item)
72 {
73 LOG (llevError, "resurrect_player: got null treasure from treasurelist %s!\n", &spell->race);
74 return 0;
75 }
76 race = t->item->name;
77 }
78
79 /* set up our paths/strings... */
80 sprintf (path, "%s/%s/%s/%s", settings.localdir, settings.playerdir, playername, playername);
81
82 strcpy (newname, path);
83 strcat (newname, ".pl");
84
85 strcpy (oldname, newname);
86 strcat (oldname, ".dead");
87
88 if (!(deadplayer = fopen (oldname, "r")))
89 {
90 new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s cannot be reached.", playername);
91 return 0;
92 }
93
94 if (!access (newname, 0))
95 {
96 new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s has already been reborn!", playername);
97 fclose (deadplayer);
98 return 0;
99 }
100
101 if (!(liveplayer = fopen (newname, "w")))
102 {
103 new_draw_info_format (NDI_UNIQUE, 0, op, "The soul of %s cannot be re-embodied at the moment.", playername);
104 LOG (llevError, "Cannot write player in resurrect_player!\n");
105 fclose (deadplayer);
106 return 0;
107 }
108
109 while (!feof (deadplayer))
110 {
111 fgets (buf, 255, deadplayer);
112 sscanf (buf, "%s", buf2);
113 if (!(strcmp (buf2, "exp")))
114 {
115 sscanf (buf, "%s %" SCNd64, buf2, &exp);
116 if (spell->stats.exp)
117 {
118 exp -= exp / spell->stats.exp;
119 sprintf (buf, "exp %" PRId64 "\n", exp);
120 }
121 }
122 if (!(strcmp (buf2, "Con")))
123 {
124 sscanf (buf, "%s %d", buf2, &Con);
125 Con -= spell->stats.Con;
126 if (Con < 1)
127 Con = 1;
128 sprintf (buf, "Con %d\n", Con);
129 }
130 if (race && !strcmp (buf2, "race"))
131 {
132 sprintf (buf, "race %s\n", race);
133 }
134 fputs (buf, liveplayer);
135 }
136 fclose (liveplayer);
137 fclose (deadplayer);
138 unlink (oldname);
139 new_draw_info_format (NDI_UNIQUE, 0, op, "%s lives again!", playername);
140
141 return 1;
142 }
143
144
145 /* raise_dead by peterm and mehlhaff@soda.berkeley.edu
146 * op -- who is doing the resurrecting
147 * spell - spell object
148 * dir -- direction the spell is cast
149 * corpseobj - corpse to raise - can be null, in which case this function will find it
150 */
151 int
152 cast_raise_dead_spell (object *op, object *caster, object *spell, int dir, const char *arg)
153 {
154 object *temp, *newob;
155 char name_to_resurrect[MAX_BUF];
156 int leveldead = 25, mflags, clevel;
157 sint16 sx, sy;
158 maptile *m;
159
160 clevel = caster_level (caster, spell);
161
162 if (spell->last_heal)
163 {
164 if (!arg)
165 {
166 new_draw_info_format (NDI_UNIQUE, 0, op, "Cast %s on who?", &spell->name);
167 return 0;
168 }
169 strcpy (name_to_resurrect, arg);
170 temp = NULL;
171 }
172 else
173 {
174 sx = op->x + freearr_x[dir];
175 sy = op->y + freearr_y[dir];
176 m = op->map;
177 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
178 if (mflags & P_OUT_OF_MAP)
179 temp = NULL;
180 else
181 {
182 /* First we need to find a corpse, if any. */
183 /* If no object, temp will be set to NULL */
184 for (temp = GET_MAP_OB (m, sx, sy); temp != NULL; temp = temp->above)
185 /* If it is corpse, this must be what we want to raise */
186 if (temp->type == CORPSE)
187 break;
188 }
189
190 if (temp == NULL)
191 {
192 new_draw_info (NDI_UNIQUE, 0, op, "You need a body for this spell.");
193 return 0;
194 }
195 strcpy (name_to_resurrect, temp->name);
196 }
197
198 /* no matter what, we fry the corpse. */
199 if (temp && temp->map)
200 {
201 /* replace corpse object with a burning object */
202 newob = arch_to_object (archetype::find ("burnout"));
203 if (newob)
204 newob->insert_at (temp, op);
205
206 leveldead = temp->level;
207 temp->destroy ();
208 }
209
210 if (resurrection_fails (clevel, leveldead))
211 {
212 if (spell->randomitems)
213 for (treasure *t = spell->randomitems->items; t; t = t->next)
214 if (t->item)
215 summon_hostile_monsters (op, t->nrof, t->item->name);
216
217 return 1;
218
219 }
220 else
221 return resurrect_player (op, name_to_resurrect, spell);
222 }
223
224
225 int
226 resurrection_fails (int levelcaster, int leveldead)
227 {
228 int chance = 9;
229
230 /* scheme: equal in level, 50% success.
231 * +5 % for each level below, -5% for each level above.
232 * minimum 20%
233 */
234 chance += levelcaster - leveldead;
235 if (chance < 4)
236 chance = 4;
237 if (chance > rndm (0, 19))
238 return 0; /* resurrection succeeds */
239 return 1;
240 }
241
242 void
243 dead_player (object *op)
244 {
245 char filename[MAX_BUF];
246 char newname[MAX_BUF];
247 char path[MAX_BUF];
248
249 /* set up our paths/strings... */
250 sprintf (path, "%s/%s/%s/%s", settings.localdir, settings.playerdir, &op->name, &op->name);
251
252 strcpy (filename, path);
253 strcat (filename, ".pl");
254 strcpy (newname, filename);
255 strcat (newname, ".dead");
256
257 if (rename (filename, newname) != 0)
258 {
259 LOG (llevError, "Cannot rename dead player's file %s into %s: %s\n", filename, newname, strerror (errno));
260 }
261 }
262
263
264
265 void
266 dead_character (const char *name)
267 {
268 char buf[MAX_BUF];
269 char buf2[MAX_BUF];
270
271 sprintf (buf, "%s/%s/%s/%s.pl", settings.localdir, settings.playerdir, name, name);
272 /* peterm: create a .dead filename.... ***.pl.dead */
273 strcpy (buf2, buf);
274 strcat (buf, ".dead");
275 if (rename (buf2, buf) == -1)
276 {
277 LOG (llevError, "Cannot rename dead player's file %s into %s: %s\n", buf2, buf, strerror (errno));
278 }
279 }
280
281
282 int
283 dead_player_exists (const char *name)
284 {
285 char buf[MAX_BUF];
286
287 sprintf (buf, "%s/%s/%s/%s", settings.localdir, settings.playerdir, name, name);
288 strcat (buf, ".pl.dead");
289 return !(access (buf, 0));
290 }