Author Topic: Mage Duel system  (Read 939 times)

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Mage Duel system
« Reply #15 on: August 07, 2012, 11:52:00 pm »


               One issue with the creature...
you can't have a mage duel across a chasm as the creature wouldn't be able to walk back and forth.

Just FYI.
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #16 on: August 08, 2012, 12:13:09 am »


               Good point @ Henesua

Yeah video is finished processing.
I managed to get the function to force the player and target to face eachother, and then the creature is generated via AssignCommand(ActionDoCommand(Part2())) etc
So - in theory, the creatures creation is added to action queue, which should follow directly after the player finishes the turn to face.

As for the gap/gorge problem.
I dont think there is any function that can determine 'is walkable', or 'can get to'

Function I have - uses a peseudo loop to determine the distance between caster and center, and target and center.
If the distance for one of them is less than 1.75, then it explodes.
If - in the scenario you point out, that the creature can never get to either creature, then it would in theory go indefinitely.

Would need to code in a max time limit etc.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Mage Duel system
« Reply #17 on: August 08, 2012, 12:19:22 am »


               Well, If you do end up having problems with the mean, Perhaps in cases where the target is moving, Try the function I posted above.
 
EDIT:  Forgot to say, the video looks really good.

Or if you wanted just one line of code instead of the function

...
location l = Location( GetArea(oCaster), (GetPosition(oCaster) + GetPosition (oTarget))/2.0, GetFacing(oCaster));
               
               

               


                     Modifié par Lightfoot8, 08 août 2012 - 02:13 .
                     
                  


            

Legacy_Carcerian

  • Hero Member
  • *****
  • Posts: 1655
  • Karma: +0/-0
Mage Duel system
« Reply #18 on: August 08, 2012, 03:10:28 am »


               Awesome vid indeed!
               
               

               
            

Legacy_ffbj

  • Hero Member
  • *****
  • Posts: 1097
  • Karma: +0/-0
Mage Duel system
« Reply #19 on: August 08, 2012, 04:03:50 am »


               As long as it's an invisible creature you could add the effect appear/disappear to a random waypoint within the vicinity of the two mages, closer to the one who was losing, however that is determined. In this way the beam effects would follow it, the creature up and down. Have some sort of conditinal so it does not happen all that often. Oh and the video was the cat's meow.
               
               

               


                     Modifié par ffbj, 08 août 2012 - 03:08 .
                     
                  


            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #20 on: August 08, 2012, 02:02:26 pm »


               Thx for the comments on the vid

I also had an idea to add EffectBeams  with the miss boolean set to true.

It would be like Voldemort vs Dumbledore - where he tries to shoot lightning bolts past him, to hit Harry.

I think if the pseudo hb on the creature, was configured to randomly shoot 'Miss' beams towards the caster/target - then it would look like beams are flying to the side of the caster / target, giving the impression of a much busier scene.
Im unsure of the logic for the beam miss function - I think it tends to shoot the miss beams towards the target, but with an angle offset of up to 45 degrees or something.  
Eg-  the beams are always in the general direction of the target, but never hitting the target.

In addition to this - might be able to make it so that energy that shoots out of the center does damage/explosions to the ground etc.
               
               

               
            

Legacy_acomputerdood

  • Sr. Member
  • ****
  • Posts: 378
  • Karma: +0/-0
Mage Duel system
« Reply #21 on: August 15, 2012, 03:05:33 pm »


               were you planning to release any of the code to produce these visual effects?  it would be nice not having to recreate them for myself.

it looks great!
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #22 on: August 17, 2012, 12:59:50 pm »


               I will have a look for the script when I get home.
I kinda suffered a module corruption - inside the module I use for creating stand-alone scripts for inclusion via resman.



#include "inv_spells_inc"
#include "nwnx_funcs"
#include "mage_duel_inc"

void main()
{
    object oCaster = OBJECT_SELF;

    object oTarget = GetLocalObject(oCaster,"INV_TARGET");
    if(GetResRef(oTarget)=="beam_intersec")
    {
        DestroyObject(oTarget,0.75);
        return;
    }
    StartDuel(oCaster,oTarget);


}



Litterally, all I have at the moment infront of me, is this - which shows that the majority of the code is contained inside mage_duel_inc

I was only really investigating this, as a potential system to develop - so yeah, I will make what I have so far public, but its gonna be very rough around the edges - Havent worked on it for about a week.
Been working on a new Subrace inspired by the Faeries from True Blood - which is actually really fun to develop.
I gave them 'Light' magic - which is essentially like a mana meter, and while they have 75% light magic or above, they get unlimited spells (their spells for that spell level replenishes, after a spell cast)
And they get light blasting powers,
ability to open portals to a Fae Realm etc
Very fun to make - will include a video of them too
               
               

               
            

Legacy_acomputerdood

  • Sr. Member
  • ****
  • Posts: 378
  • Karma: +0/-0
