Scarlet Van Halisha - Client Behavior Breakdown

Blitzkrieg

Знающий
Участник
Сообщения
57
Розыгрыши
0
Решения
2
Репутация
38
Реакции
79
Баллы
403
This thread is about first stage Scarlet Van Halisha ( on foot -NPCID: 29046, class: follower_of_frintessa).

Many think that the walking boss is two different NPCs, but it's actually one. It simply has two sets of animations, one set without wings on its back, and one set with wings.

How the boss utilizes the different sets of animations

Frst of all, we inspect lineagemonster3.int:

WalkAnimName[0]=Run_1HS
RunAnimName[0]=Run_1HS
WaitAnimName[0]=AtkWait_1HS
AtkWaitAnimName[0]=AtkWait_1HS
Atk01AnimName[0]=Atk01_1HS
Atk02AnimName[0]=Atk01_1HS
Atk03AnimName[0]=Atk01_1HS
SpAtk01AnimName[0]=SpAtk01_1HS
SpAtk02AnimName[0]=SpAtk02_1HS
SpAtk03AnimName[0]=SpAtk03_1HS
CastShortAnimName[0]=SpAtk01_1HS
CastMidAnimName[0]=SpAtk01_1HS
CastLongAnimName[0]=SpAtk01_1HS
CastEndAnimName[0]=AtkWait_1HS
MagicShotAnimName[0]=SpAtk02_1HS
MagicThrowAnimName[0]=SpAtk02_1HS
MagicNoTargetAnimName[0]=SpAtk02_1HS
DeathAnimName[0]=Death
DeathWaitAnimName[0]=Deathwait

WalkAnimName[1]=Run_1HS
RunAnimName[1]=Run_1HS
WaitAnimName[1]=AtkWait_1HS
AtkWaitAnimName[1]=AtkWait_1HS
Atk01AnimName[1]=Atk01_1HS
Atk02AnimName[1]=Atk01_1HS
Atk03AnimName[1]=Atk01_1HS
SpAtk01AnimName[1]=SpAtk01_1HS
SpAtk02AnimName[1]=Atk01_1HS
SpAtk03AnimName[1]=SpAtk03_1HS
CastShortAnimName[1]=SpAtk01_1HS
CastMidAnimName[1]=SpAtk01_1HS
CastLongAnimName[1]=SpAtk01_1HS
CastEndAnimName[1]=AtkWait_1HS
MagicShotAnimName[1]=SpAtk02_1HS
MagicThrowAnimName[1]=SpAtk02_1HS
MagicNoTargetAnimName[1]=SpAtk02_1HS
DeathAnimName[1]=Death
DeathWaitAnimName[1]=Deathwait

WalkAnimName[2]=Run_2HS
RunAnimName[2]=Run_2HS
WaitAnimName[2]=AtkWait_2HS
AtkWaitAnimName[2]=AtkWait_2HS
Atk01AnimName[2]=Atk01_2HS
Atk02AnimName[2]=Atk01_2HS
Atk03AnimName[2]=Atk01_2HS
SpAtk01AnimName[2]=SpAtk01_2HS
SpAtk02AnimName[2]=Atk01_2HS
SpAtk03AnimName[2]=SpAtk03_2HS
SpAtk04AnimName[2]=SpAtk04_2HS
SpAtk05AnimName[2]=SpAtk05_2HS
CastShortAnimName[2]=SpAtk01_2HS
CastMidAnimName[2]=SpAtk01_2HS
CastLongAnimName[2]=SpAtk01_2HS
CastEndAnimName[2]=AtkWait_2HS
MagicShotAnimName[2]=SpAtk02_2HS
MagicThrowAnimName[2]=SpAtk02_2HS
MagicNoTargetAnimName[2]=SpAtk02_2HS
DeathAnimName[2]=Death
DeathWaitAnimName[2]=DeathWait

NpcSocialAnimName[0]=social02
NpcSocialAnimName[1]=Death
NpcSocialAnimName[2]=DeathWait
NpcSocialAnimName[3]=SpAtk05_2HS



Animations ending with _1HS are the ones without wings, whereas Animations ending with _2HS have the wings sticking out.
Animations with [0] index are used when the boss doesn't hold any weapon (I think).
Animations with [1] index are used when the boss holds a weapon with handess =1
Animations with [2] index are used when the boss holds a weapon with handess = 2

The initial weapon that the boss is holding (slot_rhand=[follower_of_frintessa_calibur]) has 8204 ID and has indeed handess = 1
Through AI the boss changes weapon: EquipItem (@sword_of_frintessa). This weapon has 7903 ID and as expected, handess = 2.


