Jump to content

Creating Boss fight


kane4355

Recommended Posts

I am fairly new to questing and putting it all together. I have a small understanding of scripting, mainly using what already exists and putting it together into something that works. I also am able to create basic quests, such as kill X number of enemy or read this etc.... But i wanted to create a very complex Boss fight at the end of my mod, something almost similiar to the Gauldur Amulet fight in Reachwater Rock. I am no where close to understanding How I will get this done so if anyone can point me in the right directions or a tutorial to get me started (even to tell me its time consuming and not worth the time). but in case it still peaks the curiousity and I want to try to implement it. basically, I want to set up about 8 Phases incremented through a single NPC's health levels (lets call him NPC 1). Fight starts as soon as player walks into the room begining phase 1. Phase 2 starts when NPC 1's health goes down 25%, begining phase 2 which NPC 1 teleports out and summons in a wave of draugr who spawn from sarcphagus inside the chamber. Phase 2 ends when the Draugr are all killed, starting Phase 3 where NPC 1 pops in again to fight the player. Phase 3 ends when NPC 1 reaches 50% health teleporting out once again, starting phase 4 summoning in reanimated versions of 4 Dragon priests (reduced health). Phase 4 ends when they die, starting phase 5 with NPC 1 teleporting in, but this phase he randomly teleports between 6 locations, 4 on ledges where NPC 1 bombards player with destruction magic and other 2 within reach for a melee player to pummel NPC 1. Phase 5 ends when NPC 1 health reaches 25%, NPC teleports out and summons the remaining 4 reanimated dragon priests. This is phase 6. Phase 6 ends with their death, summoning in 1-2 Draugr Deathlords (reduced health) starting phase 7. Phase 7 ends on their death, NPC 1 teleports in starting phase 8. Phase 8 ends when NPC 1 is killed.

 

is this possible? i have tried looking over the amulet scene to see if i can understand how to get all that to happen but im clueless. any help would be much appreciated.

Link to comment
Share on other sites

  • Replies 60
  • Created
  • Last Reply

Top Posters In This Topic

Best advice, and you probably already know this:

Look how its done in the other boss fight.,

Learn how bethesda have done it, see if there are scripts or various animations used.

I know its not very helpful, but it is worth doing to help you learn.

Link to comment
Share on other sites

yes i figured it would be so... however, the boss fight there has great differences to what i actually want to do. first off, it includes multiple NPC's. one of the battles puts one of the NPC's on a platform with fakes randomly around the cell. It could prove useful for some things, however, it still alien to me even when i read them. what part of the script would i need and what part of the script does this?

 

i also already know where i would start and it of course would involve quest stages and multiple scripts. I would use the GetActorValuePercentage and establish NPC1's phases as such:

 

; Obtain NPC1's current health actor value
float NPC1Health = NPC1.GetAVPercentage("Health")
if (NPC1Health == 0.75)
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
endIf

 

However the above code only works IF the health is exactly 75%. what happens if the player hits the NPC enough that it goes below that percentage? And I cannot do <0.75 because it would just create an ongoing loop as the NPC's health went down. I would just want the next phase to start once the health gets past 75%. could there be a DoOnce command for this? Also, Once the phase completes for the Draugr, how would the NPC1 teleport back in with the same amount of health it left with? Or do I need to define that specifically with a ForceActorValue?

 

The next phase would be pretty simple, however when the Draugr are coming in, how would i silence NPC1 and place him idle on a platform above and invulnerable? Each draugr would need an alias set up in the quest. each alias would have a script to IncrementDraugrDeath. the alis scripts would designate a parent script and this parent script would define what the level of increment does, and what it will do once the increment is met. obviously in this case settting a higher quest stage and then moving NPC1 back into the fight for the next phase. The draugr scripts would be as followed: (these are just examples from scripts used in previous quests i have made)

 

Quest Script:

 

Scriptname DKHODfightscript extends Quest

