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, 4 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

# User Rev Content
1 elmex 1.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 root 1.7 The authors can be reached via e-mail at <crossfire@schmorp.de>
22 elmex 1.1 */
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 root 1.14 #include <sproto.h>
29 elmex 1.1 #include <spells.h>
30     #include <errno.h>
31 root 1.5
32 elmex 1.1 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 root 1.5 static int
39     resurrect_player (object *op, char *playername, object *spell)
40 elmex 1.1 {
41 root 1.5 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 elmex 1.16 if (!t || !t->item)
72 root 1.5 {
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 elmex 1.1
88 root 1.5 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 root 1.10 sscanf (buf, "%s %" SCNd64, buf2, &exp);
116 root 1.5 if (spell->stats.exp)
117     {
118     exp -= exp / spell->stats.exp;
119 root 1.10 sprintf (buf, "exp %" PRId64 "\n", exp);
120 root 1.2 }
121     }
122 root 1.5 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 elmex 1.1
141 root 1.5 return 1;
142 elmex 1.1 }
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 root 1.5 int
152     cast_raise_dead_spell (object *op, object *caster, object *spell, int dir, const char *arg)
153 elmex 1.1 {
154 root 1.5 object *temp, *newob;
155     char name_to_resurrect[MAX_BUF];
156     int leveldead = 25, mflags, clevel;
157     sint16 sx, sy;
158 root 1.8 maptile *m;
159 root 1.5
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 root 1.2 }
169 root 1.5 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 root 1.2 temp = NULL;
180 root 1.5 else
181     {
182     /* First we need to find a corpse, if any. */
183     /* If no object, temp will be set to NULL */
184 root 1.13 for (temp = GET_MAP_OB (m, sx, sy); temp != NULL; temp = temp->above)
185 root 1.5 /* 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 elmex 1.1
198 root 1.5 /* no matter what, we fry the corpse. */
199     if (temp && temp->map)
200     {
201     /* replace corpse object with a burning object */
202 root 1.6 newob = arch_to_object (archetype::find ("burnout"));
203 root 1.15 if (newob)
204     newob->insert_at (temp, op);
205    
206 root 1.5 leveldead = temp->level;
207 root 1.12 temp->destroy ();
208 root 1.5 }
209    
210     if (resurrection_fails (clevel, leveldead))
211     {
212     if (spell->randomitems)
213 root 1.15 for (treasure *t = spell->randomitems->items; t; t = t->next)
214 elmex 1.16 if (t->item)
215     summon_hostile_monsters (op, t->nrof, t->item->name);
216 elmex 1.1
217 root 1.5 return 1;
218 elmex 1.1
219 root 1.5 }
220     else
221 root 1.15 return resurrect_player (op, name_to_resurrect, spell);
222 elmex 1.1 }
223    
224    
225 root 1.5 int
226     resurrection_fails (int levelcaster, int leveldead)
227 elmex 1.1 {
228 root 1.5 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 elmex 1.1 }
241    
242 root 1.5 void
243     dead_player (object *op)
244 elmex 1.1 {
245 root 1.5 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 elmex 1.1 }
261     }
262    
263    
264    
265 root 1.5 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 elmex 1.1 }
279     }
280    
281    
282 root 1.5 int
283     dead_player_exists (const char *name)
284     {
285     char buf[MAX_BUF];
286 elmex 1.1
287 root 1.5 sprintf (buf, "%s/%s/%s/%s", settings.localdir, settings.playerdir, name, name);
288     strcat (buf, ".pl.dead");
289     return !(access (buf, 0));
290 elmex 1.1 }