Mage Duel system
« Reply #23 on: August 17, 2012, 02:22:51 pm »


               i'm really only interested in the mechanics of how the visuals work, and yeah, it looks like most of that will be in mage_duel_inc.

i understand if you wouldn't want to release something - just know that i'll be doing my best to copy your system from the video!  haha.

thanks for saving me a bunch of work, though '<img'>
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #24 on: August 17, 2012, 02:34:15 pm »


               most of the complex stuff is just to figure out where the place the creature.

Once you have that, just do
CreateObject  to make the creature
make sure its friendly to both players - so it doesnt attack them

Then calculate who the winner is

then instruct the creature to walk towards the loser

I use a pseudo loop that checks the distance between caster and target
whoever gets within 2ft of the creature, receives the damage from the explosion etc

The beams are done by the creature,
(he is the effect creator)
so the beams come from the creature, and hit both the caster and target

The damage from the explosion has to be created by the winner - to give the winner credit for any deaths


But yes-  hopfully my mage_duel_inc is intact, and I will release it here later tonight.
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #25 on: August 17, 2012, 09:41:41 pm »


               

#include "x0_i0_position"

int GetIsSpellHostile(int iSpellID)
{
 int i = StringToInt(Get2DAString("spells","HostileSetting",iSpellID));
 return i;
}

int HasJustCast(object oTarget)
{
    return GetLocalInt(oTarget,"JUST_CAST");
}

object GetLastSpellTarget(object oCaster)
{
    return GetLocalObject(oCaster,"LAST_CAST_AT");
}
void gao_ActionCreateObject(string sTemplate, location lLocation, int nDurationType, int nVFX, float fDuration, float fWait, float fLifetime, object oData)
{
    object oPlaceable = CreateObject(OBJECT_TYPE_PLACEABLE, sTemplate, lLocation);
    if (nDurationType >= 0 && nVFX >= 0) DelayCommand(fWait, ApplyEffectToObject(nDurationType, EffectVisualEffect(nVFX), oPlaceable, fDuration));
    if (fLifetime > 0.0) DestroyObject(oPlaceable, fLifetime);
    else    // if display is permanent, then start storing the objects as local to ease garbage collection later on.
    {       // code modified from Ornedan's modification of the original function
        int i = GetLocalInt(oData, "storetotal");
        AssignCommand(oPlaceable, ActionDoCommand(SetLocalObject(oData, "store" + IntToString(i), oPlaceable)));
        SetLocalInt(oData, "storetotal", i+1);
    }
}

void PlaceLineFromVectorToVector(string sTemplate, object oArea, vector vOne, vector vTwo, int nFrequency, float fTime, int nDurationType, int nVFX, float fDuration, float fWait, float fLifetime, object oData)
{
    int i;
    if (nFrequency < 1) nFrequency = 1;
    vector vResultant = vTwo - vOne;
    vector vUnit = VectorNormalize(vResultant);
    float fDelay = fTime/IntToFloat(nFrequency);
    float fLength = VectorMagnitude(vResultant);
    float fTheta = fLength/IntToFloat(nFrequency); // distance between each node
    float fAngle = VectorToAngle(vUnit);
    location lPos;
    float f;

    for (i=0; i<nFrequency; i++)
    {
        f = IntToFloat(i);
        lPos = Location(oArea, vOne + fTheta*f*vUnit, fAngle);
        DelayCommand(f*fDelay, gao_ActionCreateObject(sTemplate, lPos, nDurationType, nVFX, fDuration, fWait, fLifetime, oData));
    }
}


void SetJustCast(object oCaster, object oTarget)
{
    SetLocalObject(oCaster,"LAST_CAST_AT",oTarget);
    SetLocalInt(oCaster,"JUST_CAST",1);
    DelayCommand(4.00,DeleteLocalInt(oCaster,"JUST_CAST"));
    DelayCommand(4.10,DeleteLocalObject(oCaster,"LAST_CAST_AT"));
}


int ShouldTheyDuel(object oCaster, object oTarget, int iSpell)
{
  if(!GetIsSpellHostile(iSpell)) { return FALSE; }
  SetJustCast(oCaster,oTarget);
  if(HasJustCast(oTarget) && GetLastSpellTarget(oTarget)==oCaster)
  {
    return TRUE;
  }
  return FALSE;
}


void GroupDestroyObject(object oData, float fDelay=0.0f, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
   int i;
   int nTotal = GetLocalInt(oData, "storetotal");
   if (nTotal < 1) return;
   float fBreak = fOvertime/IntToFloat(nTotal);
   if (bReverseOrder)
   {
      int j = 0;
      for (i=nTotal-1; i>-1; i--)
      {
         DelayCommand(fDelay + fBreak*IntToFloat(j), DestroyObject(GetLocalObject(oData, "store" + IntToString(i))));
         j++;
      }
   }
   else
   {
      for (i=0; i<nTotal; i++)
      {
         DelayCommand(fDelay + fBreak*IntToFloat(i), DestroyObject(GetLocalObject(oData, "store" + IntToString(i))));
      }
   }
   if(GetObjectType(oData)!=OBJECT_TYPE_CREATURE)
   {
        DestroyObject(oData, fDelay + fOvertime + 0.5);
   }
}


