Never Again


Summary

  • Name: Never Again
  • Development Time: 160 hours
  • Genre: RPG
  • Playtime: 10-15 minutes
  • Engine: Creation Kit

 

Download
.zip File
Design Goals

  • Design a quest that works within the lore of the Elder Scrolls Universe
  • Create at least one reusable script
  • Script a boss level power

Tasked with stopping another Oblivion Crisis before it starts, Never Again has the player hunting down the servant of a would be Daedric Price and ending this threat to Cyrodiil.

Layout and Design: The Abandoned Home

abandoned home map

Walkthrough

  1. Directed here by a quest giver at Riverwood Bridge, the player enters an abandoned home, cobwebs and dust are all that live here. They are searching for clues as to the whereabouts of a spell caster in league with a Daedric Prince.
  2. A secret underground basement shows light use, cobwebs are still present but fewer in number. Still no combat by this point.
  3. A strange room with a bloody archway is the most obvious thing in the room. Sets of bloody rag litter the room. Across from the archway is a small work area with books and arcane tools. A journal here progresses the quest and give the player a bit of back story and a way forward, head to a crypt and acquire a sigil stone to open the portal into Oblivion. After acquiring the journal the portal opens and out comes a (D)aedra which then attacks the player. The portal isn’t working yet on this end, the player needs a sigil stone to affect transportation.

Design Goals

  • Start the quest with some exploration and light combat to get the player warmed up
  • Foreshadow the players trip to the Bloodrealm within the abandoned home

Layout and Design: The Desecrated Crypt

 Crypt map

Walkthrough

  1. The entrance to this area serves as a safe starting point. Cobwebs cover the path deeper into the crypt, are intact and break when the player walks through them.
  2. The large room here has the standard enemies you’d expect; (s)keletons and (d)rauger. Skeletons attack immediately and the drauger wait until triggered by the blue trigger volumes.
  3. The main interment section of the crypt has a (D)aedra problem, They are searching this area for something when the player arrives. A small group of (d)rauger take umbrage to people walking by.
  4. The (D)aedra in this area are searching as well when the player arrives. The daedra are spread between the upper and lower floors, this helps prevent the player from being overwhelmed by numbers. Killing the daedra leaves the path to the Sigil Stone (SS) open. The southern room holds the passage back to the beginning of the level and a quick escape to the next stage.

Design Goals

  • Challenge the player with a series of combats
  • Give the player a chance to get used to their NPC Ally’s combat style

Layout and Design: The Bloodrealm, Oblivion

blood realm map

Walkthrough

  1. After returning to the Abandoned Home, the player steps through the portal in the basement, but now with the sigil stone in hand it takes them into Oblivion. While here in the Bloodrealm of Oblivion the player is constantly being rained on by blood. He starts on an island with bodies floating in the blood ocean. A brief walk towards the main island triggers a bridge to rise up out of the water (see Scripting: Bridge) allowing the player to cross without swimming in blood
  2. Once past the bridge the player is set upon by two (D)aedra, an archer and a melee fighter, who are patrolling the path. Dotting the path on either side are spiked bloody skulls. At the top of the path is a tower that the player climbs and has a rooftop battle with another (D)aedra.
  3. The spikes have given way to stone piles, also adorned with bloody bones.  Here two (D)aedra guard the path forward, an archer and a melee fighter.
  4. The staircase takes the player up their final ascension. A (D)aedra spellcaster blocks the path raining spells from above.
  5. The boss fight. Once the player enters the blood soaked castle the object of their search, the mad mage Romani, demands to know how you got here. No matter what the player says they are attacked by Romani. Once Romani is defeated a portal opens nearby to let the player out.

The boss fight breaks down as follows:

  • When Romani starts the fight he summons help in the form of a (D)aedra
  • When damaged to 66% and then again at 33%:
    • a new (D)aedra is spawned into the fight
    • the (B)oss teleports away from where it last stood to the opposite turret (See Scripting: Boss Teleportation)
  • Once the boss dies all the summoned daedra still alive disappear

