e.g., hit by drain life attack */
| 204 | |
| 205 | /* e.g., hit by drain life attack */ |
| 206 | void |
| 207 | losexp( |
| 208 | const char *drainer) /* cause of death, if drain should be fatal */ |
| 209 | { |
| 210 | int num, uhpmin, olduhpmax; |
| 211 | |
| 212 | /* override life-drain resistance when handling an explicit |
| 213 | wizard mode request to reduce level; never fatal though */ |
| 214 | if (drainer && !strcmp(drainer, "#levelchange")) |
| 215 | drainer = 0; |
| 216 | else if (resists_drli(&gy.youmonst)) |
| 217 | return; |
| 218 | |
| 219 | /* level-loss message; "Goodbye level 1." is fatal; divine anger |
| 220 | (drainer==NULL) resets a level 1 character to 0 experience points |
| 221 | without reducing level and that isn't fatal so suppress the message |
| 222 | in that situation */ |
| 223 | if (u.ulevel > 1 || drainer) |
| 224 | pline("%s level %d.", Goodbye(), u.ulevel); |
| 225 | |
| 226 | if (u.ulevel > 1) { |
| 227 | u.ulevel -= 1; |
| 228 | /* remove intrinsic abilities */ |
| 229 | adjabil(u.ulevel + 1, u.ulevel); |
| 230 | livelog_printf(LL_MINORAC, "lost experience level %d", u.ulevel + 1); |
| 231 | SoundAchievement(0, sa2_xpleveldown, 0); |
| 232 | } else { /* u.ulevel==1 */ |
| 233 | if (drainer) { |
| 234 | svk.killer.format = KILLED_BY; |
| 235 | if (svk.killer.name != drainer) |
| 236 | Strcpy(svk.killer.name, drainer); |
| 237 | done(DIED); |
| 238 | } |
| 239 | /* no drainer or lifesaved */ |
| 240 | if (u.ulevel > 1) |
| 241 | /* can happen during debug fuzzing if fuzzer_savelife() uses |
| 242 | a blessed potion of restore ability to restore lost levels */ |
| 243 | return; |
| 244 | u.uexp = 0; |
| 245 | livelog_printf(LL_MINORAC, "lost all experience"); |
| 246 | } |
| 247 | assert(u.ulevel >= 0 && u.ulevel < MAXULEV); /* valid array index */ |
| 248 | |
| 249 | olduhpmax = u.uhpmax; |
| 250 | uhpmin = minuhpmax(10); /* same minimum as is used by life-saving */ |
| 251 | num = (int) u.uhpinc[u.ulevel]; |
| 252 | u.uhpmax -= num; |
| 253 | if (u.uhpmax < uhpmin) |
| 254 | setuhpmax(uhpmin, TRUE); |
| 255 | /* uhpmax might try to go up if it has previously been reduced by |
| 256 | strength loss or by a fire trap or by an attack by Death which |
| 257 | all use a different minimum than life-saving or experience loss; |
| 258 | we don't allow it to go up because that contradicts assumptions |
| 259 | elsewhere (such as healing wielder who drains with Stormbringer) */ |
| 260 | if (u.uhpmax > olduhpmax) |
| 261 | setuhpmax(olduhpmax, TRUE); |
| 262 | |
| 263 | u.uhp -= num; |
no test coverage detected