void ApplyPriori(int iNode,object oCaster)
{
 effect eBeam = EffectBeam(VFX_BEAM_ODD,OBJECT_SELF,BODY_NODE_HAND);
 effect eStart = EffectVisualEffect(2155);

 object oNode = GetLocalObject(oCaster,"store"+IntToString(iNode));
 if(oNode == OBJECT_INVALID)
 {
    SpeakString("oNode = Object_invalid");
    return;
 }
 oNode = CreateObject(OBJECT_TYPE_PLACEABLE,"invisobj",GetLocation(oNode),FALSE,GetTag(oNode)+"_b");
 ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eBeam,oNode,1.55);
 if(OBJECT_SELF == oCaster)
 {
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eStart,oNode,1.55);
 }
}

void UpdateDuel(object oCaster,object oTarget, int iTotalNodes, int iCurrent)
{


    //object CurrentNode = GetLocalObject(oCaster,"CURRENT_NODE");
     //Smaller = Caster = Losing
    //Bigger = Target = Losing
    int iSpellCraftCaster = GetSkillRank(SKILL_SPELLCRAFT,oCaster,FALSE);
    int iSpellCraftTarget = GetSkillRank(SKILL_SPELLCRAFT,oTarget,FALSE);
    int iNext = 0;
    if(iSpellCraftCaster >= iSpellCraftTarget)
    {
        //Caster Wins
        AssignCommand(oCaster,ActionDoCommand(ApplyPriori(iCurrent+1,oCaster)));
        AssignCommand(oTarget,ActionDoCommand(ApplyPriori(iCurrent+1,oCaster)));
        iNext = iCurrent+1;
    }else
    {
        //Caster Loses
        AssignCommand(oCaster,ActionDoCommand(ApplyPriori(iCurrent-1,oCaster)));
        AssignCommand(oTarget,ActionDoCommand(ApplyPriori(iCurrent-1,oCaster)));
        iNext = iCurrent-1;
    }
    if(iNext <= 1)
    {
        // Caster Lost
        AssignCommand(oCaster,SpeakString("Caster Lost!!"));
        DeleteLocalInt(oCaster,"DUELING");
        DeleteLocalInt(oTarget,"DUELING");
        GroupDestroyObject(oCaster, 1.0,1.0, FALSE);
        DeleteLocalInt(oCaster,"storedtotal");
        return;
    }
    if(iNext >= iTotalNodes)
    {
        // Caster Lost
        AssignCommand(oCaster,SpeakString("Caster Won!!"));
        DeleteLocalInt(oCaster,"DUELING");
        DeleteLocalInt(oTarget,"DUELING");
        GroupDestroyObject(oCaster, 1.0,1.0, FALSE);
        DeleteLocalInt(oCaster,"storedtotal");
        return;
    }
    DelayCommand(0.75,UpdateDuel(oCaster,oTarget,iTotalNodes,iNext));


}

void GroupExecuteScript(string sScript, object oData, float fOvertime=3.0f, int bReverseOrder=FALSE)
{
   int i;
   int nTotal = GetLocalInt(oData, "storetotal");
   if (nTotal < 1) return;
   float fBreak = fOvertime/IntToFloat(nTotal);
   if (bReverseOrder)
   {
      int j = 0;
      for (i=nTotal-1; i>-1; i--)
      {
         DelayCommand(fBreak*IntToFloat(j), ExecuteScript(sScript, GetLocalObject(oData, "store" + IntToString(i))));
         j++;
      }
   }
   else
   {
      for (i=0; i<nTotal; i++)
      {
         DelayCommand(fBreak*IntToFloat(i), ExecuteScript(sScript, GetLocalObject(oData, "store" + IntToString(i))));
      }
   }
}



int RandomBeam()
{
 int iReturn = 0;
 switch(d6(1))
 {
  case 1: iReturn = VFX_BEAM_SILENT_COLD;break;
  case 2: iReturn = VFX_BEAM_SILENT_EVIL;break;
  case 3: iReturn = VFX_BEAM_SILENT_FIRE;break;
  case 4: iReturn = VFX_BEAM_SILENT_HOLY;break;
  case 5: iReturn = VFX_BEAM_SILENT_LIGHTNING;break;
  case 6: iReturn = VFX_BEAM_SILENT_MIND;break;
 }
 return iReturn;
}

