Freedom Reborn Archive

Freedom Force Forums => Scripting Forum => Topic started by: Mystik on December 08, 2007, 07:45:53 PM

Title: Attribute similar to DRIVER? (was: attribute request)
Post by: Mystik on December 08, 2007, 07:45:53 PM
I am humbly requesting an attribute that is similar to driver attribute but is made for bikes/mounts/and vehicles that show the hero from the outside

basically what I'm hoping for is an attribute that is basically a fusion
e.g: robin does a custom action on bike mesh- bike mesh and robin disappear-robin on bike mesh spawns

this would be useful for he-man and his battle cat or the black knight
Title: Re: attribute request
Post by: BentonGrey on December 08, 2007, 09:02:14 PM
I haven't had a chance to mess with the Driver attribute yet (another thing I need to do over the break), but wouldn't that be possible already?  There has to be an object and a character version of each vehicle, right?  Can't you just give them different meshes?
Title: Re: attribute request
Post by: Mystik on December 08, 2007, 09:09:00 PM
no theres just a character and a vehicle
Title: Re: attribute request
Post by: BentonGrey on December 08, 2007, 10:16:55 PM
Hmm, well, in that case, I definitely second this.
Title: Re: attribute request
Post by: Epimethee on December 09, 2007, 07:32:58 AM
Noted.

It's not the first time the request pops up (it was asked for Green Gobin and his flier a couple of years ago IIRC). Maybe it could also be used for a "Gestalt" attribute.

Hopefully, though, somebody else will tackle this before I do, as won't be able to commit to it for a while. :/
Title: Re: attribute request
Post by: C4 on December 09, 2007, 10:10:25 PM
I am doing this already for my mod. so I can just as well release the code.

By the weekend.
Title: Re: attribute request
Post by: Epimethee on December 10, 2007, 04:59:15 PM
C4 is back FFXing! :D
Title: Re: attribute request
Post by: GGiant on December 11, 2007, 12:19:54 AM
One option is TR and Epimethee's driver attribute with a skoped mesh of robin on a bike.
Although that's off topic, It's much easier than scripting though I'd go with C4 on this one.
*edited*
Title: Re: attribute request
Post by: C4 on December 11, 2007, 10:17:43 PM
Quote[C4 is back FFXing!

Heh just like good old times  ;) Now Dr Mike must just script again ^_^

QuoteOne option is TR and Epimethee's driver attribute with a skoped mesh of robin on a bike.
Although that's off topic, It's much easier than scripting though I'd go with C4 on this one.

Yes that is what Thor wants to do but in order to make that happen additions to the code will have to be made.
Title: Re: attribute request
Post by: BentonGrey on January 05, 2008, 03:05:12 PM
Did this ever get released?
Title: Re: attribute request
Post by: C4 on January 06, 2008, 04:14:35 AM
No. I could not test anything on vacation. Give me a week and I should have it done.
Title: Re: attribute request
Post by: BentonGrey on January 06, 2008, 11:19:44 AM
Thanks C4!
Title: Re: attribute request
Post by: Mystik on January 30, 2008, 07:43:42 PM
bump
Title: Re: attribute request
Post by: Mystik on March 23, 2008, 01:11:32 PM
bump just finished a ton of skopes waiting for this attribute
Title: Re: attribute request
Post by: BentonGrey on March 23, 2008, 05:24:19 PM
Yep!
Title: Re: attribute request
Post by: C4 on March 24, 2008, 11:47:48 PM
Yes this has been way to long. My project is keeping me so busy.

I will make sure to force myself to finish this.
Title: Re: attribute request
Post by: Mystik on April 17, 2008, 01:58:01 PM
(looks at watch)
Title: Re: attribute request
Post by: Epimethee on April 17, 2008, 08:09:59 PM
We're working on it. Slowly.

