Skip to content

Commit

Permalink
Player can create various types of armor and weapons using a forge.
Browse files Browse the repository at this point in the history
Players can now use a forge to create all sorts of different types of
armor and weapons. The bulk of this code comes from SpliceHack, but
I've changed a fair amount of it for EvilHack. The details:

* Two objects can be placed inside a forge to create a new singular
object using the command #forge
* Various recipes exist for almost all types of metallic armor and
weapons
* A hammer (any type) must be wielded to effectively forge an object
* Only metallic objects can be forged
* When selecting the base and secondary objects, the BUC status and
material of the secondary object determines the same for the final
product
* If the base and secondary objects are enchanted, the greater of the
two enchantments carries over to the final product
* Currently, only non-magical weapons and armor can be forged (this may
change in the future)

In SpliceHack, players can forge an assortment of magical objects, and
even artifacts. I felt this was too overpowered, especially since there
isn't an additional cost for doing such a thing. Maybe in the future,
allow magical objects to be forged, but require an additional component
for that to happen.
  • Loading branch information
k21971 committed Apr 12, 2022
1 parent 687edb1 commit 996d2c8
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 10 deletions.
7 changes: 4 additions & 3 deletions doc/Guidebook.mn
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ An iron ball.
.lp _
An altar, or an iron chain.
.lp {
A fountain.
A fountain or a forge.
.lp }
A pool of water or moat or a pool of lava.
.lp \\\\
Expand Down Expand Up @@ -4505,7 +4505,7 @@ E S_elemental (elemental)
\- S_explode2 (explosion top center)
\\ S_explode3 (explosion top right)
| S_explode4 (explosion middle left)
\ S_explode5 (explosion middle center)
\ S_explode5 (explosion middle center)
| S_explode6 (explosion middle right)
\\ S_explode7 (explosion bottom left)
\- S_explode8 (explosion bottom center)
Expand All @@ -4516,10 +4516,11 @@ f S_feline (cat or other feline)
\(ha S_fire_trap (fire trap)
! S_flashbeam (flash beam)
% S_food (piece of food)
{ S_forge (forge)
{ S_fountain (fountain)
F S_fungus (fungus or mold)
* S_gem (gem or rock)
\ S_ghost (ghost)
\ S_ghost (ghost)
H S_giant (giant humanoid)
G S_gnome (gnome)
\' S_golem (golem)
Expand Down
3 changes: 2 additions & 1 deletion doc/Guidebook.tex
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ \subsection*{The map (rest of the screen)}
An altar, or an iron chain.
%.lp
\item[\tb{\{}]
A fountain.
A fountain or a forge.
%.lp
\item[\tb{\}}]
A pool of water or moat or a pool of lava.
Expand Down Expand Up @@ -5002,6 +5002,7 @@ \subsection*{Modifying {\it NetHack\/} Symbols}
\verb@^@ & S\verb+_+fire\verb+_+trap & (fire trap)\\
\verb@!@ & S\verb+_+flashbeam & (flash beam)\\
\% & S\verb+_+food & (piece of food)\\
\{ & S\verb+_+forge & (forge)\\
\{ & S\verb+_+fountain & (fountain)\\
\verb@F@ & S\verb+_+fungus & (fungus or mold)\\
\verb@*@ & S\verb+_+gem & (gem or rock)\\
Expand Down
4 changes: 2 additions & 2 deletions doc/Guidebook.txt
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@

_ An altar, or an iron chain.

{ A fountain.
{ A fountain or a forge.

} A pool of water or moat or a pool of lava.

Expand Down Expand Up @@ -5254,6 +5254,7 @@
^ S_fire_trap (fire trap)
! S_flashbeam (flash beam)
% S_food (piece of food)
{ S_forge (forge)
{ S_fountain (fountain)
F S_fungus (fungus or mold)
* S_gem (gem or rock)
Expand All @@ -5273,7 +5274,6 @@
h S_humanoid (humanoid)



NetHack 3.6 September 29, 2021


Expand Down
1 change: 1 addition & 0 deletions doc/evilhack-changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2239,4 +2239,5 @@ The following changes to date are:
- Only certain types of monsters can randomly spawn in Goblin Town
- Tortles are not slowed when walking through sewage
- Tortles and giant turtles are vulnerable to cold-based attacks
- Player can create various types of armor and weapons using a forge

7 changes: 4 additions & 3 deletions include/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -922,14 +922,15 @@ E void FDECL(dogushforth, (int));
E void FDECL(gush, (int, int, genericptr_t));
#endif
E void FDECL(dryup, (XCHAR_P, XCHAR_P, BOOLEAN_P));
E void FDECL(blowupforge, (int, int));
E void FDECL(dipforge, (struct obj *));
E int NDECL(doforging);
E void NDECL(drinkfountain);
E void FDECL(dipfountain, (struct obj *));
E void FDECL(breakforge, (int, int));
E void FDECL(blowupforge, (int, int));
E void NDECL(drinkforge);
E void FDECL(breaksink, (int, int));
E void NDECL(drinksink);
E void NDECL(drinkforge);
E void FDECL(dipforge, (struct obj *));

/* ### hack.c ### */

Expand Down
11 changes: 10 additions & 1 deletion src/cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -3801,6 +3801,7 @@ struct ext_func_tab extcmdlist[] = {
enter_explore_mode, IFBURIED },
{ 'f', "fire", "fire ammunition from quiver", dofire },
{ M('f'), "force", "force a lock", doforce, AUTOCOMPLETE },
{ M('F'), "forge", "combine two objects to create a new object", doforging, AUTOCOMPLETE },
{ ';', "glance", "show what type of thing a map symbol corresponds to",
doquickwhatis, IFBURIED | GENERALCMD },
{ '?', "help", "give a help message", dohelp, IFBURIED | GENERALCMD },
Expand Down Expand Up @@ -5933,10 +5934,15 @@ boolean doit;
if (IS_FORGE(typ)) {
add_herecmd_menuitem(win, dodrink, "Really drink the lava from the forge?");
}
if (IS_FOUNTAIN(typ))
if (IS_FOUNTAIN(typ) || IS_FORGE(typ))
Sprintf(buf, "Dip something into the %s",
defsyms[IS_FOUNTAIN(typ) ? S_fountain : S_forge].explanation);
add_herecmd_menuitem(win, dodip, buf);
if (IS_FORGE(typ)) {
Sprintf(buf, "Combine objects in the %s",
defsyms[S_forge].explanation);
add_herecmd_menuitem(win, doforging, buf);
}
if (IS_THRONE(typ))
add_herecmd_menuitem(win, dosit,
"Sit on the throne");
Expand Down Expand Up @@ -6060,6 +6066,9 @@ int x, y, mod;
|| IS_FORGE(levl[u.ux][u.uy].typ)) {
cmd[0] = cmd_from_func(mod == CLICK_1 ? dodrink : dodip);
return cmd;
} else if (IS_FORGE(levl[u.ux][u.uy].typ)) {
cmd[0] = cmd_from_func(mod == CLICK_1 ? doforging : dodip);
return cmd;
} else if (IS_THRONE(levl[u.ux][u.uy].typ)) {
cmd[0] = cmd_from_func(dosit);
return cmd;
Expand Down
186 changes: 186 additions & 0 deletions src/fountain.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,192 @@ register struct obj *obj;
update_inventory();
}

/* forging recipes - first object is the end result
of combining objects two and three
TODO: could easily allow all sorts of magical
objects (or even artifacts) to be forged, but that
feels overpowered without needing some other
component added to the mix, or maybe have the
forge be used up, or both */
static const short fusions[][3] = {
/* weapons */
{ SHURIKEN, DART, DAGGER },
{ SPEAR, ARROW, DAGGER },
{ ORCISH_SPEAR, ORCISH_ARROW, ORCISH_DAGGER },
{ DWARVISH_SPEAR, ARROW, SPEAR },
{ JAVELIN, DART, SPEAR },
{ TRIDENT, SCIMITAR, SPEAR },
{ DAGGER, ARROW, KNIFE },
{ ORCISH_DAGGER, ORCISH_ARROW, KNIFE },
{ ATHAME, DAGGER, STILETTO },
{ SCALPEL, KNIFE, STILETTO },
{ KNIFE, ARROW, DART },
{ STILETTO, KNIFE, KNIFE },
{ AXE, DAGGER, SPEAR },
{ DWARVISH_BEARDED_AXE, AXE, LONG_SWORD },
{ BATTLE_AXE, AXE, BROADSWORD },
{ SHORT_SWORD, DAGGER, DAGGER },
{ ORCISH_SHORT_SWORD, ORCISH_DAGGER, ORCISH_DAGGER },
{ DWARVISH_SHORT_SWORD, DWARVISH_SPEAR, SHORT_SWORD },
{ SCIMITAR, KNIFE, SHORT_SWORD },
{ ORCISH_SCIMITAR, KNIFE, ORCISH_SHORT_SWORD },
{ SABER, SCIMITAR, LONG_SWORD },
{ BROADSWORD, SCIMITAR, SHORT_SWORD },
{ LONG_SWORD, SHORT_SWORD, SHORT_SWORD },
{ ORCISH_LONG_SWORD, ORCISH_SHORT_SWORD, ORCISH_SHORT_SWORD },
{ TWO_HANDED_SWORD, LONG_SWORD, BROADSWORD },
{ KATANA, LONG_SWORD, LONG_SWORD },
{ TSURUGI, TWO_HANDED_SWORD, KATANA },
{ RUNESWORD, BROADSWORD, DAGGER },
{ LANCE, RANSEUR, GLAIVE },
{ HALBERD, RANSEUR, AXE },
{ DWARVISH_MATTOCK, PICK_AXE, DWARVISH_SHORT_SWORD },
{ MACE, WAR_HAMMER, DAGGER },
{ HEAVY_MACE, MACE, MACE },
{ MORNING_STAR, MACE, DAGGER },
{ ORCISH_MORNING_STAR, MACE, ORCISH_DAGGER },
{ WAR_HAMMER, MACE, FLAIL },
{ HEAVY_WAR_HAMMER, WAR_HAMMER, WAR_HAMMER },
{ AKLYS, FLAIL, SPEAR },
{ FLAIL, MORNING_STAR, MACE },
/* armor (helmets) */
{ ORCISH_HELM, DENTED_POT, ORCISH_DAGGER },
{ DWARVISH_HELM, HELMET, DWARVISH_SHORT_SWORD },
{ DENTED_POT, WAR_HAMMER, KNIFE },
{ HELMET, DENTED_POT, DAGGER },
/* armor (body armor) */
{ PLATE_MAIL, SPLINT_MAIL, CHAIN_MAIL },
{ SPLINT_MAIL, SCALE_MAIL, CHAIN_MAIL },
{ LARGE_SPLINT_MAIL, PLATE_MAIL, PLATE_MAIL },
{ BANDED_MAIL, SCALE_MAIL, RING_MAIL },
{ CHAIN_MAIL, RING_MAIL, RING_MAIL },
{ DWARVISH_CHAIN_MAIL, CHAIN_MAIL, DWARVISH_ROUNDSHIELD },
{ ELVEN_CHAIN_MAIL, CHAIN_MAIL, LARGE_SHIELD },
{ ORCISH_CHAIN_MAIL, RING_MAIL, ORCISH_SHIELD },
{ SCALE_MAIL, RING_MAIL, HELMET },
{ RING_MAIL, LARGE_SHIELD, HELMET },
{ ORCISH_RING_MAIL, ORCISH_SHIELD, ORCISH_HELM },
/* armor (shields) */
{ URUK_HAI_SHIELD, ORCISH_SHIELD, ORCISH_SHIELD },
{ ORCISH_SHIELD, ORCISH_HELM, ORCISH_BOOTS },
{ LARGE_SHIELD, HELMET, HELMET },
{ DWARVISH_ROUNDSHIELD, LARGE_SHIELD, DWARVISH_HELM },
/* armor (gauntlets and boots) */
{ GAUNTLETS, MACE, HELMET },
{ DWARVISH_BOOTS, GAUNTLETS, DWARVISH_SHORT_SWORD },
{ ORCISH_BOOTS, GAUNTLETS, ORCISH_SHORT_SWORD },
{ 0, 0, 0, }
};

int
doforging(void)
{
struct obj* obj1;
struct obj* obj2;
struct obj* output;
char allowall[2];
int i, objtype = 0;

allowall[0] = ALL_CLASSES;
allowall[1] = '\0';

/* first, we need a forge */
if (!IS_FORGE(levl[u.ux][u.uy].typ)) {
You("need a forge in order to forge objects.");
return 0;
}

/* next, the proper tool to do the job */
if ((uwep && !is_hammer(uwep)) || !uwep) {
pline("You'll need a hammer to forge successfully.");
return 0;
}

/* setup the base object */
obj1 = getobj(allowall, "use as a base");
if (!obj1) {
You("need a base object to forge with.");
return 0;
} else if (!is_metallic(obj1)) { /* object should be metallic */
pline_The("base object must be made of something metallic.");
return 0;
}

/* setup the secondary object */
obj2 = getobj(allowall, "combine with the base object");
if (!obj2) {
You("need more than one object.");
return 0;
} else if (!is_metallic(obj2)) { /* secondary object should also be metallic */
pline_The("secondary object must be made of something metallic.");
return 0;
}

/* handle illogical cases */
if (obj1 == obj2) {
You_cant("combine an object with itself!");
return 0;
} else if (is_worn(obj1) || is_worn(obj2)) { /* worn or wielded objects */
You("must remove the objects you wish to forge.");
return 0;
}

/* start the forging process */
for (i = 0; fusions[i][0] > 0; i++) {
if ((obj1->otyp == fusions[i][1] && obj2->otyp == fusions[i][2])
|| (obj2->otyp == fusions[i][1] && obj1->otyp == fusions[i][2])) {
objtype = fusions[i][0];
break;
}
}

if (!objtype) {
/* if the objects used do not match the recipe array,
the forging process fails */
You("fail to combine these two objects.");
return 1;
} else if (objtype) {
output = mksobj(objtype, TRUE, FALSE);

/* Take on the secondary object's material */
if (valid_obj_material(output, obj2->material)) {
output->material = obj2->material;
} else if (valid_obj_material(output, obj1->material)) {
output->material = obj1->material;
}

You("place the %s and the %s inside the forge.",
xname(obj1), xname(obj2));
pline("Raising your %s, you begin to forge the objects together...",
xname(uwep));

/* if objects are enchanted or have charges,
carry that over, and use the greater of the two */
if (output->oclass == obj2->oclass) {
output->spe = obj2->spe;
if (output->oclass == obj1->oclass)
output->spe = max(output->spe, obj1->spe);
} else if (output->oclass == obj1->oclass) {
output->spe = obj1->spe;
}

/* Transfer curses and blessings from secondary object */
output->cursed = obj2->cursed;
output->blessed = obj2->blessed;
/* ensure the final product is not degraded in any way */
output->oeroded = output->oeroded2 = 0;

/* Toss out old objects, add new one */
useup(obj1);
useup(obj2);
output = addinv(output);
You("have successfully forged %s.", an(xname(output)));
update_inventory();
}

return 1;
}

void
drinkfountain()
{
Expand Down

0 comments on commit 996d2c8

Please sign in to comment.