ok, i thought i could just let this whole topic go because i started using a heartbeat script to "attack" once per combat round. i know it's not directly linked to the combat round, but the hb should trigger about once every 6 seconds, so that's close enough.
anyway, i went with that, but now the NPC is running BOTH its special combat script and the heartbeat script. what's worse is that before it would only run the special script once, but now it runs it each and every attack my PC makes on him. this makes the NPC "fire" his musket 5+ times per round at the PC. he's only supposed to do it once. at this point, i'm going to attempt to paste in all the different code bits (i'll try to clean it up some, but i'd hate to cut out what i think is irrelevant because i could be wrong).
special combat script:
void main(){
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
if(LineOfSightObject(OBJECT_SELF, oTarget)){
// FIRE MUSKET
object oMusket = FindMusket(OBJECT_SELF);
if(GetIsObjectValid(oMusket)){
SendMessageToPC(oTarget, "combat");
FireMultipleShotMusket(oMusket, OBJECT_SELF, oTarget, GetLocation(oTarget));
SetLocalObject(OBJECT_SELF, "MUSKET_TARGET", oTarget);
}else{
SpeakString("invalid musket");
}
}else{
DeleteLocalObject(OBJECT_SELF, "MUSKET_TARGET");
}
SetLocalInt(OBJECT_SELF, "X2_SPECIAL_COMBAT_AI_SCRIPT_OK", 1);
}
so, it should be getting the closest enemy, checking to see if there is a clear line of sight, checking himself for a musket, and then firing it. then i saved the target to himself because i was using that in my heartbeat script. if this combat script worked correctly, then i wouldn't need to do that.
and now for the parts of the other (BIG) script. bear with me here:
object FindMusket(object oShooter){
object oMusket;
int i=0;
oMusket = GetItemPossessedBy(oShooter, "Musket");
if(GetIsObjectValid(oMusket)){
return oMusket;
}
while(i < NUM_MUSKETS){
oMusket = GetItemPossessedBy(oShooter, "MUSKET_" + IntToString(i));
if(GetIsObjectValid(oMusket)){
return oMusket;
}
i++;
}
return OBJECT_INVALID;}
this one is simple enough.
void FireMultipleShotMusket(object oMusket, object oMe, object oTarget, location lTarget){
string sMusketTag;
//make sure it's a recognized musket
sMusketTag = GetTag(oMusket);
if(!GetIsMusket(sMusketTag)){
return;
}
//check to see if we have updated constants for a special musket
// just sets some global variables
UpdateMusketConstants(sMusketTag, oMe);
//debugging - comment out
// DisplayConstants(oMe, oTarget);
//shots per round
float fDelay = 6.0/MUSKET_RATE_OF_FIRE;
//stagger shots a little bit if a bunch of people shoot at once
float f = Random(2)/5.0;
//FIXME: if shooter dies he still finishes his rounds of shots
while(f < 6.0){
DelayCommand(f, FireMusket(oMusket, oMe, oTarget, lTarget));
f += fDelay;
}
}
void FireMusket(object oMusket, object oCreature, object oTarget, location lTarget){
int iHit = 0;
int iDamage = 0;
location lMe;
vector vMe;
int iDamagePower;
//puff of smoke and spark
vMe = GetPosition(oCreature);
vMe.z += 1.0;
lMe = Location(GetArea(oCreature), vMe, 0.0);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_COM_SPARKS_PARRY), lMe);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SMOKE_PUFF), lMe);
ApplyEffectToObject (DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_S), oCreature);
iHit = RollRangedAttack (oCreature, oTarget, MUSKET_CRITICAL_RANGE, MUSKET_ATTACK_BONUS, MUSKET_RANGE_INCREMENT_FEET);
if (iHit > 0){
iDamage = RollDamage (oCreature, oTarget, MUSKET_DAMAGE_NUM_DICE, MUSKET_DAMAGE_DIE_TYPE, MUSKET_DAMAGE_BONUS)
effect eDamage = EffectDamage (iDamage, DAMAGE_TYPE_PIERCING);
if (GetObjectType (oTarget) == OBJECT_TYPE_CREATURE){
effect eBlood = EffectVisualEffect (VFX_COM_BLOOD_LRG_RED);
eBlood = EffectLinkEffects (EffectVisualEffect (VFX_COM_BLOOD_LRG_RED), eBlood);
eBlood = EffectLinkEffects (EffectVisualEffect (VFX_COM_BLOOD_LRG_RED), eBlood);
ApplyEffectAtLocation (DURATION_TYPE_INSTANT, eBlood, GetLocation (oTarget));
DelayCommand(0.01, AssignCommand(oCreature, ApplyDamage (oCreature, oTarget, iDamage, iDamagePower, DAMAGE_TYPE_PIERCING, 0.1)));
}else{
DelayCommand(0.01, AssignCommand(oCreature, ApplyDamage (oCreature, oTarget, iDamage, iDamagePower, DAMAGE_TYPE_PIERCING, 0.1, VFX_COM_BLOOD_SPARK_LARGE)));
}
}else{
}
}
}
so i might have messed up some of the brackets there, but i think it's correct. my best guess is that the "DelayCommand(AssignCommand())" lines are breaking the combat state? but then i commented out the "FireMultipleShotMusket" call in the special combat script and he still stopped combatting. but then you were saying that he had to know to continue being in combat, so maybe that was a different problem?
so, in advance, thanks to all of you who like reading through source code
'>
my last option is to just stop the NPC from firing in his combat script and only use that to set a target and signal the heartbeat script to start firing. that *should* still work, but it's not really precise (the delay seems to be anywhere from 4-8s), and it's infuriating because this *should* work.
'>
and by all means don't shy away from speaking of recursion. i'm well versed in coding concepts. i just struggle with the toolset and its scripting language
'>
WAIT! so would the special script run once per attack the NPC gets? for some reason i always thought that the DetermineCombatRound would only run once per combat round, and it would handle all the attacks of the NPC. it does kind of make sense now that it runs once per attack he's supposed to get. is that it? and if so, how can i get him to only shoot once per round?
Modifié par acomputerdood, 01 mai 2012 - 09:12 .