summaryrefslogtreecommitdiff
path: root/src/q_ultrag.cc
blob: d0ed41be09309b4b9325473f0cb0d0ffa85f7793 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#include "q_ultrag.h"

#include "cave.hpp"
#include "hooks.h"
#include "object1.hpp"
#include "object2.hpp"
#include "options.hpp"
#include "util.hpp"

#define cquest (quest[QUEST_ULTRA_GOOD])

static bool_ quest_ultra_good_move_hook(void *, void *in_, void *)
{
	struct hook_move_in *in = static_cast<struct hook_move_in *>(in_);
	s32b y = in->y;
	s32b x = in->x;
	cave_type *c_ptr = &cave[y][x];

	if (cquest.status == QUEST_STATUS_UNTAKEN)
	{
		bool_ old_quick_messages = quick_messages;

		if (quest[QUEST_MORGOTH].status < QUEST_STATUS_FINISHED) return (FALSE);

		/* The mirror of Galadriel */
		if ((c_ptr->feat != FEAT_SHOP) || (c_ptr->special != 23)) return (FALSE);

		quick_messages = FALSE;
		cmsg_print(TERM_L_BLUE, "You meet Galadriel.");
		cmsg_print(TERM_YELLOW, "'I still cannot believe this is all over.'");
		cmsg_print(TERM_YELLOW, "'Morgoth's reign of terror is over at last!'");
		cmsg_print(TERM_YELLOW, "'His spirit has been banished to the Void where he cannot do much harm.'");
		cmsg_print(TERM_YELLOW, "'We can never thank you enough, hero!'");
		cmsg_print(TERM_L_BLUE, "Although everything seems all right, Galadriel seems a little subdued.");
		cmsg_print(TERM_YELLOW, "'The spirit of Morgoth is not destroyed however -- only banished.'");
		cmsg_print(TERM_YELLOW, "'He can still control his allies left on Arda.'");
		cmsg_print(TERM_YELLOW, "'Maybe... maybe there could be a way to remove the threat of evil forever.'");
		cmsg_print(TERM_YELLOW, "'Somebody would have to go into the Void to do it.'");
		cmsg_print(TERM_YELLOW, "'But going there is certain death; we cannot ask it of anyone.'");
		cmsg_print(TERM_YELLOW, "'But you may choose, of your own free will, to attempt it...'");
		cmsg_print(TERM_L_BLUE, "Galadriel plainly presents the choice that now lies before you:");

		cmsg_print(TERM_YELLOW, "'You have earned the right to make whatever you wish of your future.'");
		cmsg_print(TERM_YELLOW, "'Become a ruler of Arda if you so desire; reign long, enjoying'");
		cmsg_print(TERM_YELLOW, "'the adulation of all, and have a happy life. Or, you can turn your'");
		cmsg_print(TERM_YELLOW, "'back on safety. Enter the Void, alone, to fight a hopeless battle'");
		cmsg_print(TERM_YELLOW, "'and face certain death.'");

		/* This is SO important a question that flush pending inputs */
		flush();

		if (!get_check("Will you stay on Arda and lead a happy life?"))
		{
			cmsg_print(TERM_YELLOW, "'So be it. I will open a portal to the Void.'");
			cmsg_print(TERM_YELLOW, "'But you must know this: the portal can only lead one way.'");
			cmsg_print(TERM_YELLOW, "'It will close once you enter, so as not to permit the horrors'");
			cmsg_print(TERM_YELLOW, "'that lurk in the Void to enter Arda. Your only way to come back'");
			cmsg_print(TERM_YELLOW, "'is to defeat the spirit of Morgoth, known as Melkor.'");
			cmsg_print(TERM_YELLOW, "'You will not be able to recall back either.'");
			cmsg_print(TERM_YELLOW, "'You can still choose to retire; it is not too late'");
			cmsg_print(TERM_YELLOW, "'to save your life.'");
			cmsg_print(TERM_YELLOW, "'One last thing: It is quite certain that Melkor will have erected'");
			cmsg_print(TERM_YELLOW, "'powerful magical barriers around him. You certainly will'");
			cmsg_print(TERM_YELLOW, "'need to find a way to break them to get to him.'");

			/* Create the entrance */
			cave_set_feat(y - 5, x, FEAT_MORE);
			cave[y - 5][x].special = 11;

			/* Continue the plot */
			cquest.status = QUEST_STATUS_TAKEN;
			cquest.init(QUEST_ULTRA_GOOD);
		}
		quick_messages = old_quick_messages;

		return TRUE;
	}

	return FALSE;
}

