• Welcome to Freedom Reborn Archive.
 

Scripting Request: FFX atttribute to recharge energy from electrical objects

Started by Urthman, February 17, 2007, 02:01:01 PM

Previous topic - Next topic

Urthman

So greedy.  I haven't even tested Stumpy's reverse gravity code patch and here I am with another request.

I was wondering if someone could script an FFX attribute that would let a character recharge some energy by using a dummy power on an "electrical" object like a streetlight, fusebox, or machine (like a processor or one of the machines in Mr. Mechanical's lair).

I'm thinking you could roll up a mix of code from the transmutator attribute (to allow targeting a particular class of objects) and the dependency or metaleater attributes (to allow drawing / leeching power from an object).

My wishlist of how this would work:

1.  Character gets a special command on electrical objects.  Ideally customizable with ffxcustom.py.

2.  Character uses a dummy power on object, customizable with ffxcustom.py (am I right in thinking that using a melee dummy power would force the character to touch the object?).

Then either:

3a) give character a fixed amount of energy (say 20-30 points) and do half that amount of damage to the object.

3b) give character energy points = to health points of object.  Do half that number of points damage to the object.

(I think I slightly prefer 3b, but 3a might be easier).

4.  Make sure it allows characters with attributes like energy tanks to absorb energy beyond the normal limit, up to the limit allowed by energy tanks.

I can live with it if the list of affected objects, the command text, and/or the dummy power have to be hardcoded in ffx.py, (I only need this for one character in the mod I'm making), but more customizable would be more fun.

P.S. - on attributes like metaleater, what's the difference between "draw health/draw energy" and "leech health/leech energy"?

catwhowalksbyhimself

Why can't you just use metaleater customized?  True you wouldn't get the custom command, but it should be close enough right?

I think leach damages the object and draw doesn't

Urthman

Quote from: catwhowalksbyhimself on February 17, 2007, 02:04:09 PM
Why can't you just use metaleater customized?  True you wouldn't get the custom command, but it should be close enough right?

I think leach damages the object and draw doesn't

I don't want the character to just passively suck up energy from surrounding objects.  I want him to have to walk up to it and "plug in" in order to recharge.

Epimethee


Epimethee

I'll try to make something (using FFvsTTR though, but I'll keep FF1 in mind, so hopefully it'll work for you). No promise... still, please PM me if you hear nothing in a while.

Urthman


Epimethee

So here it is... Might not be the most spectacularly advanced attribute ever, but it should probably work without problems in FF1 (which I haven't tested, mind you). Felt good to do a straightforward attribute for a change. :)

In FFEdit, create an attribute named ffqaltcurrent with a cost of... I dunno... 200?

In strings.txt, add:
ATTRIB_FFQALTCURRENT_01, alternate current
ATTRIB_FFQALTCURRENT_DESC_01, that plug you insist on carrying around might make you look a bit ridiculous, but being able to leech energy from various electrical sources can be handy.
CUSTOM_CUSTOM_ALTCURRENT_01, get charge
CUSTOM_CUSTOM_ALTCURRENT_DESC_01, leech electricity from this object


in ffxattribs.py, add the line:
["ffqaltcurrent","FFX_FFQALTCURRENT_CUSTOM","Alternate Current"],

in ffxdefault.py, add the entry:
FFX_FFQALTCURRENT_CUSTOM=[
["default", "electricalSources", "ffx_magnetic_lift", 3, "CUSTOM_ALTCURRENT", "effect_ffx_magnetised"],
["types", "ASource list", "dDummy Power", "iRange", "CCommand", "EFX"],
]


(Don't forget to run the FFX CC before running the game.)

in ffx.py, add two blocks of code.

The first is the list of electrical sources. Here is an example, based on the more complete list I'm using in FFvsTTR. You will need to change that list to use the FF1 templates instead.
#add your other electricity-powered physical object templates (generic and vehicles) here; bonus point for renewable sources ;)
electricalSources=(
'car_1',
'car_2',
'car_3',
'car_3_nostand',
'car_night_1',
'car_night_2',
'car_night_3',
'car_night_police',
'car_night_taxi',
'car_police',
'car_taxi',
'catsaucer_veh',
'ff_car',
'ff_computer',
'ff_objects',
'ff_science_equipment',
'ff_timemachine',
'force_field_projector',
'microwave_xray',
'mp_car',
'mp_truck',
'pat_air_conditioner',
'pat_billboard_eldiablo',
'pat_billboard_mentor',
'pat_billboard_minuteman',
'pat_billboard_nobody',
'pat_fusebox',
'pat_neonsign',
'pat_neonsign_anima',
'pat_neonsign_animb',
'pat_neonsign_animc',
'pat_park_lamp',
'pat_phone_booth',
'pat_phone_booth_night',
'pat_streetlight',
'pat_streetlight_night',
'pat_trafficlight',
'pat_TV_aerial',
'screens_base',
'streetlight',
'streetlight_day',
'streetlight_night',
'switch',
'tank_damaged',
'tape_drive',
'truck_night_ger_cargo',
'truck_night_ger_military',
)


And the second block, which is the actual attribute code:
def initffqaltcurrent(char, update=0):
    action = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 4)
    range = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 3)
    sources = eval( getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 1) )
    for template in sources: #defaults to FFvsTTR tuple of electrical sources in ffxextras.py
        Mission_CustomAction(action, char, template, 'OnFFQAltCurrent', range, 0)

