Skip to content

Commit

Permalink
Add RTP monster
Browse files Browse the repository at this point in the history
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
  • Loading branch information
liam-middlebrook committed Dec 2, 2017
1 parent 85dbdba commit 7bc17a3
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 11 deletions.
1 change: 1 addition & 0 deletions libnethack/dat/Potter.des
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ STAIR:(74,10),up
STAIR:(22,12),down
#Potter
MONSTER:'@',"Potter",(22,11)
MONSTER:'@',"rtp",(22,8)
# LIGHT IT UP
REGION: (0,0,74,20),lit,"delphi"
2 changes: 1 addition & 1 deletion libnethack/include/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -1392,7 +1392,7 @@ extern struct monst *split_mon(struct monst *, struct monst *);
extern const char *bottlename(void);

/* ### pray.c ### */

extern void gods_upset(aligntyp g_align);
extern int dosacrifice(const struct nh_cmd_arg *);
extern boolean can_pray(boolean);
extern int dopray(const struct nh_cmd_arg *);
Expand Down
1 change: 1 addition & 0 deletions libnethack/include/monflag.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
the above */
# define MS_WERE 38 /* lycanthrope in human form */
# define MS_BOAST 39 /* giants */
# define MS_RTP 40 /* Root Type People */


# define MR_FIRE 0x01 /* resists fire */
Expand Down
16 changes: 16 additions & 0 deletions libnethack/include/rtp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef RTP_H
#define RTP_H

#include <stdbool.h>

#include "extern.h"
#include "hack.h"
#include "monst.h"

struct monst *name_rtp(struct monst *mtmp);

void player_killed_rtp(struct level *lev);

struct obj *create_rtp_corpse(struct level *lev, int x, int y, enum rng rng);

#endif // RTP_H
4 changes: 4 additions & 0 deletions libnethack/src/makemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "emin.h"
#include "edog.h"
#include "eshk.h"
#include "rtp.h"
#include "vault.h"
#include <ctype.h>

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

if (mndx == PM_RTP) {
mtmp = name_rtp(mtmp);
}
return mtmp;
}

Expand Down
26 changes: 18 additions & 8 deletions libnethack/src/mon.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "hack.h"
#include "mfndpos.h"
#include "edog.h"
#include "rtp.h"
#include <ctype.h>

static boolean restrap(struct monst *);
Expand Down Expand Up @@ -301,6 +302,9 @@ make_corpse(struct monst *mtmp)
obj = mksobj_at(SCR_BLANK_PAPER, level, x, y, TRUE, FALSE, rng_main);
mtmp->mnamelth = 0;
break;
case PM_RTP:
obj = create_rtp_corpse(level, x, y, rng_main);
break;
default_1:
default:
if (mvitals[mndx].mvflags & G_NOCORPSE)
Expand All @@ -318,7 +322,8 @@ make_corpse(struct monst *mtmp)
if (flags.bypasses)
bypass_obj(obj);

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