static bool_ quest_ultra_good_stair_hook(void *, void *in_, void *)
{
	struct hook_stair_in *in = static_cast<struct hook_stair_in *>(in_);
	stairs_direction dir = in->direction;

	if (dungeon_type != DUNGEON_VOID)
		return FALSE;

	/* Cant leave */
	if ((dir == STAIRS_UP) && (dun_level == 128))
	{
		cmsg_print(TERM_YELLOW, "The portal to Arda is now closed.");
		return TRUE;
	}
	/* there is no coming back */
	if ((dir == STAIRS_UP) && (dun_level == 150))
	{
		cmsg_print(TERM_YELLOW, "The barrier seems to be impenetrable from this side.");
		cmsg_print(TERM_YELLOW, "You will have to move on.");
		return TRUE;
	}
	/* Cant enter without the flame imperishable */
	if ((dir == STAIRS_DOWN) && (dun_level == 149))
	{
		int i;
		bool_ ultimate = FALSE;

		/* Now look for an ULTIMATE artifact, that is, one imbued with the flame */
		for (i = INVEN_WIELD; i < INVEN_TOTAL; i++)
		{
			u32b f1, f2, f3, f4, f5, esp;
			object_type *o_ptr = get_object(i);

			if (!o_ptr->k_idx) continue;

			/* Examine the gloves */
			object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp);

			if (f4 & TR4_ULTIMATE)
			{
				ultimate = TRUE;
				break;
			}
		}

		if (!ultimate)
		{
			cmsg_print(TERM_YELLOW, "It seems the level is protected by an impassable barrier of pure magic.");
			cmsg_print(TERM_YELLOW, "Only the most powerful magic could remove it. You will need to use");
			cmsg_print(TERM_YELLOW, "the Flame Imperishable to pass. The source of Eru Iluvatar's own power.");
			return TRUE;
		}
		else
		{
			cmsg_print(TERM_YELLOW, "The power of the Flame Imperishable shatters the magical barrier.");
			cmsg_print(TERM_YELLOW, "The way before you is free.");
		}
	}

	return FALSE;
}

static bool_ quest_ultra_good_recall_hook(void *, void *, void *)
{
	if ((dungeon_type != DUNGEON_VOID) && (dungeon_type != DUNGEON_NETHER_REALM))
		return FALSE;

	cmsg_print(TERM_YELLOW, "You cannot recall. The portal to Arda is closed.");
	return TRUE;
}