These simple mechanics, coupled with Romani’s selection of ranged spells, make for an interesting fight. You are constantly being double teamed by Romani and his minion, attacking him with magic is difficult (ward spells) and if you go toe to toe with him he will teleport away just as you are starting to do damage. The trick for the player is managing the daedra while dealing with the boss, either by killing them as soon as they spawn or avoiding them and chasing Romani.

Design Goals

  • Give the appearance of blood everywhere
  • Give the boss a power beyond the player
  • Make the player feel like they are in Oblivion

Scripting: Bridge

A single reusable script was made to build and collapse the bridge.

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
Scriptname aaNSBridgeAnimation extends ObjectReference  
 
;Variables
ObjectReference Property Up  Auto  
ObjectReference Property Down  Auto  
Bool Property IsUp  Auto  
Bool Property doOnce  Auto  
ObjectReference Property NextObj  Auto  
Float Property waitDuration  Auto  
 
Event OnActivate(ObjectReference akActionRef)
	;Transitioning
	if(IsUp == true)
 
	        ;debug.notification(akActionRef + "Activated me to go Down")
 
		self.enable()
		Up.disable()
		self.TranslateTo(Down.GetPositionX(), Down.GetPositionY(), Down.GetPositionZ(),Down.GetAngleX(),Down.GetAngleY(),Down.GetAngleZ(), 500.0, 50.0)
		IsUp=false
 
		if(waitDuration > 0.0 )
			utility.wait(waitDuration)
		endif
	else
		;debug.notification(akActionRef + "Activated me to go up")
		self.enable()
		Down.disable()
		self.TranslateTo(Up.GetPositionX(), Up.GetPositionY(), Up.GetPositionZ(),Up.GetAngleX(),Up.GetAngleY(),Up.GetAngleZ(), 500.0, 50.0)
		IsUp=true
 
		if(waitDuration > 0.0 )
			utility.wait(waitDuration)
		endif
	endif
EndEvent
 
Event OnTranslationComplete()
	;after moving enable location and disable self
	if(IsUp)
		Up.enable()
		utility.wait(0.1)
		self.disable()
	elseif(!IsUp)
		Down.enable()
		utility.wait(0.1)
		self.disable()
	endif
EndEvent
 
Event OnCellLoad()
        ;inital setup
	self.TranslateTo(Down.GetPositionX(), Down.GetPositionY(), Down.GetPositionZ(),Down.GetAngleX(),Down.GetAngleY(),Down.GetAngleZ(), 5000.0, 100.0)
	IsUp=false
	up.disable()
	Down.enable()
	self.disable()
EndEvent

Scripting: Boss Teleportation

I wanted the boss of this quest to do something memorable. I thought that if the boss teleported away from the player and was given distance to cast spells it would be a unique way for a spellcaster to get range instead of simply running and turning around. Getting the boss to teleport was easy, but where to teleport him to was not, how am I to know where the boss and player will be fighting? Do I use triggers or a central location to teleport to? Each had its appeal but in the end I went with a mix of these ideas.

I placed an xmarker in the center of the battlefield and one at each landing point. Using the TeleportMe() function, the boss teleports to a landing point on the opposite side of the center mark when the boss had taken enough damage. Each landing point is assigned a name based on its location in relation to the center xmark.

I placed an xmarker in the center of the battlefield and one at each landing point. Using my custom TeleportMe() function, the boss teleports to a landing point on the opposite side of the center mark when the boss had taken enough damage(at both 66% and 33% health). Each landing point is assigned a name based on its location in relation to the center xmark.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Function TeleportMe() ;this function is used to teleport the Boss.  
;The centerMarker should be placed in the center of the arena. 	
        float myX = self.GetPositionX()
 	float myY = self.GetPositionY()
 	float centerX = centerMarker.GetPositionX()
 	float centerY = centerMarker.GetPositionY()
 	float diffX = centerX - myX
 	float diffY = centerY - myY
 	;debug.notification("X:" + diffX + " Y:" + diffY )
        ;place the boss in the opposite corner from the player
 	if(diffX < 0)
		if(diffY < 0)
			self.MoveTo(FrontRight)
		else
			self.MoveTo(BackRight)
		endIf
	else
		if(diffY < 0)
			self.MoveTo(FrontLeft)
		else
                        self.MoveTo(BackLeft)
		endIf
	endIf
EndFunction

Full Playthrough