How the boss gets bigger through the transision

In AI we can see the following line:
AddUseSkillDesire(myself.sm, @s_frintessa_daemon_morph1, @ST_HEAL, @AMT_MOVE_TO_TARGET, 1000000);

s_frintessa_daemon_morph1 has a skill ID of 5017. In mobskillanimgrp.dat we can find the following:
29046 5017 social02 a,s_frintessa_daemon_morph1\0 a,follower_of_frintessa\0 a,LineageMonster3.follower_of_frintessa\0

Studying this specific animation with l2editor, we can see that it uses the bonescale animnotify.


How the boss utilizes the rush/charge skill

The boss normally has a forward charge skill (ID: 5015, effect: {i_fly_self;straight;pull;400} ) that consists of 3 phases: Initial animation, boss disappearance and lastly landing animation.

In skillgrp.dat we can see that the animation letter that is asigned to skill 5015 is "A". This means the following:

combo_begin name=[A] anim0=[CastShortAnimName] anim1=[CastEndAnimName] anim2=[MagicNoTargetAnimName] loop=1 combo_end
We can observe the 3 stages that were described before. The names of these animations correspond to the animations in lineagemonster3.int, so basically: SpAtk01_2HS, AtkWait_2HS and SpAtk02_2HS.
In order to make the boss disappear in the second part of the animation (AtkWait_2HS), bhidden unrealscipt variable is used in the npc's class. Here's the full class script so you can study it yourselves:

[SPOILER = "[follower_of_frintessa]"]
class follower_of_frintessa extends LineagePawn;

var Emitter Effect0; // disappear effect
var Emitter Effect1; // ground effect
var Emitter Effect2; // body effect
var Emitter Effect3; // first hit effect
var Emitter Effect4; // second hit effect

var float EffectTimer0; // disappear effect timer
var float EffectTimer1; // ground effect timer
var float EffectTimer2; // body effect timer
var float EffectTimer3; // first hit effect timer
var float EffectTimer4; // second hit effect timer

var bool PrepareHidden;
var bool Transformed;

var vector EffectLocation;
var rotator EffectRotation;

var float DashTimer;

simulated event ClearL2Game()
{
if(Effect0 != None)
{
Effect0.NDestroy();
Effect0 = None;
}

if(Effect1 != None)
{
Effect1.NDestroy();
Effect1 = None;
}

if(Effect2 != None)
{
Effect2.NDestroy();
Effect2 = None;
}

if(Effect3 != None)
{
Effect3.NDestroy();
Effect3 = None;
}

if(Effect4 != None)
{
Effect4.NDestroy();
Effect4 = None;
}
}

simulated function Destroyed()
{
Super.Destroyed();
ClearL2Game();
}

simulated event AnimBegin(name SequenceName)
{
local vector loc;


if((SequenceName == 'AtkWait_1HS' || SequenceName == 'AtkWait_2HS') && PrepareHidden)
{
bHidden = True;
PrepareHidden = False;
bReadyToWarp = True;
}


if(SequenceName == 'SpAtk01_1HS' || SequenceName == 'SpAtk01_2HS')
{
bHidden = False;
EffectTimer0 = 0.4;
EffectTimer1 = 0.7;
EffectTimer3 = 1.1;
EffectTimer4 = 1.2;
PrepareHidden = True;
bIgnoreToWarp = True;
DashTimer = 2.0;
}


if(SequenceName == 'SpAtk02_1HS')
{
bHidden = False;
loc = Location - 70.f * Rotator2Vector(Rotation);
Effect0 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ca', Self, '', loc, Rotation);
}

if(SequenceName == 'SpAtk02_2HS')
{
bHidden = False;
loc = Location - 70.f * Rotator2Vector(Rotation);
Effect0 = Spawn(class'LineageEffect.mb_frintessa_charge_b_ca', Self, '', loc, Rotation);
}


if(SequenceName == 'Social02')
{
Transformed = True;
EffectTimer2 = 3.7;
}
}

