Aller au contenu

Photo

Funn w/ DRAGONS


  • Veuillez vous connecter pour répondre
76 réponses à ce sujet

#51
kevL

kevL
  • Members
  • 4 052 messages
- some quick tests on Khelgar (ethereal) vs. Dragon:

- the dragon won't attack nor attempt knockdown. ( good )
- the dragon perceives Khelgar and does not switch to a non-ethereal opponent ( at present )
- TailSwipe, which uses EffectKnockdown( ) definitely hits ethereal - i was hoping that effect_type_knockdown would internally prevent this ...

- therefore I'm adding code that checks for effect_type_sanctuary, where needed, to stop knockdown effects vs. ethereal opponents ( and how does half damage from Breath weapon sound ?)


ps. as noted on the wikia page, it does indeed seem to be the case, that if Ethereal/Sanctuary is cast outside the dragon's perception there is no effect - dragon attacks as against a normal, non-ethereal opponent.

( oh yeah, and good luck using Sanctuary vs an NwN2 dragon ... )


edit, Pls note all these tests were against a True Seeing opponent .. i have no idea what happens vs non-True Seeing

the 'critical' tail-slap ( vs. ethereal .. )

Image IPB


the once proud party .. soon to be hominid steaks (relax, they have Energy Immunity, Fire)

Image IPB

Modifié par kevL, 04 novembre 2011 - 11:57 .


#52
kevL

kevL
  • Members
  • 4 052 messages
the more I look at working around this, the more i come to Pain's conclusion : it's pretty much broken

i Mean, sure i can test for effect_sanctuary as the noSave version applied by 9th level Etherealness, but what about Sanctuary-casters - who apparently have the exact same effect applied on their character - what, do i have the NPC make another WillSave every time another check is done???


i'm inclined to give the benefit of the doubt on this one ... ( unless i guess the Sanctuary spell is rewritten with a variable analogous to CSL_KNOCKDOWN applied - and perhaps this could be used to enforce effect_sanctuary even when applied out-of-perception range )



hm, less talk more code .........

#53
kamal_

kamal_
  • Members
  • 5 238 messages
don't get hung up over sanctuary.

#54
kevL

kevL
  • Members
  • 4 052 messages
right.

#55
kevL

kevL
  • Members
  • 4 052 messages
Okay.

- got around the effect_sanctuary issue (Sanctuary casters should get a bit of a break, which really should go only to Etherealness casts); a target w/ effect_sanctuary won't be affected by Buffet or Swipe.

- been on break learning to encode video: Fighting Tholapsyx (world's crappiest video w/ a cool battle)*

- here's what happened - when I switched back to working the Tholapsyx OC scripts, playtesting brought out any number of anomalies (as i call them), so most are fixed and some peculiarities remain, mainly just standardizing ranges for Tholly and reviewing how extra non-dragon levels impact stuff. These ought eventually be incorp'd into the far more complicated general scripts.

- Tholly and her scripts are getting close to releasable, and can be used to juice up unique custom Drags, by any moderate+ scripter who's inclined (the latter scripts should get better spell-casting AI, as well as be applicable to several dragon races/ages & model-scaling also perhaps).



* snicker, i Used the online editor to increase saturation and whatever definition was there is gone now - but the colors look good !!

#56
M. Rieder

M. Rieder
  • Members
  • 2 530 messages
How adaptable are these scripts? Is it a case where we can just plug scripts into events on a dragon, or will we need to modify code?

#57
kevL

kevL
  • Members
  • 4 052 messages
hi Matt,

the longer project is to have three generic scripts
1. OnSpawn
2. OnUserDefined
3. the AI itself (set via OnSpawn)

uhm 4. a few includes ...
5, 6, 7, 8, etc. breath attacks, tail swipe, wing buffet, fear aura ( <- should adapt & rely on DannJ's work, hope that he's okay with this )

so really only 2 events to set up. The tricky issue may be for setting up a dragon's spell-list. Due to the problems with saving or re-saving a creature blueprint typically losing the number of casts it retains, of Special Abilities. That list wants to keep defaulting back to 1 cast per.

So at present I'm working a .2da that charts about 70 spells vs. HitDice, to give a maximum number of casts. Then a designer can simply grant a dragon a selection of those spells and click up the numbers on the Special Abilities tab to say 3 or 5 and the .2da will take care of it from there. Overall it's a non-major issue that's been taking far too much time ( unfortunately the bCheat parameter on ActionCastSpell wreaks havoc with SaveDCs, and overall i'm just not happy but there it is )

Fortunately the special combat abilities are infinite and regulated via heartbeat counters (these SaveDCs do not rely on CasterLevel).



What I'm looking at doing first, though, is getting Tholapsyx' scripts onto the Vault so fellas like Pain and other pw-Admins can grab them and have a look & go "oh yeah ... tinker tinker" and they have a real Dragon.

Apart from conforming Tholly's scripts with the general scripts, I'm figuring SaveDCs should use full dragin levels + half other class levels; and I'll try to scale ranges of breaths, wingbuffets & tailswipes according to model scale. Fortunately again, Tholly is only 1 model at scale 1 ...

so yeh, apart from spells issues it's just chuck a couple of script names into a couple of event slots and configure your dragon blueprint(s) however ya like, with the caveat about spells.


note, Tholly casts her spells directly from the roundend AI script; a salty scripter can easily pick them out and change them up .. gtg

#58
kevL

kevL
  • Members
  • 4 052 messages
Tholapsyx in the OC

http://nwvault.ign.c...s.Detail&id=392


