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
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?
no theres just a character and a vehicle
Hmm, well, in that case, I definitely second this.
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. :/
I am doing this already for my mod. so I can just as well release the code.
By the weekend.
C4 is back FFXing! :D
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*
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.
Did this ever get released?
No. I could not test anything on vacation. Give me a week and I should have it done.
Thanks C4!
bump
bump just finished a ton of skopes waiting for this attribute
Yep!
Yes this has been way to long. My project is keeping me so busy.
I will make sure to force myself to finish this.
(looks at watch)
We're working on it. Slowly.
Hoping to pull it off.
thanx guys
I am grateful for the effort
(I renamed the thread so that people didn't get the idea that this was a generic attribute request thread.)
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)
whoot :thumbup: :thumbup: :thumbup:
gonna check this asap
Great job, Epimethee. Just browsed through the code and it looks very interesting.
So now that guilt factor will come into play...
Very Cool, Ep! Can't wait to plug this in!
This might solve my problem for getting from Wonder Woman and an empty Invisible Jet to Invisible Jet with Wonder Woman inside. :wub:
Thanks for the kind words, guys; it appreciated. Hopefully, it does works correctly now; I kept finding new bugs for a long while.
Fantastic Epi! I'm thrilled that this is now an option. Robin-cycle, here I come! Ha. :D