static bool_ quest_ultra_good_death_hook(void *, void *in_, void *)
{
	struct hook_monster_death_in *in = static_cast<struct hook_monster_death_in *>(in_);
	s32b m_idx = in->m_idx;

	monster_type *m_ptr = &m_list[m_idx];

	/* Melkor is dead! */
	if (m_ptr->r_idx == 1044)
	{
		/* Total winner */
		total_winner = WINNER_ULTRA;
		has_won = WINNER_ULTRA;
		quest[QUEST_ULTRA_GOOD].status = QUEST_STATUS_FINISHED;

		/* Redraw the "title" */
		p_ptr->redraw |= (PR_FRAME);

		/* Congratulations */
		cmsg_print(TERM_L_GREEN, "****** CONGRATULATIONS ******");
		cmsg_print(TERM_L_GREEN, "You have done more than the impossible. You ended the threat of");
		cmsg_print(TERM_L_GREEN, "Melkor forever. Thanks to you, Arda will live in eternal peace.");
		cmsg_print(TERM_L_GREEN, "You feel the spirit of Eru touching you. You feel your spirit rising!");
		cmsg_print(TERM_L_GREEN, "Before you, a portal to Arda opens. You can now come back to your world");
		cmsg_print(TERM_L_GREEN, "and live happily ever after.");
		cmsg_print(TERM_L_GREEN, "What you do now is up to you, but your deeds shall ever be remembered.");
		cmsg_print(TERM_L_GREEN, "You may retire (commit suicide) when you are ready.");

		/* Create the entrance */
		cave_set_feat(p_ptr->py, p_ptr->px, FEAT_MORE);

		/* Remove now used hook */
		del_hook_new(HOOK_MONSTER_DEATH, quest_ultra_good_death_hook);
		process_hooks_restart = TRUE;

		/* End plot */
		*(quest[QUEST_ULTRA_GOOD].plot) = QUEST_NULL;
	}

	/* Tik'svvrzllat is dead! */
	if (m_ptr->r_idx == 1032)
	{
		int i;

		/* Get local object */
		object_type forge, *q_ptr = &forge;

		/* Mega-Hack -- Prepare to make the Flame Imperishable */
		object_prep(q_ptr, lookup_kind(TV_JUNK, 255));

		/* Mega-Hack -- Actually create the Flame Imperishable */
		k_allow_special[296] = TRUE;
		apply_magic(q_ptr, -1, TRUE, TRUE, TRUE);
		k_allow_special[296] = FALSE;

		/* Identify it fully */
		object_aware(q_ptr);
		object_known(q_ptr);

		/* Mark the item as fully known */
		q_ptr->ident |= (IDENT_MENTAL);

		/* Find a space */
		for (i = 0; i < INVEN_PACK; i++)
		{
			/* Skip non-objects */
			if (!p_ptr->inventory[i].k_idx) break;
		}
		/* Arg, no space ! */
		if (i == INVEN_PACK)
		{
			char o_name[200];

			object_desc(o_name, &p_ptr->inventory[INVEN_PACK - 1], FALSE, 0);

			/* Drop the item */
			inven_drop(INVEN_PACK - 1, 99, p_ptr->py, p_ptr->px, FALSE);

			cmsg_format(TERM_VIOLET, "You feel the urge to drop your %s to make room in your inventory.", o_name);
		}

		/* Carry it */
		cmsg_format(TERM_VIOLET, "You feel the urge to pick up the Flame Imperishable.");
		inven_carry(q_ptr, FALSE);
	}
	return (FALSE);
}

static bool_ quest_ultra_good_dump_hook(void *, void *in_, void *)
{
	struct hook_chardump_in *in = static_cast<struct hook_chardump_in *>(in_);
	FILE *f = in->file;

	if (quest[QUEST_ULTRA_GOOD].status >= QUEST_STATUS_TAKEN)
	{
		/* Ultra winner ! */
		if (total_winner == WINNER_ULTRA)
		{
			fprintf(f, "\n You destroyed Melkor forever and have been elevated to the status of Vala by Eru Iluvatar.");
			fprintf(f, "\n Arda will forever be free.");
		}
		else
		{
			/* Tried and failed */
			if (death)
			{
				fprintf(f, "\n You tried to destroy Melkor forever, but died in the attempt.");
				fprintf(f, "\n Arda will be quiet, but not free from evil.");
			}
		}
	}
	return (FALSE);
}


bool_ quest_ultra_good_init_hook(int q)
{
	if ((cquest.status >= QUEST_STATUS_TAKEN) && (cquest.status < QUEST_STATUS_FINISHED))
	{
		add_hook_new(HOOK_STAIR,         quest_ultra_good_stair_hook,  "ultrag_stair",  NULL);
		add_hook_new(HOOK_RECALL,        quest_ultra_good_recall_hook, "ultrag_recall", NULL);
		add_hook_new(HOOK_MONSTER_DEATH, quest_ultra_good_death_hook,  "ultrag_death",  NULL);
	}
	if (cquest.status == QUEST_STATUS_UNTAKEN)
	{
		add_hook_new(HOOK_MOVE, quest_ultra_good_move_hook, "ultrag_move", NULL);
	}
	add_hook_new(HOOK_CHAR_DUMP, quest_ultra_good_dump_hook, "ultrag_dump", NULL);
	return (FALSE);
}