Files

1) ai_reddragon_spawnscript - called from OnSpawn (.nss/.ncs)
2) ai_dragon_userdef - the UserDefined slot (.nss/.ncs)
3) ai_reddragon_roundend - the AI (.nss/.ncs)

Additional custom files:
4) klai_inc_dragon - include file (.nss)
5) kl_dragon_fearaura - Special Effect VFX for dragon's Fear Aura (.sef)

And these are default NwN2 dragon files that have been re-worked:
6) nw_s1_auradrag - activates dragon's Aura of Fear (.nss/.ncs)
7) nw_s1_dragfeara - OnEnter for the Aura of Fear (.nss/.ncs)
8) nw_s1_dragfire - dragon Fire Breath (.nss/.ncs)
9) nw_s1_dragwbuffet - dragon Wing Buffet (.nss/.ncs)
10) nw_s1_dragtslap - dragon Tail Sweep (.nss/.ncs)

Blueprints:
11) 3031_tholapsyx - Tholapsyx creature (.utc)
12) 3032_tholap_skin - Tholapsyx hide (.uti)

Plot files for NwN2 OC, Mt. Galardrym:
13) 3031_ds_tholapsyx - Tholapsyx' OnDeath script (.nss/.ncs)
14) 3032_oncliententer - OnClientEnter of Tholapsyx' Canyon (.nss/.ncs)
15) 3033a_fireking - conversation blocks for Fire Giants' Canyon (.nss/.ncs)

Plot files, custom:
16) kl_ondeath_groups - begins conversations after Tholapsyx and Fire Giants fight (.nss/.ncs)


One basically working Red Dragon,
though i'M sure some of the SaveDC's and range-algorithms would Benefit w/ tweaking.

Suggestion: spawn 'er into an empty zone and have at it!! (note, Tholly is scripthidden, so you want to uncheck that before testing)

#59
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
Working on some initial revisions to what you have, mainly on the actual adjustments to breath weapons.

Focusing on checks for the sanctuary effect. This is something which is useful in other areas of the AI as well. Also integrated the dragon age code you've got, with a var which can be used if a character polymorphs into a dragon to set the correct age to caster level.

I don't like a loop deep in the AI, it can get mess. Get effect type of sanctuary is often going to result in looping thru ALL the effects on every target, if you are dealing with a lot of buffed opponents this can get a bit much. While it looks like a single function call, GetHasEffectType(oTarget, EFFECT_TYPE_SANCTUARY) is actually calling a loop defined in ginc_effect.nss and not an engine function. My assumption here is that ethereal / sanctuary is only going to be used rarely by players, and quite often there will be quite a few effects on creatures which might result in occasional timeouts. It does add some overhead from a delay command, but there should only ever be a few of those running.

I am adding a tracking variable whenever effectethereal or effectsanctuary is applied via script using a variable named "CSL_ETHEREAL" or CSL_SANCTUARY". I am running a delay of the duration to remove this after the duration ends. Because the player can rest, or removed by dispel magic, or otherwise not have the effect when this variable is set, i am only using this variable to prove that there is no such effect on the target. If this variable is set i am going to loop thru the effects to make sure it's actually applied.

Now this is a bit of work, but then usually it's from the spell sanctuary, ethereal, or ethereal jaunt and in those cases it will check for the spellid.

The logic is such that most of the time it will just check for the spell itself, and then check for the variable, and only be about 3 or so steps, but with some safety. If the tracking var is not set the spellids should make it usually work, so it should work correctly if a custom spells.2da is not used.

[code=auto:0]
// in the _cslcore_math include
void CSLDecrementLocalInt_Void(object oObject, string sField, int iVal = 1, int bZeroLimit = FALSE)
{
int nNew = GetLocalInt(oObject, sField) - iVal;
if ( bZeroLimit && nNew < 0 )
{
nNew = 0;
}
SetLocalInt(oObject, sField, nNew);
}

int CSLIncrementLocalInt_Timed(object oObject, string sFld, float fDelay, int iVal = 1)
{
int nNew = GetLocalInt(oObject, sFld) + iVal;
SetLocalInt(oObject, sFld, nNew);
DelayCommand(fDelay, CSLDecrementLocalInt_Void(oObject, sFld, iVal, TRUE ));
return nNew;
}

// going into my _cslcore_info include
int CSLGetHasEtherealEffect( object oTarget )
{
if ( GetHasSpellEffect(SPELL_ETHEREAL_JAUNT, oTarget) )
{
return TRUE;
}

if ( GetHasSpellEffect(SPELL_ETHEREALNESS, oTarget) )
{
return TRUE;
}

if( GetLocalInt(oTarget, "CSL_ETHEREAL") )
{
effect eEffect = GetFirstEffect( oTarget );
while (GetIsEffectValid(eEffect))
{
if ( GetEffectType(eEffect) == EFFECT_TYPE_SANCTUARY )
{
return TRUE;
}
eEffect = GetNextEffect( oTarget );
}
}
return FALSE;
}

int CSLGetHasSanctuaryEffect( object oTarget )
{
if ( GetHasSpellEffect(SPELL_SANCTUARY, oTarget) )
{
return TRUE;
}

if( GetLocalInt(oTarget, "CSL_SANCTUARY") )
{
effect eEffect = GetFirstEffect( oTarget );
while (GetIsEffectValid(eEffect))
{
if ( GetEffectType(eEffect) == EFFECT_TYPE_ETHEREAL )
{
return TRUE;
}
eEffect = GetNextEffect( oTarget );
}
}
return FALSE;
}