def OnFFQAltCurrent(target, char):
    power = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 2)
    Trigger_Power(char, target, power, '')
    RegTimer('OnFFQAltCurrent2', 2, 0, char, target)

def OnFFQAltCurrent2(event):
    char = event.object
    target = event.string
    fx = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 5)
    Object_PlayEffect(target, fx, '', 0, 0, 'centre')
    oldHP = Object_GetAttr(target, "health")
    damage = min(oldHP, randint(10, 20))
    Trigger_Damage(target, damage)
    if FFX_ObjectGetAttr(target, 'FFQ_AltCurrent_Leeched'):
        danger = randint(1, 10)
        if danger == 8:
            Object_SetPrimaryState(char, PCSTATE_STUNNED, 5)
            return
        if danger == 9:
            Object_SetPrimaryState(char, PCSTATE_STUNNED, 15)
            return
        if danger == 10:
            Trigger_Explosion(target, 'ffx_ex_elec_small', -1)
            Trigger_Explosion(target, 'ffx_ex_fire_small')
            return
    else:
        FFX_ObjectSetAttr(target, 'FFQ_AltCurrent_Leeched', 1)
    newEP = int( min( Object_GetAttr(char,'maxEnergyPoints'), Object_GetAttr(char,'energyPoints') + (damage*2) ) )
    RegTimer('OnFFQAltCurrentFX', 0.5, newEP, char)

def OnFFQAltCurrentFX(event):
    char = event.object
    target = event.string
    newEP = event.user
    Object_SetAttr(char, 'energyPoints', newEP)
    fx = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 5)
    Object_PlayEffect(char, fx, '', 0, 0, 'centre')

Urthman

Wow, thanks epi.  That looks great.  I can't wait to try it out.  But I have a few questions:

1.  FFX 2.x for the first game doesn't have a ffxattribs.py file.  I don't remember needing to add code like that for other custom attributes.  I assume I can just skip that part?

2.  This bit looks unlike anything else in ffxdefault.py.  Are you sure that second line isn't FFvTR / FFX3.x specific?
FFX_FFQALTCURRENT_CUSTOM=[
["default", "electricalSources", "ffx_absorb", 3, "CUSTOM_ALTCURRENT", "effect_ffx_magnetised"],
["types", "ASource list", "dDummy Power", "iRange", "CCommand", "EFX"],
]


3.  I'm having trouble sorting through the details of your math.  Would you mind spelling out how this works regarding how much energy gets drained and how it effects the object being drained? 

Urthman

Oh, and here's the list of electrical sources I came up with for FF1:
electricalSources=(
'arial_tower',
'bus_greyhound',
'car_1',
'car_2',
'car_3',
'car_3_nostand',
'car_night_1',
'car_night_2',
'car_night_3',
'car_night_police',
'car_night_taxi',
'car_police',
'car_taxi',
'catsaucer_veh',
'car_ff',
'computer',
'ff_computer',
'ff_objects',
'conveyor',
'f4_phantom',
'fusebox',
'generator',
'lamp',
'force_field_projector',
'microwave_xray',
'mp_car',
'mp_truck',
'processor',
'processor_animated',
'regulator',
'regulator_part',
'repair_machine',
'shield_box',
'shield_dish',
'spotlight',
'trafficlight',
'screens_base',
'streetlight',
'streetlight_day',
'streetlight_night',
'switch',
'tape_drive',
'truck',
'truck_concrete',
'truck_nw',
'truck_nw_02',
'truck_pinstripe',
'turret_control',
'upper_lights',
'wires',
)

Edited to remove 'vending', I'd forgotten that it's a mechanical newspaper machine, not a soda machine.

Epimethee

Quote from: Urthman on March 13, 2007, 06:20:48 PM1.  FFX 2.x for the first game doesn't have a ffxattribs.py file.  I don't remember needing to add code like that for other custom attributes.  I assume I can just skip that part?