simulated function Tick(float DeltaTime)
{
local vector loc;
local rotator rot;

if(PrepareHidden)
{
EffectLocation = Location;
if(IsWarpDest)
EffectRotation = Vector2Rotator(WarpDest-Location);
else
EffectRotation = Rotation;
}

if(bReadyToWarp && IsWarpDest)
{
bReadyToWarp = False;
SetLocation(WarpDest);
IsWarpDest = False;
}

if(EffectTimer0 > 0)
{
EffectTimer0 -= DeltaTime;
if(EffectTimer0 <= 0)
{
loc = EffectLocation + 70.f * Rotator2Vector(EffectRotation);
rot = EffectRotation;
if(Transformed)
Effect0 = Spawn(class'Lineageeffect.mb_frintessa_charge_b_ca', Self, '', loc, rot);
else
Effect0 = Spawn(class'Lineageeffect.mb_frintessa_charge_a_ca', Self, '', loc, rot);
}
}

if(EffectTimer1 > 0)
{
EffectTimer1 -= DeltaTime;
if(EffectTimer1 <= 0)
{
loc = EffectLocation + 200.f * Rotator2Vector(EffectRotation);
loc.Z -= CollisionHeight;

rot = EffectRotation;
rot.Yaw += 16384;

if(Transformed)
Effect1 = Spawn(class'LineageEffect.mb_frintessa_charge_b_ra', Self, '', loc, rot);
else
Effect1 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ra', Self, '', loc, rot);
}
}

if(EffectTimer2 > 0)
{
EffectTimer2 -= DeltaTime;
if(EffectTimer2 <= 0)
{
Effect2 = Spawn(class'LineageEffect.mb_frintessa_body_a', Self, '', Location, Rotation);
if(Effect2 != None)
{
AttachToBone(Effect2, 'bip01 spine1');
Effect2.SetRelativeRotation(rot(32768, 16384, 49152));
Effect2.SetDrawScale(0.9);
}
}
}

if(EffectTimer3 > 0)
{
EffectTimer3 -= DeltaTime;
if(EffectTimer3 <= 0)
{
if(Transformed)
{
loc = EffectLocation + 300.f * Rotator2Vector(EffectRotation);
loc.Z -= CollisionHeight;

rot = EffectRotation;
rot.Yaw += 16384;

Effect3 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ta', Self, '', loc, rot);
}
else
{
loc = EffectLocation + 250.f * Rotator2Vector(EffectRotation);
loc.Z -= CollisionHeight;

rot = EffectRotation;
rot.Yaw += 16384;

Effect3 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ta', Self, '', loc, rot);
}
}
}

if(EffectTimer4 > 0)
{
EffectTimer4 -= DeltaTime;
if(EffectTimer4 <= 0)
{
if(Transformed)
{
loc = EffectLocation + 300.f * Rotator2Vector(EffectRotation);
loc.Z -= CollisionHeight;

rot = EffectRotation;
rot.Yaw += 16384;

Effect3 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ta', Self, '', loc, rot);
}
else
{
loc = EffectLocation + 250.f * Rotator2Vector(EffectRotation);
loc.Z -= CollisionHeight;

rot = EffectRotation;
rot.Yaw += 16384;

Effect3 = Spawn(class'LineageEffect.mb_frintessa_charge_a_ta', Self, '', loc, rot);
}
}
}

if(DashTimer > 0)
{
DashTimer -= DeltaTime;
if(DashTimer <= 0)
{
DashTimer = 0;
bHidden = False;
}
}
else
{
bHidden = False;
}
}

defaultproperties
{
WeaponScale=1.25
GroundMaxSpeed=60.00
GroundMinSpeed=60.00
bReadyToWarp=False
ControllerClass=Class'LineageMonster.HerdMonster'
bActorShadows=False
DrawScale=1.25
CollisionRadius=45.00
CollisionHeight=90.70
}


[/ SPOILER]

What about the debris falling after the raid ended?

Interestingly the teleport cube is responsible for this. Here's its script:
class teleport_npc_frin extends LineagePawn;

var actor ViewEmitter;
var string EmitterClass;

var Emitter StoneEffect[21];
var float StoneEffectInitialDelay[21];
var float StoneEffectResetTimer;
var vector StoneEffectLocation[21];

simulated function PostBeginPlay()
{
local class<Emitter> tempClass;

Super.PostBeginPlay();

tempClass = class<Emitter>( DynamicLoadObject( EmitterClass, class'Class') );
if(tempClass != None)
{
ViewEmitter = Spawn(tempClass,Self,'',Location,Rotation);
ViewEmitter.SetPhysics(PHYS_Trailer);
ViewEmitter.bTrailerSameRotation=false;
ViewEmitter.bTrailerPrePivot=true;
ViewEmitter.SetBase( Self,vect(0,0,1));
}
}

simulated event Detach(Actor Other )
{
if(ViewEmitter == Other)
ViewEmitter = None;
Super.Detach(Other);
}