void DuelPart2a(object oCaster, object oTarget)
{
    //GroupExecuteScript("default", oCaster, 5.00, FALSE);
    AssignCommand(oCaster,SpeakString("Starting Duel Part 2 Function"));
    int iTotalPoints = GetLocalInt(oCaster,"storetotal");
    int iMid = iTotalPoints/2;
    ApplyPriori(iMid,oCaster);
    AssignCommand(oCaster,SpeakString("Total Points:"+IntToString(iTotalPoints)));
    AssignCommand(oCaster,SpeakString("Mid Point:"+IntToString(iMid)));
    //object CurrentNode = GetLocalObject(oCaster,"store"+IntToString(iMid));
    //SetLocalObject(oCaster,"CURRENT_NODE",CurrentNode);

    UpdateDuel(oCaster,oTarget, iTotalPoints, iMid);

}


void DoBeams(object oCenter,int iBeam)
{
    effect eBeam1 = EffectBeam(iBeam,OBJECT_SELF,BODY_NODE_HAND);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eBeam1,oCenter,5.00);

}

void DuelPart2(object oCaster, object oTarget, object oCenter)
{
    int iSpellCraftCaster = GetSkillRank(SKILL_SPELLCRAFT,oCaster,FALSE);
    int iSpellCraftTarget = GetSkillRank(SKILL_SPELLCRAFT,oTarget,FALSE);


    int iNext = 0;
    if(iSpellCraftCaster >= iSpellCraftTarget)
    {
        AssignCommand(oCenter,ActionForceFollowObject(oTarget,0.75));
    }
    else
    {
       AssignCommand(oCenter,ActionForceFollowObject(oTarget,0.75));
    }

}


void Explode(object oCenter,object oLoser)
{
 effect e = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
 effect eDamage = EffectDamage(d12(3),DAMAGE_TYPE_MAGICAL,DAMAGE_POWER_ENERGY);
 ApplyEffectAtLocation(DURATION_TYPE_INSTANT,e,GetLocation(oCenter));
 ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oLoser);
 DestroyObject(oCenter,0.25);

}

void PseudoLoop(object oCaster, object oTarget, object oCenter, int iBeam1, int iBeam2)
{

    float fCasterDist, fTargetDist;
    AssignCommand(oCaster,DoBeams(oCenter,iBeam1));
    AssignCommand(oTarget,DoBeams(oCenter,iBeam2));
    fCasterDist = GetDistanceBetween(OBJECT_SELF,oCaster);
    fTargetDist = GetDistanceBetween(OBJECT_SELF,oTarget);
    int iKill = FALSE;
    if(fCasterDist <= 2.75)
    {
          SetLocalInt(oCaster,"DUELING",0);
          SetLocalInt(oTarget,"DUELING",0);
          AssignCommand(oTarget,Explode(oCenter,oCaster));
          iKill = TRUE;
    }
    if(fTargetDist <= 2.75)
    {
          SetLocalInt(oCaster,"DUELING",0);
          SetLocalInt(oTarget,"DUELING",0);
          AssignCommand(oCaster,Explode(oCenter,oTarget));
          iKill = TRUE;
    }
    if(iKill == TRUE)
    {
        DestroyObject(OBJECT_SELF,0.25);
        return;
    }
    DelayCommand(1.75,PseudoLoop(oCaster,oTarget,oCenter,iBeam1,iBeam2));
}


void Part2(object oCaster,object oTarget)
{
  vector v1 = GetPosition(oCaster);
  vector v2 = GetPosition(oTarget);
  float fDist = GetDistanceBetween(oCaster,oTarget);
  location l =  GenerateNewLocation(oCaster, fDist/2, GetFacing(oCaster), GetFacing(oCaster));
  object oCenter = CreateObject(OBJECT_TYPE_CREATURE,"beam_intersec",l,FALSE,"duel_center");
  effect eStart = EffectVisualEffect(2155);
  effect eStart2 = EffectCutsceneGhost();
  effect eSlow = EffectSlow();
   ApplyEffectToObject(DURATION_TYPE_PERMANENT,eSlow,oCenter);
   ApplyEffectToObject(DURATION_TYPE_PERMANENT,eStart2,oCenter);
  ApplyEffectToObject(DURATION_TYPE_PERMANENT,eStart,oCenter);
  SetName(oCenter,"Energy Ball");
  SetImmortal(oCenter,TRUE);
  AddHenchman(oCaster,oCenter);
  SetIsTemporaryNeutral(oCaster,oCenter);
  SetIsTemporaryNeutral(oTarget,oCenter);
  AssignCommand(oCenter,SpeakString("Starting Duel"));
  int i1, i2;
  i1 = RandomBeam();
  i2 = RandomBeam();
  AssignCommand(oCenter,PseudoLoop(oCaster,oTarget,oCenter,i1,i2));
  DelayCommand(1.5,DuelPart2(oCaster,oTarget,oCenter));

}
void StartDuel(object oCaster, object oTarget)
{
  SetLocalInt(oCaster,"DUELING",0);
  SetLocalInt(oTarget,"DUELING",0);
  int iDuelOn = GetLocalInt(oCaster,"DUELING");
  if(iDuelOn){ return;}
  SetLocalInt(oCaster,"DUELING",1);
  SetLocalInt(oTarget,"DUELING",1);
  //Place the duel points
    vector v1 = GetPosition(oCaster);
    vector v2 = GetPosition(oTarget);
  AssignCommand(oCaster,SetFacingPoint(v2));
  AssignCommand(oTarget,SetFacingPoint(v1));
  AssignCommand(oCaster,ActionDoCommand(Part2(oCaster,oTarget)));
}