2.  This bit looks unlike anything else in ffxdefault.py.  Are you sure that second line isn't FFvTR / FFX3.x specific?
FFX_FFQALTCURRENT_CUSTOM=[
["default", "electricalSources", "ffx_absorb", 3, "CUSTOM_ALTCURRENT", "effect_ffx_magnetised"],
["types", "ASource list", "dDummy Power", "iRange", "CCommand", "EFX"],
]
Drats. Now I remember the difference between the FFX CC in FF1 and FFvsTTR: the old Control Centre is hardcoded. Sorry, disregard what I posted. IIRC, adding an entry to ffxdefault.py won't work; if it's the case, you'll have to make do with adding something like the following to ffx.py (say, just above the def initffqaltcurrent(): line).
FFX_FFQALTCURRENT_CUSTOM=[
["default", "electricalSources", "ffx_absorb", 3, "CUSTOM_ALTCURRENT", "effect_ffx_magnetised"],
["dont_call_him_electro", "electricalSources", "some_dummy_power", 3, "CUSTOM_ALTCURRENT", "effect_ffx_zap"],
]



Quote3.  I'm having trouble sorting through the details of your math.  Would you mind spelling out how this works regarding how much energy gets drained and how it effects the object being drained? 
The object will lose 10 to 20 hp (less if it has less HP left) and the hero gets the double. (Nice that your request mentionned something similar, because I hadn't checked it out before writing the code.)

Urthman

Hey, I tested this out and it works great!  Thanks a bunch, Epi!

A couple thoughts:

1.  Make sure you use a dummy power that doesn't cost any energy!  Or the attribute will be pointless.  The default one you chose, ffx_absorb, uses a low amount of energy (in FFX 2.x, at least), so it seemed like the recharging wasn't working.  If you've got EZFX installed, I recommend a no-cost dummy power that uses the Glitch Girl Shortcircuit FX.  Apparently the dummy power has to be a direct?  I couldn't get any other kind (beam, melee) to work.

2.  I like your idea of making it backfire once in a while, but in testing, I thought 3 chances in 10 was way too often.  Also, you're electrical+fire explosion, which looks and sounds very cool, is way too powerful, often causing an instant KO.  Here's a modified version I came up with:

def OnFFQAltCurrent2(event):
    char = event.object
    target = event.string
    fx = getByTemplate(char, FFX_FFQALTCURRENT_CUSTOM, 5)
    Object_PlayEffect(target, fx, '', 0, 0, 'centre')
    oldHP = Object_GetAttr(target, "health")
    damage = min(oldHP, randint(10, 20))
    Trigger_Damage(target, damage)
    if FFX_ObjectGetAttr(target, 'FFQ_AltCurrent_Leeched'):
        danger = randint(1, 20)
        if danger == 1:
            Object_SetSecondaryState(char, SCSTATE_ENERGIZED, 20)
            Mission_StatusText('supercharged!')
            return
        if danger == 18:
            Object_SetPrimaryState(char, PCSTATE_STUNNED, 5)
            Object_SetAttr(char,'energyPoints',0)
            Mission_StatusText('you got the wires crossed!')
            return
        if danger == 19:
            Object_SetPrimaryState(char, PCSTATE_STUNNED, 15)
            Mission_StatusText('short circuit!')
            return
        if danger == 20:
            Mission_StatusText('circuits overloaded!')
            Trigger_Explosion(target, 'ffx_electric_backfire')
            Trigger_Explosion(target, 'ffx_ex_fire_small')
            return
    else:
        FFX_ObjectSetAttr(target, 'FFQ_AltCurrent_Leeched', 1)
    newEP = int( min( Object_GetAttr(char,'maxEnergyPoints'), Object_GetAttr(char,'energyPoints') + (damage*2) ) )
    RegTimer('OnFFQAltCurrentFX', 0.5, newEP, char)

(ffx_electric_backfire is a mod specific power that has a unique effect targeted at the character that will be using this attribute.  But it uses the generic electrical explosion FX.  I like the look/sound of using both the fire and electrical explosions but recommend changing them so they only do a very small amount of damage or maybe one of them does no damage.)

Thank you, Epi.  This will be fun.

Epimethee

Thanks for the feedback Urthman. :)

Dummny power costing energy: oops! I didn't realise that. Looks like I wasn't paying enough attention to the test characters' energy recharge. Maybe ffx_magnetic_lift would be better.

Direct only: curious, I can't see why it wouldn't work; it was fine when I used a ranged attack.

Backfiring: The basic idea was to penalise players camping next to a single power source; they can still reuse the same source, but there's a risk involved. The 3 in 10 risk actually didn't feel high enough when I was testing it, so I boosted it to 3 in 8; so maybe it is now too much. I've updated the above code to the old 3/10. As for the damage, again it didn't happen often for my taste (now a 10% risk) and my test characters (some of which were vulnerable to heat or electricity) never suffered more than a few paltry points of damage. As the saying goes, "your mileage may vary". Still, I'll nerf the electrical damage by adding to Trigger_Explosion() the -1 argument (the electrical explosion rather than the fire one, since I want to nerf just a bit anda lot of characters with the attribute ought to be able to absorb or resist electricity anyway).