simulated function Destroyed()
{
local int i;

Super.Destroyed();

if(ViewEmitter != None)
{
ViewEmitter.NDestroy();
ViewEmitter = None;
}

for(i = 0; i < 21; ++i)
{
if(StoneEffect != None)
{
StoneEffect.NDestroy();
StoneEffect = None;
}
}
}

// no mesh -> no bone
event GetEffTargetLocation(out vector LocVector)
{
LocVector = Location;
}

simulated function Tick(float DeltaTime)
{
local int i;
local int Index;

if(StoneEffectResetTimer >= 10)
{
for(i = 0; i < 21; ++i)
{
StoneEffectInitialDelay = FRand() * 10;
if(StoneEffect != None)
{
StoneEffect.Kill();
StoneEffect = None;
}
}

while(StoneEffectResetTimer >= 10)
{
StoneEffectResetTimer -= 10;
}
}

for(i = 0; i < 21; ++i)
{
if(StoneEffect == None && StoneEffectInitialDelay != -1 && StoneEffectInitialDelay <= StoneEffectResetTimer)
{
Index = 5 * FRand();

switch(Index)
{
case 0: StoneEffect = Spawn(class'LineageEffect.mb_frintessa_drop_b', Self, '', StoneEffectLocation, rot(0,0,0)); break;
case 1: StoneEffect = Spawn(class'LineageEffect.mb_frintessa_drop_c', Self, '', StoneEffectLocation, rot(0,0,0)); break;
case 2: StoneEffect = Spawn(class'LineageEffect.mb_frintessa_drop_d', Self, '', StoneEffectLocation, rot(0,0,0)); break;
case 3: StoneEffect = Spawn(class'LineageEffect.mb_frintessa_drop_e', Self, '', StoneEffectLocation, rot(0,0,0)); break;
case 4: StoneEffect = Spawn(class'LineageEffect.mb_frintessa_drop_f', Self, '', StoneEffectLocation, rot(0,0,0)); break;
}

StoneEffectInitialDelay = -1;
}
}

StoneEffectResetTimer += DeltaTime;
}

defaultproperties
{
EmitterClass="Lineageeffect.teleport_map_a"
StoneEffectResetTimer=10.00
StoneEffectLocation(0)=(X=174998.00,Y=-88423.00,Z=-5112.00),
StoneEffectLocation(1)=(X=174571.00,Y=-89292.00,Z=-5104.00),
StoneEffectLocation(2)=(X=174573.00,Y=-88995.00,Z=-5112.00),
StoneEffectLocation(3)=(X=174571.00,Y=-88697.00,Z=-5112.00),
StoneEffectLocation(4)=(X=174292.00,Y=-86342.00,Z=-5104.00),
StoneEffectLocation(5)=(X=173457.00,Y=-87617.00,Z=-5112.00),
StoneEffectLocation(6)=(X=173830.00,Y=-87810.00,Z=-5112.00),
StoneEffectLocation(7)=(X=173471.00,Y=-88409.00,Z=-5112.00),
StoneEffectLocation(8)=(X=173872.00,Y=-88268.00,Z=-5112.00),
StoneEffectLocation(9)=(X=173893.00,Y=-88696.00,Z=-5112.00),
StoneEffectLocation(10)=(X=179893.00,Y=-88990.00,Z=-5112.00),
StoneEffectLocation(11)=(X=173897.00,Y=-89299.00,Z=-5104.00),
StoneEffectLocation(12)=(X=174279.00,Y=-89791.00,Z=-5016.00),
StoneEffectLocation(13)=(X=174589.00,Y=-88269.00,Z=-5112.00),
StoneEffectLocation(14)=(X=174637.00,Y=-87812.00,Z=-5112.00),
StoneEffectLocation(15)=(X=175026.00,Y=-87604.00,Z=-5112.00),
StoneEffectLocation(16)=(X=174914.00,Y=-86685.00,Z=-5104.00),
StoneEffectLocation(17)=(X=172843.00,Y=-87111.00,Z=-5104.00),
StoneEffectLocation(18)=(X=172797.00,Y=-88965.00,Z=-5104.00),
StoneEffectLocation(19)=(X=175661.00,Y=-88584.00,Z=-5104.00),
StoneEffectLocation(20)=(X=175610.00,Y=-86967.00,Z=-5104.00),
GroundSpeed=120.00
ControllerClass=Class'HerdNpc'
DrawType=15
CollisionRadius=40.00
CollisionHeight=80.00
}
 

Please somebody fix my spoiler of the first post :)
 
Назад
Сверху Снизу