As promissed- Note - this was just for personal use - so there is alot of non-sensical coding here,
Just follow the flow - start with
'StartDuel()

and follow the execution.
I tried multiple methods prior to using an invisible creature, so some of the code relates to those previous methods - (the nodes etc)
you will need to create your invisibile creature still, and slot its resref into this include file
               
               

               
            

Legacy_acomputerdood

  • Sr. Member
  • ****
  • Posts: 378
  • Karma: +0/-0
Mage Duel system
« Reply #26 on: August 21, 2012, 11:38:12 am »


               i really appreciate you posting that code, Baaleos!

i've figured out how most everything works, but i'm still a little confused about a few things.  i'm guessing most of my questions stem from you just testing stuff out in the code, but i'll ask just to see if you have an actual reason for some of this:


void StartDuel(object oCaster, object oTarget)
{
SetLocalInt(oCaster,"DUELING",0);
SetLocalInt(oTarget,"DUELING",0);
int iDuelOn = GetLocalInt(oCaster,"DUELING");
if(iDuelOn){ return;}
...
}

this check will always fail, causing nothing to ever happen.  i took it out and it works fine.


void Part2(object oCaster,object oTarget)
{
....
AddHenchman(oCaster,oCenter);
...

any reason why the beam intersection creature was added as a henchman?  any faction neutral to everyone should be fine, no?  again, i took it out and haven't seen any problems.

and yes, there was a LOT of code in there that wasn't used.  i cleaned up the necessary functions, refactored and renamed a bit as well.  the only major things i added were:

- each "round" of the pseudoloop recalculates which way the middle will travel.  that way instead of just comparing spellcraft ranks and having the beam fly straight to the loser, you can add a d20 to the spellcraft each loop so the beam will go back and forth a bit.
- spectators within a certain distance of the battle will stop and watch

my future plans for the system will be:
- both caster and target will be "frozen" or "locked" in place for the battle.  right now nothing stops them from running around while beaming each other.  would EffectCutsceneParalyze be appropriate for this?
- spectators also run to the ball and try to attack it.  i'm guess it's a faction problem.
- i'd like the participants in the battle to not be affected by anything else (spells, being attacked, etc).  setting them to plot would work, but i'd like them to be untargettable - is that possible?

anyway, i have a small demo up to illustrate what i've done with Baaleos's system so far.  you can direct connect to:

dalakora.com:5122
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
Mage Duel system
« Reply #27 on: August 21, 2012, 05:11:06 pm »


               

acomputerdood wrote...

i really appreciate you posting that code, Baaleos!

i've figured out how most everything works, but i'm still a little confused about a few things. i'm guessing most of my questions stem from you just testing stuff out in the code, but i'll ask just to see if you have an actual reason for some of this:


void StartDuel(object oCaster, object oTarget)
{
SetLocalInt(oCaster,"DUELING",0);
SetLocalInt(oTarget,"DUELING",0);
int iDuelOn = GetLocalInt(oCaster,"DUELING");
if(iDuelOn){ return;}
...
}

this check will always fail, causing nothing to ever happen. i took it out and it works fine.


void Part2(object oCaster,object oTarget)
{
....
AddHenchman(oCaster,oCenter);
...

any reason why the beam intersection creature was added as a henchman? any faction neutral to everyone should be fine, no? again, i took it out and haven't seen any problems.

and yes, there was a LOT of code in there that wasn't used. i cleaned up the necessary functions, refactored and renamed a bit as well. the only major things i added were:

- each "round" of the pseudoloop recalculates which way the middle will travel. that way instead of just comparing spellcraft ranks and having the beam fly straight to the loser, you can add a d20 to the spellcraft each loop so the beam will go back and forth a bit.
- spectators within a certain distance of the battle will stop and watch

my future plans for the system will be:
- both caster and target will be "frozen" or "locked" in place for the battle. right now nothing stops them from running around while beaming each other. would EffectCutsceneParalyze be appropriate for this?
- spectators also run to the ball and try to attack it. i'm guess it's a faction problem.
- i'd like the participants in the battle to not be affected by anything else (spells, being attacked, etc). setting them to plot would work, but i'd like them to be untargettable - is that possible?

anyway, i have a small demo up to illustrate what i've done with Baaleos's system so far. you can direct connect to:

dalakora.com:5122


Yeah,
The way I was testing the system, was by using my already functional Incantation system
(the video I posted shows it in action)
The magic missile flies from me, hits a target.
A script then gets run on the caster - but the Target of the spell is set as a local object on the caster - Allowing the Script to access the caster and the target.
The main attraction of this system, is that it uses resman, and each spell is a modular script that I upload via ftp, and then add to the system via database entries, it also provided the means for me to demo/debug the mage duel system without restarting the server.
Main attraction of this system, is that the spells can be developed, uploaded, and implimented without restarting the server.
Magic Related Systems in Worlds of Rhun

During one of my experiments I accidentally set the IS_DUELING int to be 1, and it never went back to 0

The purpose of the IS_DUELING int, is to stop another player coming along, and starting a duel while your in the process of dueling.

AddHenchman(oCaster,oCenter);

Yeah - I had faction issues in my module.
I was using ResMan for most of the development of this system, on my live server.
Meaning I never had to rebuild/compile,reupload and restart any servers.
My creature, was created in a basic module, which didnt have access to the 72+ factions that my main server had.
So - when I used a bioware faction, my creature tended to attack vampire players.
By adding as Henchman, the creature is guaranteed to be friendly to the caster - although, I cant guarantee it being friendly to the target. - For that, would need a true neutral faction, and adjustments made to faction reputation to ensure both target and caster are friendly to the middle creature.

Feel free to modify the system as needed-
To be honest - I only thought the idea up, cause it looked cool in my head.
After testing it, I got a little bit of pride knowing that it was feasible, and still looked cool.

Feel free to build upon it,
look forward to seeing your changes.
               
               

               
            

Legacy_acomputerdood

  • Sr. Member
  • ****
  • Posts: 378
  • Karma: +0/-0
Mage Duel system
« Reply #28 on: August 24, 2012, 01:11:12 pm »


               here's what i've done with your prototype.  i tried to keep the include file generic, and added places where people could add customizations.


#include "x0_i0_position"

int DEBUG = 0;

float fStepIncrement = 3.0;
float fLoopTime = 1.75;
float fSpectatorSize = 30.0;
float fBeamBattleMaxLen = 45.0;
float fBeamBattleStunnedTime = 10.0;
float fTimeElapsed = 0.0;
float fMinDist = 10.0;
float fMaxDist = 100.0;


int GetSpellcasterLevels(object oPC){
    int iLevels;
    iLevels = GetLevelByclass(class_TYPE_BARD, oPC) + GetLevelByclass(class_TYPE_PALEMASTER, oPC) + GetLevelByclass(class_TYPE_SORCERER, oPC) + GetLevelByclass(class_TYPE_WIZARD, oPC);

    return iLevels;
}


int BeamBattleRandomBeam(){
    int iReturn = 0;
    switch(d6(1)){
        case 1: iReturn = VFX_BEAM_SILENT_COLD;break;
        case 2: iReturn = VFX_BEAM_SILENT_EVIL;break;
        case 3: iReturn = VFX_BEAM_SILENT_FIRE;break;
        case 4: iReturn = VFX_BEAM_SILENT_HOLY;break;
        case 5: iReturn = VFX_BEAM_SILENT_LIGHTNING;break;
        case 6: iReturn = VFX_BEAM_SILENT_MIND;break;
    }
    return iReturn;
}


int BeamBattleGetBeam(object oBeamer){
    //however you want to determine a beam

    return BeamBattleRandomBeam();
}


void BeamBattleDoBeams(object oCenter, int iBeam){
    effect eBeam1 = EffectBeam(iBeam, OBJECT_SELF, BODY_NODE_HAND);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBeam1, oCenter, 5.00);
}


// give some other reward
void BeamBattleGetReward(object oWinner, object oLoser){
    //based on level difference between two characters (NOT caster levels)
    int iXPReward = 60 - (10 * (GetHitDice(oWinner) - GetHitDice(oLoser)));
    if (iXPReward < 10)
        iXPReward = 10;
    if (iXPReward >= 100)
        iXPReward = 100;
    GiveXPToCreature(oWinner, iXPReward);

    //custom to dalakora
    object oToken = GetItemPossessedBy(oWinner, "DALA_CONVERTED");
    if(GetIsObjectValid(oToken)){
        int iObsDuelPoints = GetLocalInt(oToken, "OBS_DUEL_POINTS");
        int iLoserLevels = GetSpellcasterLevels(oLoser);
        SetLocalInt(oToken, "OBS_DUEL_POINTS", iObsDuelPoints + iLoserLevels);
    }
}


void BeamBattleExplode(object oCenter, object oLoser, object oWinner){
    effect e = EffectVisualEffect(VFX_FNF_MYSTICAL_EXPLOSION);
//    effect eDamage = EffectDamage(d12(3), DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);
    ApplyEffectAtLocation(DURATION_TYPE_INSTANT, e, GetLocation(oCenter));
//    ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oLoser);
    if(GetIsObjectValid(oLoser)){
        SetCommandable(TRUE, oLoser);
        SetCommandable(TRUE, oWinner);
        effect eKnockdown = ExtraordinaryEffect(EffectKnockdown());
        effect eDispell = ExtraordinaryEffect(EffectDispelMagicAll(100));
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockdown, oLoser, 12.0);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eDispell, oLoser);
    }

    BeamBattleGetReward(oWinner, oLoser);
    DestroyObject(oCenter, 0.25);
}


