Skip to content

Commit 7bc17a3

Browse files
Add RTP monster
Creates a new level 10 monster resembling a Computer Science House Root Type Person. RTPs will cause bad fate to fall upon the player when they are killed byt the player. However unless the player does something to anger them, RTPs are peaceful. Add 1 RTP spawn on Potter Level RTP names are automatically chosen from a list of RTPs. Inspired-by: ComputerScienceHouse/bingehack#66
1 parent 85dbdba commit 7bc17a3

File tree

10 files changed

+202
-11
lines changed

10 files changed

+202
-11
lines changed

libnethack/dat/Potter.des

+1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ STAIR:(74,10),up
3838
STAIR:(22,12),down
3939
#Potter
4040
MONSTER:'@',"Potter",(22,11)
41+
MONSTER:'@',"rtp",(22,8)
4142
# LIGHT IT UP
4243
REGION: (0,0,74,20),lit,"delphi"

libnethack/include/extern.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1392,7 +1392,7 @@ extern struct monst *split_mon(struct monst *, struct monst *);
13921392
extern const char *bottlename(void);
13931393

13941394
/* ### pray.c ### */
1395-
1395+
extern void gods_upset(aligntyp g_align);
13961396
extern int dosacrifice(const struct nh_cmd_arg *);
13971397
extern boolean can_pray(boolean);
13981398
extern int dopray(const struct nh_cmd_arg *);

libnethack/include/monflag.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
the above */
5555
# define MS_WERE 38 /* lycanthrope in human form */
5656
# define MS_BOAST 39 /* giants */
57+
# define MS_RTP 40 /* Root Type People */
5758

5859

5960
# define MR_FIRE 0x01 /* resists fire */

libnethack/include/rtp.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#ifndef RTP_H
2+
#define RTP_H
3+
4+
#include <stdbool.h>
5+
6+
#include "extern.h"
7+
#include "hack.h"
8+
#include "monst.h"
9+
10+
struct monst *name_rtp(struct monst *mtmp);
11+
12+
void player_killed_rtp(struct level *lev);
13+
14+
struct obj *create_rtp_corpse(struct level *lev, int x, int y, enum rng rng);
15+
16+
#endif // RTP_H

libnethack/src/makemon.c

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "emin.h"
99
#include "edog.h"
1010
#include "eshk.h"
11+
#include "rtp.h"
1112
#include "vault.h"
1213
#include <ctype.h>
1314

@@ -1221,6 +1222,9 @@ makemon(const struct permonst *ptr, struct level *lev, int x, int y,
12211222
if (!in_mklev && lev == level)
12221223
newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */
12231224

1225+
if (mndx == PM_RTP) {
1226+
mtmp = name_rtp(mtmp);
1227+
}
12241228
return mtmp;
12251229
}
12261230

libnethack/src/mon.c

+18-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "hack.h"
77
#include "mfndpos.h"
88
#include "edog.h"
9+
#include "rtp.h"
910
#include <ctype.h>
1011

1112
static boolean restrap(struct monst *);
@@ -301,6 +302,9 @@ make_corpse(struct monst *mtmp)
301302
obj = mksobj_at(SCR_BLANK_PAPER, level, x, y, TRUE, FALSE, rng_main);
302303
mtmp->mnamelth = 0;
303304
break;
305+
case PM_RTP:
306+
obj = create_rtp_corpse(level, x, y, rng_main);
307+
break;
304308
default_1:
305309
default:
306310
if (mvitals[mndx].mvflags & G_NOCORPSE)
@@ -318,7 +322,8 @@ make_corpse(struct monst *mtmp)
318322
if (flags.bypasses)
319323
bypass_obj(obj);
320324

321-
if (mtmp->mnamelth)
325+
// RTPs drop the root password not a specialized item
326+
if (mtmp->mnamelth && mndx != PM_RTP)
322327
obj = oname(obj, NAME(mtmp));
323328