// general purpose damage reduction function i use for adjusting damage to the target based on element type
// inside of _HKSpell
int HkApplyTargetModifiers( int nDamageTotal, int iDamageType, object oTarget, int iHitEffect = VFX_IMP_HEALING_M, float fDelay = 0.0f, object oCaster = OBJECT_SELF )
{
if (
( iDamageType == DAMAGE_TYPE_COLD ) && GetHasFeat(FEAT_ENERGY_ABSORB_COLD, oTarget) ||
( iDamageType == DAMAGE_TYPE_FIRE ) && GetHasFeat(FEAT_ENERGY_ABSORB_FIRE, oTarget) ||
( iDamageType == DAMAGE_TYPE_ACID ) && GetHasFeat(FEAT_ENERGY_ABSORB_ACID, oTarget) ||
( iDamageType == DAMAGE_TYPE_ACID ) && GetHasFeat(FEAT_ENERGY_ABSORB_ACID, oTarget) ||
( iDamageType == DAMAGE_TYPE_SONIC ) && GetHasFeat(FEAT_ENERGY_ABSORB_SONIC, oTarget) ||
( iDamageType == DAMAGE_TYPE_ELECTRICAL ) && GetHasFeat(FEAT_ENERGY_ABSORB_ELECTRICAL, oTarget) ||
( iDamageType == DAMAGE_TYPE_NEGATIVE ) && GetHasFeat(FEAT_ENERGY_ABSORB_NEGATIVE, oTarget) ||
( iDamageType == DAMAGE_TYPE_POSITIVE ) && GetHasFeat(FEAT_ENERGY_ABSORB_POSITIVE, oTarget) ||
( iDamageType == DAMAGE_TYPE_MAGICAL ) && GetHasFeat(FEAT_ENERGY_ABSORB_MAGIC, oTarget) ||
( iDamageType == DAMAGE_TYPE_DIVINE ) && GetHasFeat(FEAT_ENERGY_ABSORB_DIVINE, oTarget)
)
{
effect eHeal = EffectHeal( CSLGetMax(nDamageTotal/2, 1) );
CSLRemoveEffectByType(oTarget, EFFECT_TYPE_WOUNDING);
//Apply heal effect and VFX impact
//HkApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);
//HkApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);


DelayCommand(fDelay, HkApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget));
DelayCommand(fDelay, HkApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect( iHitEffect ), oTarget));


return 0;
}


// half damage if Target has Effect_Type_Sanctuary
if ( CSLGetHasEtherealEffect( oTarget ) )
{
return 0;
}

if ( CSLGetHasSanctuaryEffect(oTarget) )
{
nDamageTotal = nDamageTotal / 2;
}

return nDamageTotal;
}


// function to get the dragons age
// _SCInclude_Monster

int SCDragonGetAge( object oDragon = OBJECT_SELF ) // what if it's a druid or wizard shapechanger
{
int iHitDice = GetHitDice(oDragon); // so we can figure out non dragon levels
int iDragonLevel = GetLevelByclass(class_TYPE_DRAGON, oDragon);

if ( iHitDice > iDragonLevel ) // this is not a pure dragon, lets figure out what it is
{
// lets look for a variable setting the dragons hit dice
// this supports toolset overrides and also scripting changes
// ( for when a druid shifts into dragon form set this on polymorphing to the wildshape or caster level as appropriate)
int iTempDragonLevel = GetLocalInt( oDragon, "CSL_DRAGON_HD");
if ( iTempDragonLevel > 0 )
{
iDragonLevel = iTempDragonLevel;
}
else
{
iDragonLevel += GetLevelByclass(class_TYPE_SORCERER, oDragon); // full levels since draconic heritage is a prerequisite

iDragonLevel += GetLevelByclass(class_DRAGON_SHAMAN, oDragon);
iDragonLevel += GetLevelByclass(class_TYPE_DRAGON_DISCIPLE, oDragon);
iDragonLevel += GetLevelByclass(class_DRAGON_WARRIOR, oDragon);

iDragonLevel += (iHitDice-iDragonLevel)/2; // half of all other levels


SetLocalInt( oDragon, "CSL_DRAGON_HD", iDragonLevel );
}
}


iDragonLevel -= CSLGetNegativeLevels( oDragon );

if ( iDragonLevel < 1 )
{
return 1;
}

if ( iDragonLevel > iHitDice )
{
return iHitDice;
}

return iDragonLevel;
}


// general purpose breath weapon function, this way i only have code in one spot and it affects all dragons
void SCDragonBreath( int iDamageType, int VFXShape=SHAPE_SPELLCONE, float fRange=0.0, int iVFXImpact=VFX_NONE, int iVFXBreath=VFX_NONE, string sVFXBreath="", object oDragon = OBJECT_SELF )
{
int iAge = SCDragonGetAge(oDragon);
int iDice = iAge;
int iDC = 13 + iAge/2 + GetAbilityModifier( ABILITY_CONSTITUTION, oDragon);
int iDamage;
float fDelay;
if (fRange==0.0)
{
fRange=10.0 + iAge/2.0;
}
int iSaveType = CSLGetSaveTypeByDamageType(iDamageType);
effect eImpact = EffectVisualEffect(iVFXImpact);
effect eBreath;
SCPlayDragonBattleCry();
PlayCustomAnimation(oDragon, "Una_breathattack01", 0, 0.7f);
if (sVFXBreath!="") // NWN2 EFFECT
{
eBreath = EffectNWN2SpecialEffectFile(sVFXBreath);
DelayCommand(0.5f, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBreath, oDragon, 3.0f));
}
else if (iVFXBreath!=VFX_NONE) // NWN1 BEAM
{
eBreath = EffectVisualEffect(iVFXBreath);
object oEndTarget = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_ipoint ", CSLGetAheadLocation(oDragon, fRange));
DelayCommand(0.5f, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBreath, oEndTarget, 4.0f));
DelayCommand(1.0f, DestroyObject(oEndTarget));
}
location lLocation = GetLocation( HkGetSpellTarget() );

