Author Topic: Has anyone tried making a delayed-timer event?  (Read 837 times)

Titanicus

  • Sentient
  • **
  • Posts: 61
  • Karma: +3/-0
    • View Profile
Has anyone tried making a delayed-timer event?
« on: March 08, 2015, 03:06:05 AM »
Just wondering what a good way would be for me to have a function run once and then call itself one more time after xxxx seconds. I'm trying to create a torpedo-like effector that drops the maxAcceleration of a ship down to 0 for 5 seconds. :)

dalolorn

  • Sentient
  • **
  • Posts: 199
  • Karma: +7/-0
  • ABEM Developer
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #1 on: March 08, 2015, 05:54:53 AM »
Keeping in mind that this is the sort of thing that you may only ever have one method of application and only one method of expiration for - like LimitedSight statuses from nebulae - because if they expire in the wrong order, you're screwed.

Apply a status (let's make it a unique status, just in case) for a period of 5 seconds. Make a custom status hook for the abovementioned status whose onCreate() function sets maxAcceleration to 0, storing the original maximum in the hook's "data" variable. onDestroy() must then set maxAcceleration back to the variable stored in "data".

This won't work correctly if there's anything whatsoever in the game that would alter maxAcceleration outside of that one status. Either you'll fail to achieve the desired effect because maxAcceleration is being recalculated all the time by the Ship or LeaderAI scripts (an unlikely scenario) or you'll limit the ship's maxAcceleration to a value lower than the existing maximum, or even set it above the default maxAcceleration. (In your case, you'd probably make it impossible for the ship to ever accelerate again.)

... Wait a second. I think I handled maxAcceleration in ABEM's derelicts, I'll check how it was done.

Edit: No, sorry, that was rotationSpeed. I set it to 0 in onCreate and then to 0.1 in onDestroy.

Anyway, here's a couple of hooks that might be of use for handling reapplication. READ WHAT I HAVE TO SAY BELOW, IT'S IMPORTANT.

Code: [Select]
class MaxStacks : StatusHook {
Document doc("Cannot have more than # stacks. DO NOT IN A BILLION YEARS CONSIDER USING THIS UNLESS YOU'RE APPLYING STATUSES WITH A DURATION OF -1. If you need your statuses to expire while using this hook, use CombinedExpiration.");
Argument count("Maximum", AT_Integer, "10", doc="How many stacks of a status can exist on a given object. Defaults to 10.");

#section server
void onAddStack(Object& obj, Status@ status, StatusInstance@ instance, any@ data) override {
if(status.stacks > arguments[0].integer) {
status.remove(obj, instance);
}
}
#section all
};

class CombinedExpiration : StatusHook {
Document doc("All stacks of the status expire simultaneously. Should only ever be used with a status with a duration of -1, in order to avoid anomalous side-effects.");
Argument duration("Duration", AT_Decimal, "10.0", doc="How long the status persists after its last application before expiring. Defaults to 10 seconds.");

#section server
void onAddStack(Object& obj, Status@ status, StatusInstance@ instance, any@ data) override {
double timer = 0;
data.store(timer);
}

bool onTick(Object& obj, Status@ status, any@ data, double time) override {
double timer = 0;
data.retrieve(timer);
timer += time;
data.store(timer);
return timer < arguments[0].decimal;
}
#section all
}

Hopefully, you won't need MaxStacks, as even a status with "Unique: True" will still call onAddStack whenever someone TRIES to reapply it. You'd just call CombinedExpiration with a duration of 5, and apply the status with a duration of -1. (CombinedExpiration is supposed to act as a replacement for the game's own system, not alongside it; I never actually tried using them simultaneously. My guess is that whatever duration was shorter would supersede the other.)

However, a more likely scenario is that you'll also need to call MaxStacks with a stack count of 1. I remember Lucas didn't particularly like the way I wrote that hook, and I know from my own experiences that it does not work well with any duration that isn't -1, hence my writing up CombinedExpiration back when I was working on that. So long as you don't try to use it without CombinedExpiration, you SHOULD be fine, but I can't make any promises. (In any case, ABEM's Adaptive Laser seemed to work fine with that configuration.)
« Last Edit: March 08, 2015, 06:11:43 AM by dalolorn »