object BeamBattleCalculateRoundLoser(object oCaster, object oTarget){
    int iCasterScore;
    int iTargetScore;

    //this is where we determine where the beam moves
    int iSpellCraftCaster = GetSkillRank(SKILL_SPELLCRAFT, oCaster, FALSE);
    int iSpellCraftTarget = GetSkillRank(SKILL_SPELLCRAFT, oTarget, FALSE);

//    iCasterScore = d20() + 1;
//    iTargetScore = d20();



    // custom to dalakora
    int iCasterSpellcraft = GetSkillRank(SKILL_SPELLCRAFT, oCaster, FALSE);
    int iTargetSpellcraft = GetSkillRank(SKILL_SPELLCRAFT, oTarget, FALSE);

    int iCasterInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oCaster);
    int iTargetInt = GetAbilityModifier(ABILITY_INTELLIGENCE, oTarget);

    object oToken = GetItemPossessedBy(oCaster, "DALA_CONVERTED");
    int iObsDuelPoints = GetLocalInt(oToken, "OBS_DUEL_POINTS");
    int iCasterBonus = iObsDuelPoints/500;

//    int iTargetBonus = FloatToInt(GetChallengeRating(oTarget)) + 1;

    int iCasterLevels = GetSpellcasterLevels(oCaster);
    int iTargetLevels = GetSpellcasterLevels(oTarget);


    iCasterScore = iCasterSpellcraft + iCasterInt + iCasterBonus + iCasterLevels + d20();
    iTargetScore = iTargetSpellcraft + iTargetInt + iTargetLevels;

    if(DEBUG){
        SendMessageToPC(oCaster, "iCasterSpellcraft: " + IntToString(iCasterSpellcraft));
        SendMessageToPC(oCaster, "iCasterInt: " + IntToString(iCasterInt));
        SendMessageToPC(oCaster, "iCasterBonus: " + IntToString(iCasterBonus));
        SendMessageToPC(oCaster, "iCasterLevels: " + IntToString(iCasterLevels));
        SendMessageToPC(oCaster, "iTargetSpellcraft: " + IntToString(iTargetSpellcraft));
        SendMessageToPC(oCaster, "iTargetInt: " + IntToString(iTargetInt));
//        SendMessageToPC(oCaster, "iTargetBonus: " + IntToString(iTargetBonus));
        SendMessageToPC(oCaster, "iTargetLevels: " + IntToString(iTargetLevels));
        SendMessageToPC(oCaster, IntToString(iCasterScore) + " :  " + IntToString(iTargetScore));
    }

    // end custom
    if(iCasterScore >= iTargetScore){
        return oTarget;
    }else{
        return oCaster;
    }
}