Hoping to pull it off.
Title: Re: attribute request
Post by: Mystik on April 20, 2008, 04:03:13 PM
thanx guys
I am grateful for the effort
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: stumpy on April 21, 2008, 03:44:30 AM
(I renamed the thread so that people didn't get the idea that this was a generic attribute request thread.)
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: Epimethee on April 27, 2008, 07:04:36 PM
Done.  ^_^

This is a variant on Shapshifter/Temporary Form. You create two characters with the attributes: the Gestalt, which is your shapeshifter, and the Amalgam, which is your temporary form. The Gestalt needs to touch (using a custom command) another character or an object to transform into the Amalgam.

The attribute requires changing code in different place, though, so rather than add it manually, you may wish to wait until the next FFX update. Otherwise, don't forget to back up first. ;)

In FFEdit, add the following attributes:
ffqamalgam (cost: -7000)
ffqgestalt (cost: 400)

In strings.txt, add:
ATTRIB_FFQAMALGAM_01, amalgam
ATTRIB_FFQAMALGAM_DESC_01, (not multiplayable) this character is just a temporary form assumed by a GESTALT, and cannot be selected in the squad.
ATTRIB_FFQGESTALT_01, gestalt
ATTRIB_FFQGESTALT_DESC_01, (not multiplayable) you are able to switch between two or more forms by merging with a specific object or person.
CUSTOM_FFQGESTALTMERGE_01, merge
CUSTOM_FFQGESTALTMERGE_DESC_01, amalgam yourself with this target
CUSTOM_FFQGESTALTREVERT_01, revert
CUSTOM_FFQGESTALTREVERT_DESC_01, split this amalgam

and compile the language files using FFEdit or M25's tool.

In ffxcustom2.py, add:
### Gestalt/Amalgam
FFX_FFQGESTALT_CUSTOM=[
["default", "effect_entropy_spawn", "", "", "", "", "", ""],
["types", "EEffect", "ATarget 1", "ANew Form 1", "ATarget 2", "ANew Form 2", "ATarget 3", "ANew Form 3" ],
]

FFX_FFQAMALGAM_CUSTOM=[
["default", "effect_entropy_spawn", "power", "isNever"],
["types", "EEffect", "AAnimation", "fRevert Trigger"],
]

For the attribute to work, you MUST create an FFX_FFQGESTALT_CUSTOM entry for your character. The Gestalt attribute customization allows a character up to three targets, with each having a specific Amalgam. For example:
### Gestalt/Amalgam
FFX_FFQGESTALT_CUSTOM=[
["default", "effect_entropy_spawn", "", "", "", "", "", ""],
["types", "EEffect", "ATarget 1", "ANew Form 1", "ATarget 2", "ANew Form 2", "ATarget 3", "ANew Form 3" ],
["don_blake", "effect_ffx_thunder", "stick", "thor", "", "", "", ""],
["wraith_warrior_gestalt", "effect_entropy_spawn", "subterrestrial", "wraith_manta_amalgam", "", "", "", ""],
["batman", "effect_paper", "batglider_object", "batglider_amalgam", "batcycle_object", "batcycle_amalgam", "", ""],
["symbiote", "effect_ffx_evil", "civilian_male", "venom", "civilian_female", "carnage", "cop", "venom"],
]

FFX_FFQAMALGAM_CUSTOM=[
["default", "effect_entropy_spawn", "power", "isNever"],
["types", "EEffect", "AAnimation", "fRevert Trigger"],
["thor", "effect_ffx_thunder", "power", "isExiled"],
["wraith_manta_amalgam", "effect_entropy_spawn", "power", "isPowerNulled"],
]




in ffx.py, do the following changes:
add:
# Given a character template name, returns the Rumble Room "custom_template_n" name if present in the current mission.
# Returns None if not found.
# Added FFX 3.3 pre-alpha - Ep.
def getCustomTemplateName(realTemplateName):
    for object in Mission_GetDynamicObjects():
        if Object_GetTemplate(object)[0:7] == 'custom_':
            if FFX_GetTemplate(object) == realTemplateName:
                return Object_GetTemplate(object)
    return None


change the first line under the morph() function:
def morph(name,char,template,proportional=0,hasPortrait=1):
    morphVars=['shapeRow','ffqgestaltRow','originalIndex','shots0','shots1','shots2','shots3'] #Ep. 2008-04-20: added ffqgestaltRow for said attribute
(etc.)


replace the existing getMorphFX():
def getMorphFX(char):
    name=FFX_GetTemplate(char)
    fx='effect_entropy_spawn'
    for set in FFX_SHAPESHIFT_CUSTOM:
        if set[0]==name:
            fx=set[1]
    for set in FFX_TEMPFORM_CUSTOM:
        if set[0]==name:
            fx=set[1]
    for set in FFX_MIMIC_CUSTOM:
        if set[0]==name:
            fx=set[1]
    for set in FFX_FFQGESTALT_CUSTOM:
        if set[0]==name:
            fx=set[1]
    return fx


replace the existing initAttribs():
def initAttribs(event):
    #identify which heros have the 'modified' attributes
    #do all tempforms first so we can fill in the default arrays
    for object in js.Mission_GetDynamicObjects():
        if (Object_GetClass(object) & FFX_CHARACTER):
            if (hasAttribute(object,'tempform')!=0) | (hasAttribute(object,'involuntaryform')!=0) | (hasAttribute(object,'ffqamalgam')!=0):
                object=initialiseChar(object)
    for object in js.Mission_GetDynamicObjects():
        if (Object_GetClass(object) & FFX_CHARACTER):
            if (hasAttribute(object,'tempform')==0) & (hasAttribute(object,'involuntaryform')==0) | (hasAttribute(object,'ffqamalgam')!=0):
                object=initialiseChar(object)
    RegTimer('updateAttribs5',0.5)
    RegTimer('updateFFX',1)
    RegTimer('updateStates',1.25)


replace the existing tempCheck():
def tempCheck(event):
    name=event.object
    #stops them doing melee idle in front of villains
    cshelper.disable(name)
    if hasAttribute(name,'tempform') | hasAttribute(name,'involuntaryform') | (hasAttribute(object,'ffqamalgam')!=0):
        Object_Destroy(name)


update Power Analysis' attrDesc list:
attrDesc=[
['flier','levitation','ffqglider','ffqbasiclevitation','ffqlowgravflier','flight'],
['heavy lifter','superstrength'],
['claws','bladed weapon'],
['telepathy','powerscan','enhanced senses'],
['shapeshifter','accidentalchange','ffqgestalt','involuntaryform','tempform','ffqamalgam','metamorphic','icecloud','gaseousform','sandstorm','shapeshifting'],
['groupteleporter','bulktp','teleportation'],
['tough guy','invulnerable','invulnerable0','invulnerable2','invulnerable22a34','invulnerable2a','invulnerable3','invulnerable34','invulnerable4','invulnerability'],
['puppetn','puppetu','transmutation'],
['spinner','superspeed'],
['telekinetic','supertk','earthcontrol','telekinesis'],
['masscontrol','density-modulation'],
['illusionist','image-projection'],
]


and finally, add the attributes code:
####################### GESTALT/AMALGAM #################################
# You can change into amalgamed temporary forms by merging with specific character templates or common objects.
# - If the target is an enemy character, this power can only be used once per specific target *object* (not template),
#   even if using different Gestalt characters.
# - If the Amalgam is KO'ed, the Gestalt source character is too, but not the target.
# - If the target has moved too far, the command won't work.
# - Both attributes are removable. Removing the Amalgam attribute reverts the character to his base Gestalt form;
#   however, the Gestalt attribute will stil be functional and will need to be disabled separately.

# Ripped off Dr. Mike's Shapeshifter and Accidental Change code.
# The following functions and constants have been changed to work with Gestalt:
# - morph()
# - getMorphFX()
# - tempCheck()
# - initAttribs()
# - attrDesc list
# - added getCustomTemplateName()

# v. 1.0
# Added FFX 3.3 pre-alpha
# TO DO:
# - Add AI (good luck with that...)

def initffqgestalt(char, update=0, remove=0):
    if isMP():
        return
    if remove:
        if not FFX_ObjectGetAttr(char, 'ffqgestalt'):
            return
        FFX_ObjectSetAttr(char, 'ffqgestalt', 0)
        for i in (2, 4, 6):
            target = getByTemplate(char, FFX_FFQGESTALT_CUSTOM, i)
            if target != '':
                Mission_RemoveCustomAction('CUSTOM_FFQGESTALTMERGE', char, target)
                #custom action for RR's custom_template_n target characters
                targetRealName = getCustomTemplateName(target)
                if targetRealName != None:
                    Mission_RemoveCustomAction('CUSTOM_FFQGESTALTMERGE', char, targetRealName)
        return
    if FFX_ObjectGetAttr(char, 'ffqgestalt'):
        return
    FFX_ObjectSetAttr(char, 'ffqgestalt', 1)
    #store the original row
    for i in (3, 5, 7):
        form = getByTemplate(char, FFX_FFQGESTALT_CUSTOM, i)
        target = getByTemplate(char, FFX_FFQGESTALT_CUSTOM, i-1)
        if not '' in (form, target):
            action='OnFFQGestaltForm%i'%(i)
            Mission_CustomAction('CUSTOM_FFQGESTALTMERGE', char, target, action, 3, 0)
            #custom action for RR's custom_template_n target characters
            targetRealName = getCustomTemplateName(target)
            if targetRealName != None:
                Mission_CustomAction('CUSTOM_FFQGESTALTMERGE', char, targetRealName, action, 3, 0)
    #store the original row
    template=Object_GetTemplate(char)
    realName=''
    print FFX_FFQGESTALT_CUSTOM
    if template[:6]=='custom':
        realName=FFX_GetTemplate(char)
        newSet=[]
        needToAdd=1
        for set in FFX_FFQGESTALT_CUSTOM:
            if set[0]==realName:
                for entry in set:
                    newSet.append(entry)
            if set[0]==template:
                needToAdd=0
        if needToAdd:
            if len(newSet) > 0:
                newSet[0]=template
            else:
                newSet = FFX_FFQGESTALT_CUSTOM[0][:] #append as a copy to avoid messing with the original data
                newSet[0] = template
            FFX_FFQGESTALT_CUSTOM.append(newSet)
    i=0
    for set in FFX_FFQGESTALT_CUSTOM:
        if (set[0]==template) | (set[0]==realName):
            FFX_ObjectSetAttr(char,'ffqgestaltRow',i)
            break
        i=i+1

def OnFFQGestaltForm3(target, char):
    OnFFQGestaltChange(char, target, 3)

def OnFFQGestaltForm5(target, char):
    OnFFQGestaltChange(char, target, 5)

def OnFFQGestaltForm7(target, char):
    OnFFQGestaltChange(char, target, 7)

def OnFFQGestaltChange(char, target, index):
    print target
    if not Object_Exists(target):
        return
    if isBuilding(target) | ( Object_GetAttr(target, 'minHealth') > 0 ) | ( Object_GetAttr(target, 'physical') == 0 ):
        Mission_StatusText("Invalid target type for Gestalt. You may need to update your FFX Control Centre settings.")
        return
    #if the target is an enemy, has any Gestalt power already been used against this character?
    if FFX_ObjectGetAttr(target, 'ffqgestalt_target', 0):
        Mission_StatusText("This character has become resistant to Gestalt attacks.")
        return
    #is the target still in range or has it moved too far?
    charPos = Get_ObjectPos(char)
    targetPos = Get_ObjectPos(target)
    if ( distance2D(charPos, targetPos) > 60 ):
        Mission_StatusText("Missed! The target has moved away.")
        return
    if chargeEP(char,0)==0:
        return
    #move to the target's position and orientation
    heading = Object_GetOrientation(target)[1]
    teleportToPos(char, targetPos, heading)
    #amalgam identified - let's go! find the original form
    originalForm = FFX_FFQGESTALT_CUSTOM[ int(FFX_ObjectGetAttr(char, 'ffqgestaltRow')) ][0]
    newTemplate = getByTemplate(originalForm, FFX_FFQGESTALT_CUSTOM, index, 1)
    name=getFormName()
    #make the target disappear
    RegTimer("OnFFQGestaltHideTarget", 0.2, 0, target, name)
    morph(name,char,newTemplate,1,1)
   
def OnFFQGestaltHideTarget(event):
    target = event.object
    name = event.string
    #store the amalgam's target component's class type and name
    isCharacter = ( ( Object_GetClass(target) & FFX_CHARACTER ) != 0 )
    missionobjvar.Object_SetVar( name, 'ffqgestalt_target', (isCharacter, FFX_GetTemplate(target), target) )
    #if a character, hide and disable
    if isCharacter:
        Object_SetPrimaryState(target, PCSTATE_EXILE, 10000, 0)
        Object_SetSecondaryState(target, SCSTATE_INVISIBLE, 10000, 0)
        if Object_GetClass(target) & OC_CONTROLLABLE:
            FFX_AdjustPortrait(target, 0)
        AIDisable(target)
        #if the target is an enemy, make the power a one-shot deal against this character
        if not FFQ_isSameSide(name, target):
            FFX_ObjectSetAttr(target, 'ffqgestalt_target', 1)
            RegTimer("OnFFQGestaltTargetEnemy", 15, 0, target)
        FFX_ObjectSetAttr(target, 'ffqgestalt_hidden', 1) #used by OnFFQGestaltTargetEnemy()
    #otherwise, just destroy it
    else:
        Object_Destroy(target)

# If the hidden target(s) is an enemy character and a bad guy, check periodically to see if it's the last standing enemy;
# if it is, display a message to the player once.
def OnFFQGestaltTargetEnemy(event):
    target = event.object
    if not FFX_ObjectGetAttr(target, 'ffqgestalt_hidden'):
        return
    for baddie in cshelper.getAllBaddies(1):
        if not FFX_ObjectGetAttr(baddie, 'ffqgestalt_hidden'):
            RegTimer("OnFFQGestaltTargetEnemy", 15, 0, target)
            return
    #the only bad guys left are gestalt targets; alert the player
    Mission_StatusText("The only enemies left are amalgamed with your Gestalt heroes. Revert to beat them.")
       
   
def initffqamalgam(char,update=0, remove=0):
    global FFX_FFQGESTALT_CUSTOM
    if isMP():
        return
    if remove:
        FFX_ObjectSetAttr(char, 'ffqamalgam', 0)
        FFX_ObjectSetAttr(char, 'ffqgestaltReverting', 1)
        OnFFQAmalgamRevertFromTemp(char, char, 1)
        return
    FFX_ObjectSetAttr(char, 'ffqamalgam', 1)
    #at startup add them into the default slots for gestalt
    if Mission_GetAttr('shapeReady')==0: #shapeReady is used by various attributes
        for hero in cshelper.getAllHeroes():
            if hasAttribute(hero,'ffqgestalt'):
                row=-1
                index=0
                template = Object_GetTemplate(hero)
                for set in FFX_FFQGESTALT_CUSTOM:
                    if set[0] == template:
                        row=index
                    index=index+1
                if row==-1:
                    row=len(FFX_FFQGESTALT_CUSTOM)
                    newSet = FFX_FFQGESTALT_CUSTOM[0]
                    newSet[0] = template
                    FFX_FFQGESTALT_CUSTOM.append(newSet)
                for index in (3, 5, 7):
                    if FFX_FFQGESTALT_CUSTOM[row][index]=='':
                        FFX_FFQGESTALT_CUSTOM[row][index]=Object_GetTemplate(char)
                        break
        RegTimer('destroyTemp',1,0,char)
        return
    #put in a revert command to original form
    Mission_CustomAction('CUSTOM_FFQGESTALTREVERT', char, char, 'OnFFQAmalgamRevertFromTemp', 5, 0)
    #start checking for forced split
    revertFn=getByTemplate(char, FFX_FFQAMALGAM_CUSTOM, 3)
    if revertFn not in ("", "isNever"):
        RegTimer('OnFFQAmalgamForceRevertCheck',1,0,char,revertFn)

def OnFFQAmalgamForceRevertCheck(event):
    char=event.object
    if not Object_Exists(char):
        return
    if FFX_ObjectGetAttr(char,'ffqgestaltReverting',0) != 0:
        return
    #if the amalgam is KO, revert it now, hero points notwistanding
    if not Object_IsAlive(char):
        ffqAmalgamRevertFromTemp(char,char,1)
        return
    fn=event.string
    RegTimer('OnFFQAmalgamForceRevertCheck',1,0,char,fn)
    forceback=0
    code='forceback=%s(char)'%(fn)
    exec code
    if forceback:
        FFX_ObjectSetAttr(char,'ffqgestaltReverting',1)
        OnFFQAmalgamRevertFromTemp(char,char,1)

def OnFFQAmalgamRevertFromTemp(dummy,char,forced=0):
    if forced==0:
        if chargeEP(char,0)==0:
            return
    row=int(FFX_ObjectGetAttr(char,'ffqgestaltRow'))
    template = FFX_FFQGESTALT_CUSTOM[row][0]
    if FFX_TemplateExists(template)==0:
        customTemplate=getTemplateFromRealName(template)
        if FFX_TemplateExists(customTemplate):
            template=customTemplate
    #reveal the target object and set the positions
    pos = Get_ObjectPos(char)
    newPos = (pos[0]+10, pos[1]+10, pos[2])
    targetData = missionobjvar.Object_GetVar(char, 'ffqgestalt_target')
    target = targetData[2]
    if targetData[0]: #if a character
        teleportToPos(target, pos)
        Object_SetPrimaryState(target, PCSTATE_EXILE, 0, REMOVE_STATE)
        Object_SetSecondaryState(target, SCSTATE_INVISIBLE, 0, REMOVE_STATE)
        FFX_ObjectSetAttr(target, 'ffqgestalt_hidden', 0) #used by OnFFQGestaltTargetEnemy()
        if Object_GetClass(target) & OC_CONTROLLABLE:
            FFX_AdjustPortrait(target, 1)
        AIEnable(target)
    else:
        Object_SpawnAt(targetData[1], pos, target)
    teleportToPos(char, newPos)
    alignWith(target, char)
    #morph back the character
    name = getFormName()
    if FFX_HasPortrait(char):
        morph(name,char,template,1,1)
    else:
        morph(name,char,template,1,0)
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: Mystik on April 27, 2008, 07:13:31 PM
whoot  :thumbup: :thumbup: :thumbup:

gonna check this asap
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: C4 on April 29, 2008, 01:58:29 AM
Great job, Epimethee. Just browsed through the code and it looks very interesting.

So now that guilt factor will come into play...
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: TaskMasterX on April 29, 2008, 04:20:03 AM
Very Cool, Ep! Can't wait to plug this in!
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: yell0w_lantern on April 29, 2008, 12:31:03 PM
This might solve my problem for getting from Wonder Woman and an empty Invisible Jet to Invisible Jet with Wonder Woman inside.  :wub:
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: Epimethee on April 29, 2008, 06:10:01 PM
Thanks for the kind words, guys; it appreciated. Hopefully, it does works correctly now; I kept finding new bugs for a long while.
Title: Re: Attribute similar to DRIVER? (was: attribute request)
Post by: BentonGrey on May 19, 2008, 01:37:14 PM
Fantastic Epi!  I'm thrilled that this is now an option.  Robin-cycle, here I come!  Ha. :D