Titanicus

  • Sentient
  • **
  • Posts: 61
  • Karma: +3/-0
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #2 on: March 08, 2015, 06:04:25 AM »
Yes every ship object in the game has a maxAcceleration field so you can just set that to 0. I'm pretty sure nothing in the vanilla game touches it directly.

dalolorn

  • Sentient
  • **
  • Posts: 199
  • Karma: +7/-0
  • ABEM Developer
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #3 on: March 08, 2015, 06:12:13 AM »
Gah, did I really take so long to edit that post? :O

Edit: By the way, I don't know offhand which imports you'll need to make that work.
« Last Edit: March 08, 2015, 06:14:33 AM by dalolorn »

GGLucas

  • Dr. Evil
  • BMS Staff
  • Delusional
  • *
  • Posts: 1877
  • Karma: +300/-6
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #4 on: March 08, 2015, 10:19:24 AM »
There's already a hook that removes acceleration, InterdictMovement(), it is used in the status 'Entangled', which is applied by the ion cannon.

On a flagship, though, you can just add that status with a duration of 5 seconds. Since the status has "Unique: True" in it, you can stack it with no problem without messing with the effects.

Interdicting support ships is going to be hard, they have minimal code around them. You could probably use the old predecessor of the statuses system to add a TimedEffect to the ship, which you would have to define in data/effects/ to have Start: and End: calls, then add it with something like this:

Code: [Select]
TimedEffect eff(ET_MyEffectName, 5.0);
evt.target.addTimedEffect(eff);

dalolorn

  • Sentient
  • **
  • Posts: 199
  • Karma: +7/-0
  • ABEM Developer
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #5 on: March 08, 2015, 12:20:48 PM »
Leave it to Lucas to sweep my ideas away with an easy, yet effective solution... :D

Titanicus

  • Sentient
  • **
  • Posts: 61
  • Karma: +3/-0
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #6 on: March 08, 2015, 06:52:18 PM »
Yea, main point is to just drop speeds in fleet combat to sane levels. If ships had the same acceleration they use to zip around the solar system as they do while fighting fleets, well... either your scale is going to be with ships as big as planets or everything will look like it's flying around at light speed for it's size. :D

*PS: Is there a problem with just dropping velocity of the hit target to 0 and removing acceleration directly through writing to the evt.ship.acceleration, etc...? Since velocity and acceleration are just constantly changing anyways, it would be like nailing a ship with a big hunk of gum. :)
« Last Edit: March 08, 2015, 06:54:01 PM by Titanicus »

GGLucas

  • Dr. Evil
  • BMS Staff
  • Delusional
  • *
  • Posts: 1877
  • Karma: +300/-6
    • View Profile
Re: Has anyone tried making a delayed-timer event?
« Reply #7 on: March 08, 2015, 08:17:04 PM »
Setting acceleration won't do a whole lot, since that is constantly being computed by the movement solver. Setting velocity to 0 will definitely have an effect, though you'll probably want to do it with a call to obj.impulse(-obj.velocity);, since that takes care of all the bits needed to keep your change synced in multiplayer.

You will screw up the movement solver and make things overshoot/not intercept correctly though.

Thy Reaper

  • BMS Lead Developer
  • BMS Administrator
  • Hopeless
  • *
  • Posts: 3237
  • Karma: +397/-8
    • View Profile
    • Blind Mind Studios
Re: Has anyone tried making a delayed-timer event?
« Reply #8 on: March 08, 2015, 08:22:34 PM »
One thing that might be possible is multiplying the time factor passed to the mover. That should keep everything working sensibly (although might cause some desync in multiplayer).