void BeamBattleMoveCenter(object oCaster, object oTarget, object oCenter){
    object oLoser = BeamBattleCalculateRoundLoser(oCaster, oTarget);

    float fStopAt = GetDistanceBetween(oCenter, oLoser) - fStepIncrement;
    AssignCommand(oCenter, ActionForceMoveToObject(oLoser, FALSE, fStopAt, fLoopTime));
}


void BeamBattlePseudoLoop(object oCaster, object oTarget, object oCenter, int iBeam1, int iBeam2){
    float fCasterDist;
    float fTargetDist;

    AssignCommand(oCaster, BeamBattleDoBeams(oCenter, iBeam1));
    AssignCommand(oTarget, BeamBattleDoBeams(oCenter, iBeam2));

    fCasterDist = GetDistanceBetween(OBJECT_SELF, oCaster);
    fTargetDist = GetDistanceBetween(OBJECT_SELF, oTarget);

    fTimeElapsed += fLoopTime;

    int iKill = FALSE;
    if(fCasterDist <= 2.75){
        AssignCommand(oTarget, BeamBattleExplode(oCenter, oCaster, oTarget));
        iKill = TRUE;
    }
    if(fTargetDist <= 2.75){
        AssignCommand(oCaster, BeamBattleExplode(oCenter, oTarget, oCaster));
        iKill = TRUE;
    }
    if(fBeamBattleMaxLen < fTimeElapsed){
        iKill = TRUE;
    }
    if(iKill == TRUE){
        SetCommandable(TRUE, oCaster);
        SetCommandable(TRUE, oTarget);

        SetLocalInt(oCaster, "DUELING", 0);
        SetLocalInt(oTarget, "DUELING", 0);
        DestroyObject(OBJECT_SELF, 0.25);
        return;
    }

    AssignCommand(oCenter, BeamBattleMoveCenter(oCaster, oTarget, oCenter));
    DelayCommand(fLoopTime, BeamBattlePseudoLoop(oCaster, oTarget, oCenter, iBeam1, iBeam2));
}