object oTarget = GetFirstObjectInShape(VFXShape, fRange, lLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR, GetPosition(oDragon));
while(GetIsObjectValid(oTarget))
{
if ( oTarget != oDragon && CSLSpellsIsTarget( oTarget, SCSPELL_TARGET_STANDARDHOSTILE, oDragon))
{
SignalEvent(oTarget, EventSpellCastAt(oDragon, GetSpellId()));

fDelay = GetDistanceBetween(oDragon, oTarget)/20.0f;

iDamage = HkGetSaveAdjustedDamage( SAVING_THROW_REFLEX, SAVING_THROW_METHOD_FORHALFDAMAGE, d6(iDice), oTarget, iDC, iSaveType, oDragon );

iDamage = HkApplyTargetModifiers( iDamage, iDamageType, oTarget, VFX_IMP_HEALING_M, fDelay, oDragon );
//if (HkSavingThrow(SAVING_THROW_REFLEX, oTarget, iDC, iSaveType))
//{
// iDamage = iDamage/2;
// if (GetHasFeat(FEAT_EVASION, oTarget) || GetHasFeat(FEAT_IMPROVED_EVASION, oTarget)) iDamage = 0;
//}
//else if (GetHasFeat(FEAT_IMPROVED_EVASION, oTarget))
//{
// iDamage = iDamage/2;
//}
if (iDamage)
{

eBreath = EffectDamage(iDamage, iDamageType);
DelayCommand(fDelay, HkApplyEffectToObject(DURATION_TYPE_INSTANT, eBreath, oTarget));
DelayCommand(fDelay, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImpact, oTarget, 3.0 ));
DelayCommand(fDelay+0.5, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImpact, oTarget, 3.0 ));
DelayCommand(fDelay+1.0, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImpact, oTarget, 3.0 ));
}
}
oTarget = GetNextObjectInShape(VFXShape, fRange, lLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_DOOR);
}
}


// and implemented in FT_drgbrthfire and the other breath weapon ability scripts
#include "_HkSpell"
#include "_SCInclude_Monster"

////#include "_inc_helper_functions"
//#include "_SCUtility"

void main()
{
int iAttributes = SCMETA_ATTRIBUTES_SUPERNATURAL | SCMETA_ATTRIBUTES_SOMANTICCOMP | SCMETA_ATTRIBUTES_HOSTILE | SCMETA_ATTRIBUTES_CANTCASTINTOWN;
SCDragonBreath(DAMAGE_TYPE_FIRE, SHAPE_SPELLCONE, 0.0, VFX_IMP_FLAME_M, VFX_NONE, "fx_red_dragon_breath.sef");
}

#60
kevL

kevL
  • Members
  • 4 052 messages

painofdungeoneternal wrote...

Working on some initial revisions to what you have, mainly on the actual adjustments to breath weapons.

Focusing on checks for the sanctuary effect. This is something which is useful in other areas of the AI as well.

yes ...


Also integrated the dragon age code you've got, with a var which can be used if a character polymorphs into a dragon to set the correct age to caster level.

admittedly, didn't concern myself at all w/ polymorphs .. but it should be done. And, good idea incorporating classes like Sorcerer (and Wizard, etc.) as Full HD into Age/DC


I don't like a loop deep in the AI, it can get mess. Get effect type of sanctuary is often going to result in looping thru ALL the effects on every target, if you are dealing with a lot of buffed opponents this can get a bit much. While it looks like a single function call, GetHasEffectType(oTarget, EFFECT_TYPE_SANCTUARY) is actually calling a loop defined in ginc_effect.nss and not an engine function.

am aware of that and yep it struck me that loop is going pretty deep. As you've pointed out, it's really a job for *SuperCSL* - brilliant solution here:


My assumption here is that ethereal / sanctuary is only going to be used rarely by players, and quite often there will be quite a few effects on creatures which might result in occasional timeouts. It does add some overhead from a delay command, but there should only ever be a few of those running.

I am adding a tracking variable whenever effectethereal or effectsanctuary is applied via script using a variable named "CSL_ETHEREAL" or CSL_SANCTUARY". I am running a delay of the duration to remove this after the duration ends. Because the player can rest, or removed by dispel magic, or otherwise not have the effect when this variable is set, i am only using this variable to prove that there is no such effect on the target. If this variable is set i am going to loop thru the effects to make sure it's actually applied.

( my emphasis ) Thatis, if I understand it okay, good luck sir.


Now this is a bit of work, but then usually it's from the spell sanctuary, ethereal, or ethereal jaunt and in those cases it will check for the spellid.