324329
/* Avoid "It was hidden under a green mold corpse!" during Blind combat. An
@@ -2108,13 +2113,18 @@ xkilled(struct monst *mtmp, int dest)
21082113
cleanup:
21092114
/* punish bad behaviour */
21102115
if (is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) &&
2111-
(mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) &&
2112-
u.ualign.type != A_CHAOTIC) {
2113-
HTelepat &= ~INTRINSIC;
2114-
change_luck(-2);
2115-
pline("You murderer!");
2116-
if (Blind && !Blind_telepat)
2117-
see_monsters(FALSE); /* Can't sense monsters any more. */
2116+
(mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD)) {
2117+
if (u.ualign.type != A_CHAOTIC) {
2118+
HTelepat &= ~INTRINSIC;
2119+
change_luck(-2);
2120+
pline("You murderer!");
2121+
if (Blind && !Blind_telepat)
2122+
see_monsters(FALSE); /* Can't sense monsters any more. */
2123+
}
2124+
// Even chaotic players get punishment for killing RTPs
2125+
if (mndx == PM_RTP) {
2126+
player_killed_rtp(level);
2127+
}
21182128
}
21192129
if ((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame)
21202130
change_luck(-1);

libnethack/src/monst.c

+8
Original file line numberDiff line numberDiff line change
@@ -3489,6 +3489,14 @@ const struct permonst mons[] = {
34893489
M1_HUMANOID | M1_OMNIVORE,
34903490
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC,
34913491
M3_INFRAVISIBLE, HI_GUARDIAN),
3492+
MON("rtp", S_HUMAN,
3493+
LVL(10, 6, 5, 10, 0), G_NOGEN,
3494+
A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
3495+
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
3496+
SIZ(WT_HUMAN, 400, 0, MS_RTP, MZ_HUMAN), 0, 0,
3497+
M1_HUMANOID | M1_OMNIVORE,
3498+
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT,
3499+
M3_INFRAVISIBLE, CLR_BLUE),
34923500
/*
34933501
* array terminator
34943502
*/

libnethack/src/pray.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ static void godvoice(aligntyp, const char *);
1818
static void god_zaps_you(aligntyp);
1919
static void fry_by_god(aligntyp);
2020
static void gods_angry(aligntyp);
21-
static void gods_upset(aligntyp);
2221
static void consume_offering(struct obj *);
2322
static boolean water_prayer(boolean);
2423
static boolean blocked_boulder(int, int);
@@ -1074,7 +1073,7 @@ gods_angry(aligntyp g_align)
10741073
}
10751074