void BeamBattleDoPseudoLoop(object oCaster, object oTarget, object oCenter){
    int i1, i2;
    i1 = BeamBattleGetBeam(oCaster);
    i2 = BeamBattleGetBeam(oTarget);

    AssignCommand(oCenter, BeamBattlePseudoLoop(oCaster, oTarget, oCenter, i1, i2));
}


object BeamBattleMakeMiddle(object oCaster,object oTarget){
    vector v1 = GetPosition(oCaster);
    vector v2 = GetPosition(oTarget);
    float fDist = GetDistanceBetween(oCaster, oTarget);
    location l = GenerateNewLocation(oCaster, fDist/2, GetFacing(oCaster), GetFacing(oCaster));
    object oCenter = CreateObject(OBJECT_TYPE_CREATURE, "beam_intersec", l, FALSE, "duel_center");
    effect eStart = EffectVisualEffect(2155);
    effect eStart2 = EffectCutsceneGhost();
    effect eSlow = EffectSlow();
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSlow, oCenter);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStart2, oCenter);
    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStart, oCenter);
    SetName(oCenter, " ");
    SetImmortal(oCenter, TRUE);
    SetIsTemporaryNeutral(oCaster, oCenter);
    SetIsTemporaryNeutral(oTarget, oCenter);
//    AssignCommand(oCenter, SpeakString("Starting Duel"));

    return oCenter;
}


string BeamBattleGetRandomSpeak(){
    string sReturn = "";

    switch(d6()){
        case 1: sReturn = "By the gods!"; break;
        case 2: sReturn = "Amazing!"; break;
        case 3: sReturn = "Such power to behold!"; break;
        case 4: sReturn = "Look at that!"; break;
        case 5: sReturn = "I'm not worthy!"; break;
        case 6: sReturn = "Aaaaahhhhhhh!"; break;
    }
    return sReturn;
}


int BeamBattleStart(object oCaster, object oTarget){
    if(GetLocalInt(oTarget,"DUELING")){
        SendMessageToPC(oCaster, "Target already engaged in a duel.");
        return -1;
    }
    if(GetLocalInt(oCaster,"DUELING")){
        SendMessageToPC(oCaster, "You are already engaged in a duel.");
        return -1;
    }

    float fDistance = GetDistanceBetween(oCaster, oTarget);
    if(fDistance < fMinDist){
        SendMessageToPC(oCaster, "You are too close to your target.");
        return -1;
    }
    if(fMaxDist < fDistance){
        SendMessageToPC(oCaster, "You are too far from your target.");
        return -1;
    }

    SetLocalInt(oCaster, "DUELING", 1);
    SetLocalInt(oTarget, "DUELING", 1);

    //Place the duel points
    vector v1 = GetPosition(oCaster);
    vector v2 = GetPosition(oTarget);
    AssignCommand(oCaster, SetFacingPoint(v2));
    AssignCommand(oTarget, SetFacingPoint(v1));

    DelayCommand(0.1, SetCommandable(FALSE, oCaster));
    DelayCommand(0.1, SetCommandable(FALSE, oTarget));
    DelayCommand(fBeamBattleMaxLen, SetCommandable(TRUE, oCaster));
    DelayCommand(fBeamBattleMaxLen, SetCommandable(TRUE, oTarget));

    object oCenter = BeamBattleMakeMiddle(oCaster, oTarget);

    object oSpectator = GetFirstObjectInShape(SHAPE_SPHERE, fSpectatorSize, GetLocation(oCenter), TRUE, OBJECT_TYPE_CREATURE);
    while(GetIsObjectValid(oSpectator)){
        if((oSpectator == oCenter) || (oSpectator == oCaster) || (oSpectator == oTarget)){
        }else{
            AssignCommand(oSpectator, ClearAllActions());
            AssignCommand(oSpectator, SetFacingPoint(GetPosition(oCenter)));
            string sSpeak = BeamBattleGetRandomSpeak();
            AssignCommand(oSpectator, ActionSpeakString(sSpeak));
            DelayCommand(0.1, SetCommandable(FALSE, oSpectator));
            DelayCommand(fBeamBattleStunnedTime, SetCommandable(TRUE, oSpectator));
        }
        oSpectator = GetNextObjectInShape(SHAPE_SPHERE, fSpectatorSize, GetLocation(oCenter));
    }

    BeamBattleDoPseudoLoop(oCaster, oTarget, oCenter);

    return 0; 
}

PS: you'd think that the "code" formatting blocks would understand that spaces are important for code formatting.


basically, you just call the BeamBattleStart() with the two objects.  mine is being called from an onActivateItem.  people will need a center creature, whose resref is "beam_intersec".
               
               

               


                     Modifié par acomputerdood, 24 août 2012 - 12:26 .