hm, guess should do that for v1.1 (not comfortable w/ SpellID's but they're pretty straightforward eh - as long as they're not broke)


The logic is such that most of the time it will just check for the spell itself, and then check for the variable, and only be about 3 or so steps, but with some safety. If the tracking var is not set the spellids should make it usually work, so it should work correctly if a custom spells.2da is not used.


(i'm all in favor of standard .2da's fer sure)


re. code-stuffs above: Great, do what ya gotta do, PoDE!

#61
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
Wing buffet revisions, i basically repurposed my gust of wind and grapple code to work, so a dragon wing buffet will open doors, extinguish flames, make it harder to aim ranged weapons, and remove gaseous AOE spells. Not to mention really throwing opponents farther away, especially anyone foolish enough to play a pixie. Put the ethereal changes into gust of wind as well so should affect things globally.


implementation

#include "_HkSpell"
#include "_SCInclude_Monster"

void main()
{
	int iAttributes = SCMETA_ATTRIBUTES_EXTRAORDINARY | SCMETA_ATTRIBUTES_HOSTILE | SCMETA_ATTRIBUTES_TURNABLE | SCMETA_ATTRIBUTES_CANTCASTINTOWN;
	//Declare major variables
	
	object oDragon = OBJECT_SELF;
	
	int iAge = SCDragonGetAge(oDragon);
	int iDC  = 13 + iAge/2 + GetAbilityModifier( ABILITY_STRENGTH, oDragon);
	float fRadius	= (GetScale(oDragon, SCALE_Y) * 20) + 4.0f; // RADIUS_SIZE_GINORMOUS
	int iDistanceMod = 0;
	int iTargetSize;
	int iObjectType;
	float fDelay;
	float fRandomDuration;
	object oTarget;
	effect eVis, eBreath;
	//Use the HD of the creature to determine save DC
	
	
	location lStartLocation = GetLocation(oDragon);
	// HkGetSpellTargetLocation()

	effect eWingBuffet = EffectNWN2SpecialEffectFile("fx_reddr_wbuffet.sef");
	effect eShake = EffectVisualEffect(VFX_FNF_SCREEN_SHAKE);
	
	SCPlayDragonBattleCry();
	PlayCustomAnimation(oDragon, "*specialattack01", FALSE, 1.3f);
	DelayCommand(0.5f, HkApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWingBuffet, OBJECT_SELF, 3.3f));
	DelayCommand(1.0f, HkApplyEffectAtLocation(DURATION_TYPE_INSTANT, eShake, lStartLocation));
	//Get first target in spell area
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lStartLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_AREA_OF_EFFECT, GetPositionFromLocation(lStartLocation) );
	//oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GINORMOUS, lSelf, TRUE);
	while(GetIsObjectValid(oTarget))
	{
		iDistanceMod = FloatToInt(GetDistanceBetween(oTarget, oDragon))/2;
		
		iObjectType = GetObjectType(oTarget);
		
		if ( oTarget == oDragon || GetIsDead(oTarget, TRUE) || CSLGetHasEtherealEffect( oTarget ) || CSLGetHasSanctuaryEffect(oTarget) )
		{
			// they never felt it...
			// SignalEvent(oTarget, EventSpellCastAt(oDragon, SPELLABILITY_DRAGON_WING_BUFFET));
		}
		else if ( CSLSpellsIsTarget(oTarget, SCSPELL_TARGET_STANDARDHOSTILE, oDragon) )
		{
			// not a target for whatever reason
		}
		else if ( iObjectType == OBJECT_TYPE_AREA_OF_EFFECT || iObjectType == OBJECT_TYPE_DOOR )
		{
			SignalEvent(oTarget, EventSpellCastAt(oDragon, SPELLABILITY_DRAGON_WING_BUFFET));
			CSLEnviroWindGustEffect( lStartLocation, oTarget, "Wing Buffet" );
		}
		else if (  HkSavingThrow(SAVING_THROW_REFLEX, oTarget, iDC-CSLGetSizeModifierGrapple(oTarget)-iDistanceMod, SAVING_THROW_TYPE_NONE)) // FortitudeSave(oTarget,  ) )
		{
			// they saved
			SignalEvent(oTarget, EventSpellCastAt(oDragon, SPELLABILITY_DRAGON_WING_BUFFET));
			//SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE ));
			CSLTorchExtinguishObject( oTarget );
			CSLRemoveEffectSpellIdSingle( SC_REMOVE_ALLCREATORS, OBJECT_SELF, oTarget, SPELL_GLITTERDUST, SPELL_DECK_BUTTERFLYSPRAY);
		}
		else
		{
			SignalEvent(oTarget, EventSpellCastAt(oDragon, SPELLABILITY_DRAGON_WING_BUFFET));
			CSLEnviroWindGustEffect( lStartLocation, oTarget, "Wing Buffet" );
			//SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), TRUE ));
		}
			
		//Get next target in spell area
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lStartLocation, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_AREA_OF_EFFECT, GetPositionFromLocation( lStartLocation ) );
	}
}





cslcore_info
/**  
* @author
* @param 
* @see 
* @return 
* @replaces HasSizeIncreasingSpellEffect
*/
int CSLGetHasSizeIncreaseEffect(object oCreature)
{
	if (  GetHasSpellEffect( SPELL_ENTROPIC_HUSK,oCreature) || GetHasSpellEffect(SPELL_ENLARGE_PERSON,oCreature) || GetHasSpellEffect( SPELLABILITY_GRAYENLARGE,oCreature) || GetHasSpellEffect( SPELL_RIGHTEOUS_MIGHT,oCreature) )
	{
		return TRUE;
	}
	return FALSE;
}

/**  
* @author
* @param 
* @see 
* @return 
*/
int CSLGetHasSizeDecreaseEffect(object oCreature)
{
	if ( GetHasSpellEffect( SPELL_REDUCE_PERSON,oCreature) || GetHasSpellEffect( SPELL_REDUCE_PERSON_GREATER,oCreature) || GetHasSpellEffect( SPELL_REDUCE_ANIMAL,oCreature) || GetHasSpellEffect( SPELL_REDUCE_PERSON_MASS,oCreature) )
	{
		return TRUE;
	}
	return FALSE;
}