/* Avoid "It was hidden under a green mold corpse!" during Blind combat. An
Expand Down Expand Up @@ -2108,13 +2113,18 @@ xkilled(struct monst *mtmp, int dest)
cleanup:
/* punish bad behaviour */
if (is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) &&
(mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) &&
u.ualign.type != A_CHAOTIC) {
HTelepat &= ~INTRINSIC;
change_luck(-2);
pline("You murderer!");
if (Blind && !Blind_telepat)
see_monsters(FALSE); /* Can't sense monsters any more. */
(mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD)) {
if (u.ualign.type != A_CHAOTIC) {
HTelepat &= ~INTRINSIC;
change_luck(-2);
pline("You murderer!");
if (Blind && !Blind_telepat)
see_monsters(FALSE); /* Can't sense monsters any more. */
}
// Even chaotic players get punishment for killing RTPs
if (mndx == PM_RTP) {
player_killed_rtp(level);
}
}
if ((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame)
change_luck(-1);
Expand Down
8 changes: 8 additions & 0 deletions libnethack/src/monst.c
Original file line number Diff line number Diff line change
Expand Up @@ -3489,6 +3489,14 @@ const struct permonst mons[] = {
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT | M2_MAGIC,
M3_INFRAVISIBLE, HI_GUARDIAN),
MON("rtp", S_HUMAN,
LVL(10, 6, 5, 10, 0), G_NOGEN,
A(ATTK(AT_WEAP, AD_PHYS, 2, 6),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, 0, MS_RTP, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_COLLECT,
M3_INFRAVISIBLE, CLR_BLUE),
/*
* array terminator
*/
Expand Down
3 changes: 1 addition & 2 deletions libnethack/src/pray.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ static void godvoice(aligntyp, const char *);
static void god_zaps_you(aligntyp);
static void fry_by_god(aligntyp);
static void gods_angry(aligntyp);
static void gods_upset(aligntyp);
static void consume_offering(struct obj *);
static boolean water_prayer(boolean);
static boolean blocked_boulder(int, int);
Expand Down Expand Up @@ -1074,7 +1073,7 @@ gods_angry(aligntyp g_align)
}

/* The g_align god is upset with you. */
static void
void
gods_upset(aligntyp g_align)
{
if (g_align == u.ualign.type)
Expand Down
131 changes: 131 additions & 0 deletions libnethack/src/rtp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include "rtp.h"

typedef const struct {
const char* name;
const bool female;
} rtpEntry;

rtpEntry rtpNames[] = {
{"Angelo DiNardi", false},
{"Chris Lockfort", false},
{"Dan Willemsen", false},
{"Derek Gonyeo", false},
{"Ethan House", false},
{"Grant Cohoe", false},
{"Jordan Rodgers", false},
{"Kevin Thompson", false},
{"Liam Middlebrook", false},
{"McSaucy", false},
{"Rob Glossop", false},
{"Russ Harmon", false},
{"Stephanie Miller", true},
{"Steve Greene", false},
{"Will Orr", false},
{"William Dignazio", false},
};

struct monst *
name_rtp(struct monst *mtmp)
{
int rtp_id = rn2(sizeof(rtpNames) / sizeof(rtpEntry));

if (rtpNames[rtp_id].female) {
mtmp->female = TRUE;
}

return christen_monst(mtmp, msg_from_string(rtpNames[rtp_id].name));
}

struct obj *
create_rtp_corpse(struct level *lev, int x, int y, enum rng rng)
{
struct obj *obj = NULL;
struct obj *orig_obj = NULL;
// There should be a significant reward in order to tempt the player into
// trying to kill an RTP. Otherwise it's risk without reward.

// In the future this should be a random selection from a slew of different
// items ranging in usefulness.
obj = mksobj_at(MAGIC_MARKER, lev, x, y, TRUE, FALSE, rng);


orig_obj = obj;

// What else are RTPs good for :D
obj = oname(obj, "The Root Password");
return obj;
}

void
player_killed_rtp(struct level *lev)
{
pline("You hear a faint whisper in the air: \"I'll shred your world\"");

// get a large sample set
int random = rn2(100);

// Enumerate through all the possibilities when the player kills an
// RTP
//
if (!(random / 10)) {
change_luck(-3);
}

// 5% chance that the player hallucinates for a long while
if (!(random / 20)) {
make_hallucinated(rn2(420) + 50, TRUE);
}

// 1% chance the player gets sick and dies after 42 turns
if (random == 42) {
make_sick(42, "Right before you killed that RTP 42 turns ago they gave you Heartbleed </3", TRUE, SICK_VOMITABLE);
}

// 33% chance that alignment changes
if (!(random / 3)) {
aligntyp player_align = u.ualign.type;
aligntyp new_align = A_NEUTRAL;

// If we're not neutral switch to opposite or neutral
if (player_align) {
new_align = rn2(1) * -player_align;
} else {
new_align = rn2(1)? 1: -1;
}

if (uarmh && uarmh->otyp == HELM_OF_OPPOSITE_ALIGNMENT) {
u.ualignbase[A_CURRENT] = new_align;
} else {
u.ualign.type = u.ualignbase[A_CURRENT] = new_align;
}
}

// 25% chance that you anger your god
if(!(random / 4)) {
gods_upset(u.ualign.type);
}

// 16.67% chance that player loses a level (if > 1)
if (!(random / 6) && u.ulevel > 1) {
losexp(NULL, FALSE);
}

// 20% chance to spawn a random (suitable for the level) angry monster near
// the player
if (!(random / 5)) {
makemon(NULL, lev, u.ux, u.uy, MM_ANGRY);
}

if (!(random / 10)) {
// Neat that this function already exists for our usage!
rndcurse();
}

if (!(random / 10)) {
if(uarmg) erode_obj(uarmg, NULL, ERODE_CORRODE, TRUE, TRUE);
}

if (!(random / 15)) {
polyself(FALSE);
}
}
21 changes: 21 additions & 0 deletions libnethack/src/sounds.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,27 @@ domonnoise(struct monst *mtmp)
else
verbl_msg = "Who do you think you are, War?";
break;
case MS_RTP:
{
static const char *const rtp_foe_msg[] = {
"What about our imagine subscription?",
"I can ensure everything is down...",
"See if you can go to sleep now.",
};
static const char *const rtp_pax_msg[] = {
"Not my server, not my problem.",
"You name it, we don't have to vote on it.",
"I can get it ALL on it!",
"Yeah but that definitely happened again.",
"Yeah I'd like to think about what we want",
"Why did MegaVM start VMs wtf!? Welp... shit shit shit WHO was last logged in?",
"I wasn't saturating the upload on 49net...",
"I can't remember how I fixed it.",
};
verbl_msg = mtmp->mpeaceful ? rtp_pax_msg[rn2(sizeof(rtp_pax_msg))]
: rtp_foe_msg[rn2(sizeof(rtp_foe_msg))];
}
break;
}

if (pline_msg)
Expand Down

0 comments on commit 7bc17a3

Please sign in to comment.