10761075
/* The g_align god is upset with you. */
1077-
static void
1076+
void
10781077
gods_upset(aligntyp g_align)
10791078
{
10801079
if (g_align == u.ualign.type)

libnethack/src/rtp.c

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include "rtp.h"
2+
3+
typedef const struct {
4+
const char* name;
5+
const bool female;
6+
} rtpEntry;
7+
8+
rtpEntry rtpNames[] = {
9+
{"Angelo DiNardi", false},
10+
{"Chris Lockfort", false},
11+
{"Dan Willemsen", false},
12+
{"Derek Gonyeo", false},
13+
{"Ethan House", false},
14+
{"Grant Cohoe", false},
15+
{"Jordan Rodgers", false},
16+
{"Kevin Thompson", false},
17+
{"Liam Middlebrook", false},
18+
{"McSaucy", false},
19+
{"Rob Glossop", false},
20+
{"Russ Harmon", false},
21+
{"Stephanie Miller", true},
22+
{"Steve Greene", false},
23+
{"Will Orr", false},
24+
{"William Dignazio", false},
25+
};
26+
27+
struct monst *
28+
name_rtp(struct monst *mtmp)
29+
{
30+
int rtp_id = rn2(sizeof(rtpNames) / sizeof(rtpEntry));
31+
32+
if (rtpNames[rtp_id].female) {
33+
mtmp->female = TRUE;
34+
}
35+
36+
return christen_monst(mtmp, msg_from_string(rtpNames[rtp_id].name));
37+
}
38+
39+
struct obj *
40+
create_rtp_corpse(struct level *lev, int x, int y, enum rng rng)
41+
{
42+
struct obj *obj = NULL;
43+
struct obj *orig_obj = NULL;
44+
// There should be a significant reward in order to tempt the player into
45+
// trying to kill an RTP. Otherwise it's risk without reward.
46+
47+
// In the future this should be a random selection from a slew of different
48+
// items ranging in usefulness.
49+
obj = mksobj_at(MAGIC_MARKER, lev, x, y, TRUE, FALSE, rng);
50+
51+
52+
orig_obj = obj;
53+
54+
// What else are RTPs good for :D
55+
obj = oname(obj, "The Root Password");
56+
return obj;
57+
}
58+
59+
void
60+
player_killed_rtp(struct level *lev)
61+
{
62+
pline("You hear a faint whisper in the air: \"I'll shred your world\"");
63+
64+
// get a large sample set
65+
int random = rn2(100);
66+
67+
// Enumerate through all the possibilities when the player kills an
68+
// RTP
69+
//
70+
if (!(random / 10)) {
71+
change_luck(-3);
72+
}
73+
74+
// 5% chance that the player hallucinates for a long while
75+
if (!(random / 20)) {
76+
make_hallucinated(rn2(420) + 50, TRUE);
77+
}
78+
79+
// 1% chance the player gets sick and dies after 42 turns
80+
if (random == 42) {
81+
make_sick(42, "Right before you killed that RTP 42 turns ago they gave you Heartbleed </3", TRUE, SICK_VOMITABLE);
82+
}
83+
84+
// 33% chance that alignment changes
85+
if (!(random / 3)) {
86+
aligntyp player_align = u.ualign.type;
87+
aligntyp new_align = A_NEUTRAL;
88+
89+
// If we're not neutral switch to opposite or neutral
90+
if (player_align) {
91+
new_align = rn2(1) * -player_align;
92+
} else {
93+
new_align = rn2(1)? 1: -1;
94+
}
95+
96+
if (uarmh && uarmh->otyp == HELM_OF_OPPOSITE_ALIGNMENT) {
97+
u.ualignbase[A_CURRENT] = new_align;
98+
} else {
99+
u.ualign.type = u.ualignbase[A_CURRENT] = new_align;
100+
}
101+
}
102+
103+
// 25% chance that you anger your god
104+
if(!(random / 4)) {
105+
gods_upset(u.ualign.type);
106+
}
107+
108+
// 16.67% chance that player loses a level (if > 1)
109+
if (!(random / 6) && u.ulevel > 1) {
110+
losexp(NULL, FALSE);
111+
}
112+
113+
// 20% chance to spawn a random (suitable for the level) angry monster near
114+
// the player
115+
if (!(random / 5)) {
116+
makemon(NULL, lev, u.ux, u.uy, MM_ANGRY);
117+
}
118+
119+
if (!(random / 10)) {
120+
// Neat that this function already exists for our usage!
121+
rndcurse();
122+
}
123+
124+
if (!(random / 10)) {
125+
if(uarmg) erode_obj(uarmg, NULL, ERODE_CORRODE, TRUE, TRUE);
126+
}
127+
128+
if (!(random / 15)) {
129+
polyself(FALSE);
130+
}
131+
}

libnethack/src/sounds.c

+21
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,27 @@ domonnoise(struct monst *mtmp)
810810
else
811811
verbl_msg = "Who do you think you are, War?";
812812
break;
813+
case MS_RTP:
814+
{
815+
static const char *const rtp_foe_msg[] = {
816+
"What about our imagine subscription?",
817+
"I can ensure everything is down...",
818+
"See if you can go to sleep now.",
819+
};
820+
static const char *const rtp_pax_msg[] = {
821+
"Not my server, not my problem.",
822+
"You name it, we don't have to vote on it.",
823+
"I can get it ALL on it!",
824+
"Yeah but that definitely happened again.",
825+
"Yeah I'd like to think about what we want",
826+
"Why did MegaVM start VMs wtf!? Welp... shit shit shit WHO was last logged in?",
827+
"I wasn't saturating the upload on 49net...",
828+
"I can't remember how I fixed it.",
829+
};
830+
verbl_msg = mtmp->mpeaceful ? rtp_pax_msg[rn2(sizeof(rtp_pax_msg))]
831+
: rtp_foe_msg[rn2(sizeof(rtp_foe_msg))];
832+
}
833+
break;
813834
}
814835

815836
if (pline_msg)

0 commit comments

Comments
 (0)