/**  
* @author
* @param 
* @see 
* @return 
*/
int CSLGetSizeCategory(object oCreature)
{
	
	int iCreatureSize = GetCreatureSize(oCreature); // get the real creature size...
	
	int nAppearance = GetAppearanceType(oCreature); // handles size exceptions - note that flying creatures cannot use actual height to determine this
	switch(nAppearance)
	{
		case APPEAR_TYPE_BAT:
			iCreatureSize = CREATURE_SIZE_DIMINUTIVE;
			break;
		case APPEAR_TYPE_PIXIE:
			iCreatureSize = CREATURE_SIZE_SMALL;
			break;
		case APPEAR_TYPE_SYLPH:
			iCreatureSize = CREATURE_SIZE_SMALL;
			break;
		case APPEAR_TYPE_HOMUNCULUS:
			iCreatureSize = CREATURE_SIZE_TINY;
			break;
		case APPEAR_TYPE_IMP:
			iCreatureSize = CREATURE_SIZE_TINY;
			break;
		case APPEAR_TYPE_MEPHIT_FIRE:
		case APPEAR_TYPE_MEPHIT_ICE:
			iCreatureSize = CREATURE_SIZE_SMALL;
			break;
		case APPEAR_TYPE_DEMILICH_SMALL:
		case APPEAR_TYPE_DEMILICH:
			iCreatureSize =  CREATURE_SIZE_DIMINUTIVE;
			break;
	}
	
	// figure out height from the creatures actual height...
	
	/*
	if ( iCreatureSize == CREATURE_SIZE_INVALID )
	{
		float fHeight = CSLGetCreatureHeight( oCreature );
		if ( fHeight == 0.0f )
		{
			return iCreatureSize;
		}
		else if ( fHeight <= 0.1524f ) { iCreatureSize = CREATURE_SIZE_FINE; } // CREATURE_SIZE_FINE < .5 feet  0.1524f
		else if ( fHeight <= 0.3048f ) { iCreatureSize = CREATURE_SIZE_DIMINUTIVE; } // CREATURE_SIZE_DIMINUTIVE < 1 foot  0.3048f
		else if ( fHeight <= 0.6096f ) { iCreatureSize = CREATURE_SIZE_TINY; } // CREATURE_SIZE_TINY < 2 feet 0.6096f
		else if ( fHeight <= 1.2192f ) { iCreatureSize = CREATURE_SIZE_SMALL; } // CREATURE_SIZE_SMALL < 4 feet 1.2192f
		else if ( fHeight <= 2.4384f ) { iCreatureSize = CREATURE_SIZE_MEDIUM; } // CREATURE_SIZE_MEDIUM < 8 feet  2.4384f
		else if ( fHeight <= 4.8768f ) { iCreatureSize = CREATURE_SIZE_LARGE; } // CREATURE_SIZE_LARGE < 16 feet 4.8768f
		else if ( fHeight <= 9.7536f ) { iCreatureSize = CREATURE_SIZE_HUGE; } // CREATURE_SIZE_HUGE < 32 feet 9.7536f
		else if ( fHeight <= 19.5072f ) { iCreatureSize = CREATURE_SIZE_GARGANTUAN; } // CREATURE_SIZE_GARGANTUAN < 64 feet 19.5072f
		else if ( fHeight > 19.5072f ) { iCreatureSize = CREATURE_SIZE_COLOSSAL; } // CREATURE_SIZE_COLOSSAL > 64 feet 19.5072f
		return iCreatureSize;
	}
	*/
	
	// Per SRD, reduce and enlarge adjusts creatures up and down by one category
	if (  CSLGetHasSizeIncreaseEffect(oCreature)  )
	{
		switch(iCreatureSize)
		{
			case CREATURE_SIZE_FINE:
				iCreatureSize = CREATURE_SIZE_DIMINUTIVE;
				break;
			case CREATURE_SIZE_DIMINUTIVE:
				iCreatureSize = CREATURE_SIZE_TINY;
				break;
			case CREATURE_SIZE_TINY:
				iCreatureSize = CREATURE_SIZE_SMALL;
				break;
			case CREATURE_SIZE_SMALL:
				iCreatureSize = CREATURE_SIZE_MEDIUM;
				break;
			case CREATURE_SIZE_MEDIUM:
				iCreatureSize = CREATURE_SIZE_LARGE;
				break;
			case CREATURE_SIZE_LARGE:
				iCreatureSize = CREATURE_SIZE_HUGE;
				break;
			case CREATURE_SIZE_HUGE:
				iCreatureSize = CREATURE_SIZE_GARGANTUAN;
				break;
			case CREATURE_SIZE_GARGANTUAN:
				iCreatureSize = CREATURE_SIZE_COLOSSAL;
				break;
		}
	}
	else if ( CSLGetHasSizeDecreaseEffect(oCreature) )
	{
		switch(iCreatureSize)
		{
			case CREATURE_SIZE_DIMINUTIVE:
				iCreatureSize = CREATURE_SIZE_FINE;
				break;
			case CREATURE_SIZE_TINY:
				iCreatureSize = CREATURE_SIZE_DIMINUTIVE;
				break;
			case CREATURE_SIZE_SMALL:
				iCreatureSize = CREATURE_SIZE_TINY;
				break;
			case CREATURE_SIZE_MEDIUM:
				iCreatureSize = CREATURE_SIZE_SMALL;
				break;
			case CREATURE_SIZE_LARGE:
				iCreatureSize = CREATURE_SIZE_MEDIUM;
				break;
			case CREATURE_SIZE_HUGE:
				iCreatureSize = CREATURE_SIZE_LARGE;
				break;
			case CREATURE_SIZE_GARGANTUAN:
				iCreatureSize = CREATURE_SIZE_HUGE;
				break;
			case CREATURE_SIZE_COLOSSAL:
				iCreatureSize = CREATURE_SIZE_GARGANTUAN;
				break;
		}
	}
	
	return iCreatureSize;
}

