• Welcome to Freedom Reborn Archive.
 

New Attribute: Free Spirit

Started by TaskMasterX, August 06, 2007, 02:04:38 PM

Previous topic - Next topic

TaskMasterX

I got this idea for an attribute from the Marvel character, Brother Voodoo. His body is host to his dead brother's spirit which he can release at will to help him. His brother's spirit can then possess other people.
How It Works:
What I came up with is kind of a cross between Astral Projection and Summoning. The character with this attribute begins the mission with two commands: Release Spirit and Leave Host. They both do basically the same thing except which one you click on determines which one you control after the seperation. Clicking Release Spirit causes the spirit to spawn at the character's spot and you maintain control over the host while M25's AI then takes control of the Spirit and vice versa with choosing the Leave Host command. When the Spirit is released, the Host loses 1 point of Strength and Endurance until the Spirit is merged back with the host. The Spirit is a hero file that you make and put into the customization array. Unlike Astral Projection, you don't need to have another attribute like Astral Form for the Spirit. Just put in the name in the customization array. Also, the spirit automatically gets flight and permanent pass-thru defense, like the Astral Form does or the illusions for the Illusionist attribute, so when making the hero file for the Spirit, you don't need to add these things.
You have a command to merge back whenever you want (the command appears on the Host if you're controlling the Spirit and on the Spirit of controlling the Host).
If the Spirit dies then the Host is stunned for 10 seconds. If the Host dies, then so does the Spirit.

Here's the code for ffx.py along with example lines for the strings.txt
################################# FREE SPIRIT #########################################################
# You can release a free-roaming spirit that resides within you that you can call forth to aid you.
# -TaskmasterX
# ATTRIB_FREESPIRIT_01, free spirit
# ATTRIB_FREESPIRIT_DESC_01, your body is host to a free-roaming spirit that you can release to aid you.
# RELEASE_SPIRIT_01, release spirit
# RELEASE_SPIRIT_DESC_01, temporarily release the free-roaming spirit within you
# LEAVE_HOST_01, leave host
# LEAVE_HOST_DESC_01, temporarily leave your host to aid them in the material world
# CUSTOM_RETURN_TO_HOST_01, return to host
# CUSTOM_RETURN_TO_HOST_DESC_01, return the spirit to the host
# CUSTOM_RETURN_SPIRIT_01, recall spirit
# CUSTOM_RETURN_SPIRIT_DESC_01, return the spirit to the host
########################################################################################################

def initfreespirit(char,update=0):
    if isMP():
        return
    if update==0:
        if not FFX_ObjectGetAttr(char,'free_spirit'):
            Mission_CustomAction('RELEASE_SPIRIT',char,char,'OnReleaseSpirit',4,0)
            Mission_CustomAction('LEAVE_HOST',char,char,'OnLeaveHost',4,0)

def OnReleaseSpirit(dummy,char):
    AI_Animate(char,getByTemplate(char,FFX_FREESPIRIT_CUSTOM,2),'OnReleaseSpirit2')
    FFX_ObjectSetAttr(char,'release_spirit',1)

def OnLeaveHost(dummy,char):
    AI_Animate(char,getByTemplate(char,FFX_FREESPIRIT_CUSTOM,2),'OnReleaseSpirit2')
    FFX_ObjectSetAttr(char,'leave_host',1)

def OnReleaseSpirit2(event):
    char=event.object
    spiritFX(char)
    name=getFormName()
    spiritTemplate=getByTemplate(char,FFX_FREESPIRIT_CUSTOM,1)
    OnDrop(char,char)
    if spiritTemplate=='':
        spiritTemplate=Object_GetTemplate(char)
    FFX_Spawn(name,spiritTemplate,char)
    FFX_ObjectSetAttr(name,'morph',1)
    FFX_ObjectSetAttr(name,'free_spirit',1)
    if FFX_ObjectGetAttr(char,'release_spirit')==1:
        FFX_AdjustPortrait(char,1)
        FFX_AdjustPortrait(name,0)
    if FFX_ObjectGetAttr(char,'leave_host')==1:
        FFX_AdjustPortrait(char,0)
    makeIllusion(name,1)
    RegTimer('removeFX',0.5,3,name)
    RegTimer('OnReleaseSpirit3',1,0,char,name)

def OnReleaseSpirit3(event):
    char=event.object
    name=event.string
    maxHP=Object_GetAttr(char,'maxHealth')
    hp=Object_GetAttr(char,'health')
    FFX_ObjectSetAttr(char,'fsMaxHP',maxHP)
    endBonus = -1
    newMaxHP=getAdjustedHealth(char,endBonus)
    Object_SetAttr(char,'maxHealth',newMaxHP)
    newMaxHPa = newMaxHP * 100
    pctLoss1 = newMaxHPa / maxHP
    pctLoss2 = pctLoss1 / 100
    newHP = hp * pctLoss2
    Object_SetAttr(char,'health',newHP)
    str=Object_GetAttr(char,'templateStrength')-1
    Object_SetAttr(char,'strength',str)
    Object_SetAttr(char,'baseStrength',str)
    if FFX_ObjectGetAttr(char,'release_spirit')==1:
        m25ai.ClearAIStandardOnly(name)
        m25ai.AIEnableWatch(name)
        m25ai.AIEnable(name)
        m25ai.AIEnableCustom(name)
        m25ai.SetBrawler(name)
        Mission_SelectHero(char)
        Mission_CustomAction('CUSTOM_RETURN_SPIRIT',char,name,'OnSpiritReturn',0,0)
        Mission_CustomAction('CUSTOM_TRANSFER',char,name,'OnTransferFromHost',100,0)
    if FFX_ObjectGetAttr(char,'leave_host')==1:
        m25ai.ClearAIStandardOnly(char)
        m25ai.AIEnableWatch(char)
        m25ai.AIEnable(char)
        m25ai.AIEnableCustom(char)
        m25ai.SetBrawler(char)
        Mission_SelectHero(name)
        Mission_CustomAction('CUSTOM_RETURN_TO_HOST',name,char,'OnSpiritReturn',0,0)
        Mission_CustomAction('CUSTOM_TRANSFER',name,char,'OnTransferFromSpirit',100,0)
    Mission_RemoveCustomAction('RELEASE_SPIRIT',char,char)
    Mission_RemoveCustomAction('LEAVE_HOST',char,char)
    RegTimer('SpiritLink',1,0,name,char)

def OnTransferFromSpirit(target,char):
    if FFX_ObjectGetAttr(char,'free_spirit')==1:
        FFX_AdjustPortrait(char,0)
        RegTimer('OnSpiritReturn2',0.1,0,target)
        m25ai.SetAIStandardOnly(target)
        m25ai.AIDisableWatch(target)
        m25ai.AIDisableCustom(target)
        m25ai.ClearAIStandardOnly(char)
        m25ai.AIEnableWatch(char)
        m25ai.AIEnable(char)
        m25ai.AIEnableCustom(char)
        m25ai.SetBrawler(char)
        Mission_RemoveCustomAction('CUSTOM_TRANSFER',char,target)
        Mission_RemoveCustomAction('CUSTOM_RETURN_TO_HOST',char,target)
        Mission_CustomAction('CUSTOM_RETURN_SPIRIT',target,char,'OnSpiritReturn',0,0)
        Mission_CustomAction('CUSTOM_TRANSFER',target,char,'OnTransferFromHost',100,0)

def OnTransferFromHost(char,target):
    FFX_AdjustPortrait(target,0)
    RegTimer('OnSpiritReturn2',0.1,0,char)
    m25ai.SetAIStandardOnly(char)
    m25ai.AIDisableWatch(char)
    m25ai.AIDisableCustom(char)
    m25ai.ClearAIStandardOnly(target)
    m25ai.AIEnableWatch(target)
    m25ai.AIEnable(target)
    m25ai.AIEnableCustom(target)
    m25ai.SetBrawler(target)
    Mission_RemoveCustomAction('CUSTOM_TRANSFER',target,char)
    Mission_RemoveCustomAction('CUSTOM_RETURN_SPIRIT',target,char)
    Mission_CustomAction('CUSTOM_RETURN_TO_HOST',char,target,'OnSpiritReturn',0,0)
    Mission_CustomAction('CUSTOM_TRANSFER',char,target,'OnTransferFromSpirit',100,0)

def OnSpiritReturn(target,char):
    spiritFX(target)
    spiritFX(char)
    if FFX_ObjectGetAttr(char,'free_spirit')==1:
        FFX_AdjustPortrait(char,0)
        RegTimer('destroyTemp',1,0,char)
        RegTimer('OnSpiritReturn2',0.1,0,target)
        normalize(target)
        maxHP=Object_GetAttr(target,'maxHealth')
        hp=Object_GetAttr(target,'health')
        oldmaxHP=FFX_ObjectGetAttr(target,'fsMaxHP')
        Object_SetAttr(target,'maxHealth',oldmaxHP)
        newMaxHPa = oldmaxHP * 100
        pctGain = newMaxHPa / maxHP
        hpBonus = pctGain / 100
        newHP = hp * hpBonus
        Object_SetAttr(target,'health',newHP)
        str=Object_GetAttr(target,'templateStrength')
        Object_SetAttr(target,'strength',str)
        Object_SetAttr(target,'baseStrength',str)
        m25ai.SetAIStandardOnly(target)
        m25ai.AIDisableWatch(target)
        m25ai.AIDisableCustom(target)
        FFX_ObjectSetAttr(target,'leave_host',0)
        FFX_ObjectSetAttr(target,'release_spirit',0)
        Mission_RemoveCustomAction('CUSTOM_RETURN_SPIRIT',target,char)
        Mission_CustomAction('RELEASE_SPIRIT',target,target,'OnReleaseSpirit',4,0)
        Mission_CustomAction('LEAVE_HOST',target,target,'OnLeaveHost',4,0)
        return
    FFX_AdjustPortrait(target,0)
    RegTimer('destroyTemp',1,0,target)
    RegTimer('OnSpiritReturn2',0.1,0,char)
    normalize(char)
    maxHP=Object_GetAttr(char,'maxHealth')
    hp=Object_GetAttr(char,'health')
    oldmaxHP=FFX_ObjectGetAttr(char,'fsMaxHP')
    Object_SetAttr(char,'maxHealth',oldmaxHP)
    newMaxHPa = oldmaxHP * 100
    pctGain = newMaxHPa / maxHP
    hpBonus = pctGain / 100
    newHP = hp * hpBonus
    Object_SetAttr(char,'health',newHP)
    str=Object_GetAttr(char,'templateStrength')
    Object_SetAttr(char,'strength',str)
    Object_SetAttr(char,'baseStrength',str)
    FFX_ObjectSetAttr(char,'leave_host',0)
    FFX_ObjectSetAttr(char,'release_spirit',0)
    Mission_RemoveCustomAction('CUSTOM_RETURN_SPIRIT',char,target)
    Mission_CustomAction('RELEASE_SPIRIT',char,char,'OnReleaseSpirit',4,0)
    Mission_CustomAction('LEAVE_HOST',char,char,'OnLeaveHost',4,0)

def OnSpiritReturn2(event):
    target=event.object
    FFX_AdjustPortrait(target,1)
    Mission_SelectHero(target)

def spiritFX(shell):
    fx=getByTemplate(shell,FFX_FREESPIRIT_CUSTOM,3)
    if fx!='':
        Object_PlayEffect(shell,fx)

def SpiritLink(event):
    c1=event.object
    c2=event.string
    if Object_Exists(c1) & Object_Exists(c2):
        l1=Object_IsAlive(c1)
        l2=Object_IsAlive(c2)
        if l1 and not l2:
            cshelper.kill(c1)
        if l2 and not l1:
            Object_SetPrimaryState(c2,PCSTATE_STUNNED,10)
            return
        RegTimer('SpiritLink',1,0,c1,c2)

def getAdjustedHealth(char,endBonus):
    baseEnd = GetCharacterData(char)['endurance']+endBonus
    if Object_GetClass(char) & OC_CONTROLLABLE:
        return int (( baseEnd**2 + baseEnd + 2 ) * 5 )
    else:
        diff6health = (15,30,60,105,165,480,660,870,1110,1380)
        diffdiv = (0, 9, 4, 3, 2, 1.5, 1, 0)
        return int(diff6health[baseEnd]/diffdiv[int(ff.RPG_GAME_DIFFICULTY)] )


...and here's the code for the customization you put in ffxcustom2.py
### Free Spirit
FFX_FREESPIRIT_CUSTOM=[
["default","","ranged","effect_pan_teleport"],
["types","USpirit Form","AAnimation","EFX"],
["brother voodoo","brother voodoo-brother","ranged","effect_pan_teleport"],
]

1st is the name of the character with the Free Spirit attribute, followed by the hero file name of the spirit. 3rd is the animation the Host uses to release the Spirit and last is the FX that plays with release.

Epimethee

Very nice. :)