int Property TotalDraugr Auto
int DeadDraugr = 0
ObjectReference Property DKQbook02 auto

 function IncrementDeadDraugr()
      DeadDraugr = DeadDraugr + 1
      if DeadDraugr >= TotalDraugr
	DKQbook02.enable(true)
            setStage(20)
      endif
endFunction

 

Alias Script

 

Scriptname DKQHDDraugrdeadcountscript extends ReferenceAlias

DKHODfightscript Property myQuestScript auto 

Event OnDeath(Actor akKiller)
       ; increment dead count
       myQuestScript = GetOwningQuest() as DKHODfightscript
       myQuestScript.IncrementDeadDraugr()
endEvent

 

As far as I know, each Draugr would need a separate Alias defined with each one having this script or at least that is how it has worked so far.

 

So that is where I am at. The increment scripts can be applied to the Dragon Priests as well. But implementing the phases of NPC1 and getting him to teleport and do all those special things is where I am stuck at. I will continue to investigate possibilities.

Link to comment
Share on other sites

So i found a DoOnce script from an existing vanilla script, defaultActivateLinkDoOnceSCRIPT. it is a bool property and is set to true by manually setting it through the properties.

this is the script:

 

ScriptName defaultActivateLinkDoOnceSCRIPT extends objectReference
{Default script intended for triggers.  When hit, they'll activate their linked reference}

import game
import debug

objectReference property OnlyActor auto
{Set this property if you want to only allow activation from a specific actor, such as the player}

bool property doOnce auto
{by default, this trigger fires once only.}

function ActivateNow(objectReference trigRef)
; 	Debug.Trace("Activating: " + self + " " + myLink)
objectReference myLink = getLinkedRef()

self.activate(self, true)
if MyLink != NONE
	myLink.activate(self as objectReference)	
endif
if doOnce == true
	gotoState("allDone")
endif
endFunction

auto STATE waiting
EVENT onTriggerEnter(objectReference actronaut)
; 	Debug.Trace("Trigger Enter: " + actronaut)
		
	if !onlyActor
		activateNow(actronaut)
	endif
	
	if onlyActor == actronaut
		activateNow(actronaut)
	endif
	
endEVENT
endSTATE

STATE allDone
;do nothing
endSTATE

 

i am assuming this value when set true applies to the whole script and not to just a certain line. I am wondering If I could use it per phase, such as this:

 

; Obtain NPC1's current health actor value
float NPC1Health = NPC1.GetAVPercentage("Health")
if (NPC1Health == 0.75)
 if DoOnce == true
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
 endif
endIf

 

could this make it possible to include all phases in one script or will i have to create a script for each phase, being one for <=.75, <=.50, and <=.25 all with the DoOnce command?

 

Edit: I just got another idea: incrementing a value so that when one phase happens it increases the value and each phase requires a certain value in order for its actions to become true.

 

example:

 

int NPC1Phase = 0 ;initiates phase increment value

; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health")
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf

Edited by kane4355
Link to comment
Share on other sites

So, i used that above and put it in to see if it would compile, using the below script:

 

Scriptname DKRashPhaseset01 extends ObjectReference

Actor Property NPC1  Auto 
int NPC1Phase = 0 ;initiates phase increment value

; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health")
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf

 

i got the following errors on compilation:

 

Starting 1 compile threads for 1 files...

Compiling "DKRashPhaseset01"...

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\DKRashPhaseset01.psc(7,19): no viable alternative at input 'NPC1'

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\DKRashPhaseset01.psc(7,23): required (...)+ loop did not match anything at input '.'

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\DKRashPhaseset01.psc(7,6): Unknown user flag NPC1

No output generated for DKRashPhaseset01, compilation failed.

 

it seems line 7 is having some issues with syntax. line 7 is as follows:

float NPC1Health = NPC1.GetAVPercentage("Health")

 

I know that with certain extensions, syntax's change because they are allowed in certain references and others just do not comprehend it, which is why it sends an error. that syntax was taken directly from the wiki, only thing changed was the name from bob to NPC1. There is a possibility that my extension is not right. Maybe I should set this as a quest extension?

 

Edit: that doesnt work either....

Edited by kane4355
Link to comment
Share on other sites

some more homework on this. I added an event and changed it back to an object reference extension. I will attach it to NPC1 and have the script start once NPC1 has been activated (NPC1 idles in a sarcphagus and activates upon layer walking into a trigger box)

 

This is what I have so far ( and it seems no matter what the case it just doesnt want to give, so I am missing something):

 

Scriptname DKRashPhaseset01 extends ObjectReference

ObjectReference Property NPC1  Auto 
int NPC1Phase = 0 ;initiates phase increment value

Event OnActivate(ObjectReference akActionRef)
; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health") 
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
Endevent

 

now the value NPC1 sticks because I created an event ( i think) but now I get this error:

 

Starting 1 compile threads for 1 files...

Compiling "DKRashPhaseset01"...

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\DKRashPhaseset01.psc(8,24): GetAVPercentage is not a function or does not exist

c:\program files (x86)\steam\steamapps\common\skyrim\Data\Scripts\Source\temp\DKRashPhaseset01.psc(8,6): type mismatch while assigning to a float (cast missing or types unrelated)

No output generated for DKRashPhaseset01, compilation failed.

 

the same line, now line 8 is having issues recognizing GETAVPercentage as a function at all. it also is giving me an error on float. do i replace float with function?

 

EDIT: NOPE!!!! it stays a float. the problem was with the extension after all. actors are not part of objectreferences even though you can set them. in some cases, actors are just like object references but have more values or things that can be done to them. in which case, finding the health value of an object reference would be retarded because they dont have health whereas actors do. So I changed the extenstion to "Actor" and the Property as well and it compiled. here it is:

 

Scriptname DKRashPhaseset01 extends Actor

Actor Property NPC1  Auto 
int NPC1Phase = 0 ;initiates phase increment value

Event OnActivate(ObjectReference akActionRef)
; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health") 
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 ;(Do Stuff)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
Endevent

 

Now I have the transition to Phase 2... however, there are still some unknowns I will have to work with... such as How can I teleport NPC1 to another location keeping the same health and stats, silence him and keep him still? and then teleport him back in when phase 2 is complete, teleporting him with the same health and stats and lifting the silence stillness?

 

an idea comes to mind that effects mannequins and keeps them still BUT i believe its an AIdata field and nothing to do with the scripts. OR I could just enable an actor with stats that resemble the mannequins in those locations and just disable the real actor... but how does the health persist through this?

Edited by kane4355
Link to comment
Share on other sites

i stopped brainstorming on here to finish off some work and started yesterday with the script and this is what I have so far:

 

Scriptname DKRashPhaseset01 extends Actor

Actor Property NPC1  Auto 
int NPC1Phase = 0 ;initiates phase increment value
ObjectReference Property teleportnointeraction01 auto
Quest Property myQuest01 auto
int Property StageSet01 auto
int Property StageSet02 auto
int Property StageSet03 auto
ObjectReference Property DKRAGfake01 auto
ObjectReference Property DKRAGfake02 auto

Event OnActivate(ObjectReference akActionRef)
; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health") 
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet01)
DKRAGfake01.Enable(true)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf 
if (NPC1Health <= 0.50)
 if NPC1Phase == 1
 ;Initiate Phase 4
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet02)
DKRAGfake01.Enable(true)
       ;Do More stuff
 Debug.Trace("NPC1 has less then 50% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
if (NPC1Health <= 0.25)
 if NPC1Phase == 2
 ;Initiate Phase 6
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet03)
DKRAGfake02.Enable(true)
       ;Do More stuff
 Debug.Trace("NPC1 has less then 25% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
Endevent

 

 

 

it is still incomplete, as you can see ";(Do Stuff)" is where i haven't put anything in. here is basically what I want to do and this script is basic because my understanding is basic.. There are 8 phases. the first phase starts when the player crosses a trigger point and activates a door opening and the NPC1 who is sleeping in a coffin to awaken (exactly like a dragon priest, because he is one). Once NPC1's health reaches 75% phase two starts. he teleports to a ledge and cannot be interacted with, does not initiate combat and ignores everything, pretty much silenced and the player cannot interact with him. during this phase Draugr are activated from their slumber and attack the player. this is phase 2. Once the draugr are all dead, phase 3 starts with NPC1 teleporting back in initiating combat with player and having the same health he left with. phase 4 starts when NPC1 has 50% health where he teleports to the ledge once again, same as phase 2. This time, lesser dragon priests are brought in, 4 of them to be exact. player kills these and it initiates phase 5. 6 locations around the room are set, 4 of them on ledges out of players reach except by long range means and 2 are on the ground within players range for melee. during phase 5, NPC1 will randomly teleport to each of these locations, but not stay more than 30 seconds and randomly move to another one. the 4 locations on ledges, the NPC does not move but stays in the location until he randomly moves to another location, bombarding player with destruction magic. Once the NPC1 gets his health down to 25% he teleports out again to the ledge where he cannot be interacted with and 4 more dragon priests are awakened, same as phase 4. this starts phase 6. once they die, phase 7 starts with the dragon priest summoned in... normal fight like phase 1 but with a catch: the player has a time limit to kill the dragon priest because after a while he starts reanimating the dead draugr and dragon priests that died in the room. after 30 seconds, 4 draugr are reanimated. after 1 minute, another 4 draugr. after 1.5 minutes, 4 dragon priests, and after 2 minutes another 4 dragon priests. the times may vary depending on level of difficulty at the end but i plan on this being a lvl 50+ mod. NPC1 will be flagged as essential so once he reaches bleedout this starts phase 8. all the reanimated corpses are killed and the staff the dragon priest wields is dropped. the player will take and equip the staff and use it to attack the priest which will kill him off. once he does that, the player has the option to either keep the staff or destroy it (due to it being evil).

 

increment scripts:

 

quest:

 

Scriptname DKdraugrquestfightscript extends Quest

int Property TotalDraugr Auto
int DeadDraugr = 0
int Property Stageset Auto
       
 function IncrementDeadDraugr()
      DeadDraugr = DeadDraugr + 1
      if DeadDraugr >= TotalDraugr
            setStage(Stageset)
               DeadDraugr == 0 ;Resets value to 0
               endif
endFunction

 

 

 

alias:

 

Scriptname DKQITCPH1Draugrdeadscript extends ReferenceAlias

DKdraugrquestfightscript Property myQuestScript auto 

Event OnDeath(Actor akKiller)
       ; increment dead count
       myQuestScript = GetOwningQuest() as DKdraugrquestfightscript
       myQuestScript.IncrementDeadDraugr()
endEvent

 

 

 

i have 2 scripts (above) that work fine for knowing when the draugr die and it revolves around questing. so, once the NPC1's health reaches 75%, he does all that other stuff plus set a stage that activates a traplinker connected to all the draugr. then i created 3 increment checkers as quest scripts, one for the draugr, one for the first set of dragon priests and one for the third. then creating an alias for every single actor involved and then applying 3 different scripts that increment their specific value up ondeath. 8 draugr, once 8 deaths occur, an action is taken which is setting the stage of the quest to the next level which i added this in as a fragment code on the next stage:

Alias_DKRAGfakealias01.GetReference().Disable()
Alias_DKRashAulGhuulalias.GetReference().MoveTo(DKRAGteleportinteract01)
Alias_DKRashAulGhuulalias.GetReference().Activate(Game.GetPlayer())

 

 

 

the first line disables the fake npc, second line teleports NPC1 back into the room for the fight, and the third line i am not sure if i need, because the original script is set up to run onactivate and i did not know if it would do a continue loop or turn off once a specific event was met. so i set it to activate the NPC1 again. this will also be applied to the dragonpriests, but with different script names and a different increment variable.

 

The script above is attached to NPC1 and the onactivate event is when the player crosses the trigger, activating the dragon priest. questions and confusions: does the onactivate continue a loop, as in does the script stay activated through numerous IF functions? IE does a loop apply in the script i have above until the last IF function is met or does it stop when one IF section is met? such as if the phase = 0 and if the health <= .75, will it stop there and not continue when the NPC1 reaches 50%?

 

one of the issues i have is not teleporting the npc but moving the same NPC and making them non-interactive, keeping the same health and bring them back in all while having them in plain view of the player. the best way i can think of this is creating a room outside of the actual fight room, distant in the void and closed off with an xmarker heading specified as a teleport location and NPC1.Moveto that location, with collision markers around him, keeping him there until he gets teleported back. and on the same line, creating two fake visuals, using the mannequin traits and AIdata, but with my NPC1's nif file, set them on initially disabled, and enable one when npc1 gets teleported out. is there an easier way to do that? i thought about doing a playidle on the NPC1 when i teleporting him to the ledge location, but it says that it is very volatile when doing this in conjunction with waiting on an event to occur, not to mention it doesnt exclude being able to damage him or silence him NOR does it give a way to reverse the effect when teleported back.

 

second issue i have is the random effect of teleporting in during phase 5. I set xmarkerheadings as the 6 locations he can teleport in at, but how to set it up so that it does it randomly until he reaches less than 50% health is beyond me. I was going to jerry rig it into a way so that he goes through the six locations every 30 seconds on a rythm and then it loops back until he gets down to the specified health. But, setting it to loop back is an issue for me to understand as well. i havent seen while loops at all in papyrus.

 

third issue, is setting up the interval of reanimation during phase 7. I suppose i can set a wait timer and do a reanimate but what would be the best way to go about it.

 

4th issue is how do i go about doing phase 8? how do i go about being able to kill an essential player in bleedout just by the simple burst of a certain staff? i know you can killessential and can do an onswing, but this is a magic staff, can you do something like that?

Edited by kane4355
Link to comment
Share on other sites

You are using the Event OnActivate() which basically is saying when the player "talks" to the boss it will start the script. You want to change the beginning Event OnActivate() to Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked).