/**  
* @author
* @param 
* @see 
* @return 
*/
int CSLGetSizeModifierAttack(object oCreature)
{
	int iCreatureSize = CSLGetSizeCategory(oCreature);
	int iSizeMod = 0;
	if (GetRacialType(oCreature) == RACIAL_TYPE_DRAGON || GetRacialType(oCreature) == RACIAL_TYPE_CONSTRUCT) 
	{
		iSizeMod += 4;
	}
	switch(iCreatureSize)
	{
		case CREATURE_SIZE_FINE:
			return 8-iSizeMod;
			break;
		case CREATURE_SIZE_DIMINUTIVE:
			return 4-iSizeMod;
			break;
		case CREATURE_SIZE_TINY:
			return 2-iSizeMod;
			break;
		case CREATURE_SIZE_SMALL:
			return 1-iSizeMod;
			break;
		case CREATURE_SIZE_MEDIUM:
			return 0-iSizeMod;
			break;
		case CREATURE_SIZE_LARGE:
			return -1-iSizeMod;
			break;
		case CREATURE_SIZE_HUGE:
			return -2-iSizeMod;
			break;
		case CREATURE_SIZE_GARGANTUAN:
			return -4-iSizeMod;
			break;
		case CREATURE_SIZE_COLOSSAL:
			return -8-iSizeMod;
			break;
	}
	return 0;
}


CSLcore_environment
void CSLEnviroWindGustEffect( location lStartLocation, object oTarget, string sName = "Wind" )
{
	if ( GetIsObjectValid(oTarget) )
	{
			effect eDamage;
			float fDelay = GetDistanceBetweenLocations(lStartLocation, GetLocation(oTarget))/20;
			effect eVis = EffectVisualEffect(VFX_HIT_SPELL_SONIC);
			
			
			if (GetObjectType(oTarget) == OBJECT_TYPE_AREA_OF_EFFECT)
			{
				if ( !CSLGetPreferenceSwitch("GustsLimitedToCloudSpells",FALSE) || CSLGetIsCloud( GetAreaOfEffectSpellId( oTarget ) ) )
				{
					DestroyObject(oTarget);
				}
			}
			else if (GetObjectType(oTarget) == OBJECT_TYPE_DOOR)
			{
				if ( GetLocked(oTarget) == FALSE  && GetLocalString(oTarget, "SC_ARCANELOCK_CASTERTAG") == "" )
				{
					if (GetIsOpen(oTarget) == FALSE)
					{
						AssignCommand(oTarget, ActionOpenDoor(oTarget));
					}
					else
					{
						AssignCommand(oTarget, ActionCloseDoor(oTarget));
					}
				}
			}
			else
			{
				fDelay = GetDistanceBetweenLocations(lStartLocation, GetLocation(oTarget))/20;
				
				int iCreatureSize = GetCreatureSize(oTarget);
				int bFlying = CSLGetIsFlying(oTarget);
				int bKnockDown = FALSE;
				int iThrownFeet = 0;
				int iThrownDamage = 0;
				
				if ( bFlying && iCreatureSize == CREATURE_SIZE_TINY  )
				{
					iThrownFeet = d6()*10;
					iThrownDamage = d6(2);
				}
				else if ( iCreatureSize == CREATURE_SIZE_TINY  )
				{
					iThrownFeet = d4()*10;
					iThrownDamage = d4( CSLGetMax(iThrownFeet/10,1) );
					bKnockDown = TRUE;
				}
				else if ( bFlying && iCreatureSize == CREATURE_SIZE_SMALL  )
				{
					iThrownFeet = d6()*10;
				}
				else if ( iCreatureSize == CREATURE_SIZE_SMALL  )
				{
					bKnockDown = TRUE;
				}
				else if ( bFlying && ( iCreatureSize == CREATURE_SIZE_MEDIUM || iCreatureSize == CREATURE_SIZE_INVALID ) )
				{
					iThrownFeet = d6()*5;
				}
				else if ( iCreatureSize == CREATURE_SIZE_MEDIUM || iCreatureSize == CREATURE_SIZE_INVALID  )
				{
					bKnockDown = TRUE;
				}
				
				
				
				if ( iThrownFeet > 0 )
				{
					float fDistance = FeetToMeters(IntToFloat(iThrownFeet));
					CSLHurlTargetFromLocation(lStartLocation, oTarget, fDistance);
					SendMessageToPC( oTarget, "The "+sName+" throws you "+IntToString(iThrownFeet)+" Feet" );
					if ( iThrownDamage > 0 )
					{
						eDamage = EffectDamage(iThrownDamage, DAMAGE_TYPE_BLUDGEONING);
						ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget);
						
					}
				}
				
				if ( bKnockDown )
				{
					ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, RoundsToSeconds(1));
					if ( !GetIsImmune( oTarget, IMMUNITY_TYPE_KNOCKDOWN ) )
					{
						CSLIncrementLocalInt_Timed(oTarget, "CSL_KNOCKDOWN",  RoundsToSeconds(1), 1); // so i can track the fact they are knocked down and for how long, no other way to determine
						SendMessageToPC( oTarget, "The strong "+sName+" knocks you down" );
					}
				}
				
					
				effect eWind = EffectSkillDecrease(SKILL_LISTEN, 4);
				if ( GetWeaponRanged( GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget) ) )
				{
					eWind = EffectLinkEffects( eWind, EffectAttackDecrease(4, ATTACK_BONUS_MISC) );
					SendMessageToPC( oTarget, "You find it harder to aim into the strong "+sName );
				}
				
				ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eWind, oTarget, RoundsToSeconds(1) );
				
				
				CSLIncrementLocalInt( oTarget, "GUSTED", 1 );
				DelayCommand(6.0f+fDelay, CSLDecrementLocalInt_Void( oTarget, "GUSTED", 1 ) );
				
				//Apply effects to the currently selected target.
				//DelayCommand(fDelay, HkApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
				//This visual effect is applied to the target object not the location as above.  This visual effect
				//represents the flame that erupts on the target not on the ground.
				DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
				DelayCommand(fDelay,CSLTorchExtinguishObject( oTarget ) );
				CSLRemoveEffectSpellIdSingle( SC_REMOVE_ALLCREATORS, OBJECT_SELF, oTarget, SPELL_GLITTERDUST, SPELL_DECK_BUTTERFLYSPRAY);
				
			}
	}
}



