From 7bc17a39777640601f8efe29bedcbd1ac14ce56c Mon Sep 17 00:00:00 2001 From: Liam Middlebrook Date: Sat, 25 Nov 2017 17:50:51 -0800 Subject: [PATCH] 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: https://github.com/ComputerScienceHouse/bingehack/issues/66 --- libnethack/dat/Potter.des | 1 + libnethack/include/extern.h | 2 +- libnethack/include/monflag.h | 1 + libnethack/include/rtp.h | 16 +++++ libnethack/src/makemon.c | 4 ++ libnethack/src/mon.c | 26 ++++--- libnethack/src/monst.c | 8 +++ libnethack/src/pray.c | 3 +- libnethack/src/rtp.c | 131 +++++++++++++++++++++++++++++++++++ libnethack/src/sounds.c | 21 ++++++ 10 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 libnethack/include/rtp.h create mode 100644 libnethack/src/rtp.c diff --git a/libnethack/dat/Potter.des b/libnethack/dat/Potter.des index f26df7e4..1188c852 100644 --- a/libnethack/dat/Potter.des +++ b/libnethack/dat/Potter.des @@ -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" diff --git a/libnethack/include/extern.h b/libnethack/include/extern.h index 277e9094..7d08f4a9 100644 --- a/libnethack/include/extern.h +++ b/libnethack/include/extern.h @@ -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 *); diff --git a/libnethack/include/monflag.h b/libnethack/include/monflag.h index b371f87d..2a70a6f4 100644 --- a/libnethack/include/monflag.h +++ b/libnethack/include/monflag.h @@ -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 */ diff --git a/libnethack/include/rtp.h b/libnethack/include/rtp.h new file mode 100644 index 00000000..50e35d32 --- /dev/null +++ b/libnethack/include/rtp.h @@ -0,0 +1,16 @@ +#ifndef RTP_H +#define RTP_H + +#include + +#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 diff --git a/libnethack/src/makemon.c b/libnethack/src/makemon.c index 8cb5a76c..0e43d0cf 100644 --- a/libnethack/src/makemon.c +++ b/libnethack/src/makemon.c @@ -8,6 +8,7 @@ #include "emin.h" #include "edog.h" #include "eshk.h" +#include "rtp.h" #include "vault.h" #include @@ -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; } diff --git a/libnethack/src/mon.c b/libnethack/src/mon.c index bec10cf1..db3183b5 100644 --- a/libnethack/src/mon.c +++ b/libnethack/src/mon.c @@ -6,6 +6,7 @@ #include "hack.h" #include "mfndpos.h" #include "edog.h" +#include "rtp.h" #include static boolean restrap(struct monst *); @@ -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) @@ -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 @@ -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); diff --git a/libnethack/src/monst.c b/libnethack/src/monst.c index 1a756c35..f073013d 100644 --- a/libnethack/src/monst.c +++ b/libnethack/src/monst.c @@ -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 */ diff --git a/libnethack/src/pray.c b/libnethack/src/pray.c index 14ab38a4..75e86c0d 100644 --- a/libnethack/src/pray.c +++ b/libnethack/src/pray.c @@ -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); @@ -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) diff --git a/libnethack/src/rtp.c b/libnethack/src/rtp.c new file mode 100644 index 00000000..2246847b --- /dev/null +++ b/libnethack/src/rtp.c @@ -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 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); + } +} diff --git a/libnethack/src/sounds.c b/libnethack/src/sounds.c index 59e7aafd..112a9ec2 100644 --- a/libnethack/src/sounds.c +++ b/libnethack/src/sounds.c @@ -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)