If you have less than four squad members, you still don't control both directly, right?

BTW, maybe a command on the alternate character to switch player control would be a good feature.

TaskMasterX

Excellent idea, Ep! Thanks! I did notice that when the AI controlled Spirit possesses a target the target comes under the control of the player and when the spirit leaves the target, it's now under the control of the player. And I noticed that when I played the Spirit and possessed a target, the host would attack me! Hmmm.... :huh:

TaskMasterX

Okay, I updated the above code. I found a few problem areas and fixed them and also added in Ep's suggestion to be able to switch control back and forth between the host and spirit.

crocodamon

Hi task i am a newbie, what am i need to do to install this atributes on my  :ffvstr: or FFX3.2 ?

catwhowalksbyhimself

Copy and paste the code into the files in missions/script indicated above each code segment.

TaskMasterX

Hi Croc! You do need  :ffvstr: and FFX 3.2 for this attribute.
Go to your C:\<Game Folder>\ffx3\Missions\Scripts folder and open the ffx.py file with Notepad.
Scroll down to the bottom of the file and copy that large block of code from the first post above and paste it into the space right above where you see this:
######################################################################
##
## FFX FOOTER:
## FunctionWrapper import
##
######################################################################

Save and close the file.
Then open the ffxcustom2.py file, which is in the same folder as the ffx.py file, again with Notepad.
Copy and paste that small block of code to the bottom of that file.
Save and close.
Open FFEdit and click the Attributes tab.
Click the New button and type the name freespirit.
Give it a cost, 500 or 600 should be good enough.
Click the Save button and close FFEdit.
At this point the attribute should work. But the attribute will look like ATTRIB_FREESPIRIT in the Attributes List in the game and won't have a description. Nor will you have descriptions for the commands. To get those you'll need to do this:
Go to the C:\<Game Folder>\ffx3\Lang\English folder and open the strings.txt file.
Copy and paste this:
ATTRIB_FREESPIRIT_01, free spirit
ATTRIB_FREESPIRIT_DESC_01, your body is host to a free-roaming spirit that you can release to aid you.
RELEASE_SPIRIT_01, release spirit
RELEASE_SPIRIT_DESC_01, temporarily release the free-roaming spirit within you
LEAVE_HOST_01, leave host
LEAVE_HOST_DESC_01, temporarily leave your host to aid them in the material world
CUSTOM_RETURN_TO_HOST_01, return to host
CUSTOM_RETURN_TO_HOST_DESC_01, return the spirit to the host
CUSTOM_RETURN_SPIRIT_01, recall spirit
CUSTOM_RETURN_SPIRIT_DESC_01, return the spirit to the host

...to the bottom of that file.
Save and close the file.
Open FFEdit and make sure you scroll down to the bottom of the FFEdit page (if it isn't already) so you can see the blank grey line at the bottom. Click the Generate Language Files button. You'll see the blank line now saying that it's generating your language files. This can take a while. It may be done quick or it may take 15-20 minutes to complete. So, be patient. When the line is blank again, it's finished. Load the game up and try it out.

Installing new attributes basically always follows these same steps.
1.) copy and paste the main code to ffx.py and then any other code that needs to be copied to other files.
2.) create the new attribute and give it a cost in FFEdit.
3.) Create and then generate the text strings for the descriptions of the attribute and any commands the attribute may give the character.

Hope that helps!