#62
kevL

kevL
  • Members
  • 4 052 messages
that's just beautiful, man

( i can see lil bits of my stuff in there, Lol )


ps. luv what yer doin with Doors - that'd freak a guy right out

#63
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
lol wait till you see a druid shifting into a dragon using all that.

#64
kamal_

kamal_
  • Members
  • 5 238 messages
A minor point, but the grammar in those player messages only works for generically named dragons, eg "ancient red dragon", not specifically named ones "Tholapsyx". 'The Tholapsyx damages you with it's wing buffet' just isn't right.

#65
The Fred

The Fred
  • Members
  • 2 516 messages
Draconomonicon!

#66
Axe_Edge

Axe_Edge
  • Members
  • 278 messages
Great stuff! I'm starting another OC through tonight. I'm looking forward to Tholapsyx. Any chance certain dragons protecting a large heart receiving an upgrade? (hint)

:)

Modifié par Axe_Edge, 12 janvier 2012 - 05:39 .


#67
kevL

kevL
  • Members
  • 4 052 messages
oh yeh, totally forgot about those guys!

(gonna make 'Raps proud :)


ps. Axe, don't forget ver.1.2 went out a few days ago ..... 'course ye notice tha'



( hmm, i see a few more up on the clifftops .. but i wouldna do *that* hehe )

(unless, there's a dialog ... less talk, more scripting)

#68
kevL

kevL
  • Members
  • 4 052 messages
thanks Axe,

there's some funny behavior in the Valley, due to my UserDefined script getting a call in both areas (as yet unintentionally)


i'm sorting it out ...

#69
Axe_Edge

Axe_Edge
  • Members
  • 278 messages
No problem. I'm looking forward to facing the wyrms when they're ready.

Are there two more back in West Harbor?  I'll have to look.  I might be thinking of MotB on that one.

Edit:  I was thinking of SoZ :blink:

Modifié par Axe_Edge, 14 janvier 2012 - 06:12 .


#70
kevL

kevL
  • Members
  • 4 052 messages
haven't looked at those West Harbor/SoZ dragons yet; ironically this all grew out of a Blue Dragon in SoZ (special encounter, iirc)

My original idea was just to put some code in the Pia, to beef up dragons in general - it was only after I realized that Tholapsyx is borky that this separate project rose up! So i'm trying to keep their difficulty the same as originally, and if anyone wants them tougher, like me, throw the Pia in as well. gtg ..


The dragons at the 'large heart' are working themselves in nicely. It's leading me in the direction I originally wanted to go: using a single function that identifies Dragon Race, to slap on standardized SaveDCs and automagically calculate ranges & radii as a factor of ModelScale. that's done, in a basic form. Just have to conform scripts w/ spellabilities left,

and run 'em through a few fights :)

#71
kevL

kevL
  • Members
  • 4 052 messages
done. Up. enjoy,

#72
Axe_Edge

Axe_Edge
  • Members
  • 278 messages

kevL wrote...

done. Up. enjoy,


Way cool.

B)

#73
Axe_Edge

Axe_Edge
  • Members
  • 278 messages
kevL, this is incredible. Late last night, my party finally came upon the transition to the canyon. After waiting so long to get there to see the dragon in action, I decided to play one battle before calling it a day. The battle was Hella fun! I'll expand on the encounter when I have time. This needs to be placed into the "must haves".

Great job.

Modifié par Axe_Edge, 19 mars 2012 - 04:07 .


#74
kevL

kevL
  • Members
  • 4 052 messages
<big grin>

look out fer when that Displacement kicks in eh! ( just when ya think ya got 'er beggin fer mercy .. BOOM!!


Ps. would luv to hear a story at yur leisure, Axe

Modifié par kevL, 19 mars 2012 - 06:35 .


#75
kevL

kevL
  • Members
  • 4 052 messages
Fighting Tholapsyx v.2

- tweaked up version of the original Fighting Tholapsyx video. (colors, audio sync, and text are quite better, etc.) dont expect anything glamorous tho,