Note: Keep akAggressor blank and don't call it Game.GetPlayer() otherwise if companions attack it wont register.

Link to comment
Share on other sites

i was actually thinking of just removing an event all together. the draugr increment script does what it is supposed to do without any activation and is attached to the quest self and sets up a function to increment. so that is what i tried doing here :

 

Scriptname DKRashPhaseset01 extends Actor

Actor Property NPC1  Auto 
int NPC1Phase = 0 ;initiates phase increment value
ObjectReference Property teleportnointeraction01 auto
Quest Property myQuest01 auto
int Property StageSet01 auto
int Property StageSet02 auto
int Property StageSet03 auto
ObjectReference Property DKRAGfake01 auto
ObjectReference Property DKRAGfake02 auto

function IncrementNPC1Phase()
; Obtain NPC1's current health actor value to establish phase lines
float NPC1Health = NPC1.GetAVPercentage("Health") 
if (NPC1Health <= 0.75)
 if NPC1Phase == 0
 ;Initiate Phase 2
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet01)
DKRAGfake01.Enable(true)
 Debug.Trace("NPC1 has less then 75% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf 
if (NPC1Health <= 0.50)
 if NPC1Phase == 1
 ;Initiate Phase 4
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet02)
DKRAGfake01.Enable(true)
 Debug.Trace("NPC1 has less then 50% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
if (NPC1Health <= 0.25)
 if NPC1Phase == 2
 ;Initiate Phase 6
 	NPC1.MoveTo (teleportnointeraction01)
myQuest01.SetStage(StageSet03)
DKRAGfake02.Enable(true)
 Debug.Trace("NPC1 has less then 25% health remaining")
 NPC1Phase = NPC1Phase +1
 endif
endIf
endFunction

 

i really dont want it to activate, i want it active 24/7 to allow for the looping effects and if functions to work. but if this doesnt work then ill attempt the onhit.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...