Author Topic: Slower weapon  (Read 1958 times)

Hi I want to make this weapon that slows the player it hits, and I haven't been able to figure it out.

Hi I want to make this weapon that slows the player it hits, and I haven't been able to figure it out.
What have you tried, what do you know already, did you look at other add-ons that might do something similar, what code do you have so far, where are you stuck?

Code: [Select]
function Projectile::OnHitObject(%this, %obj, %slot, %hitObj, %hitPos, %hitNormal)
{
%oldMS = %hitObj.maxForwardSpeed;
applySlow(%hitobj, 5, 5, %oldMS);
}

function applySlow(%obj, %time, %speedDrain, %oldMS)
{
%obj.setMaxForwardSpeed(%oldMS - %speedDrain);
%timeSec = %time * 1000;
schdule(0, %timeSec, StopSlow, %obj, %oldMS);
}

function StopSlow(%obj, %ms)
{
%obj.setMaxForwardSpeed(%ms);

}

Code: [Select]
function Projectile::OnHitObject(%this, %obj, %slot, %hitObj, %hitPos, %hitNormal)
{
%oldMS = %hitObj.maxForwardSpeed;
applySlow(%hitobj, 5, 5, %oldMS);
}

function applySlow(%obj, %time, %speedDrain, %oldMS)
{
%obj.setMaxForwardSpeed(%oldMS - %speedDrain);
%timeSec = %time * 1000;
schdule(0, %timeSec, StopSlow, %obj, %oldMS);
}

function StopSlow(%obj, %ms)
{
%obj.setMaxForwardSpeed(%ms);

}
For starters: Using the namespace "Projectile" will apply this to all projectiles instead of your specific weapon. OnHitObject isn't an actual callback; you'll want onDamage and its respective arguments. You should call the parent to keep other projectile effects in place. You need to check if the thing you're damaging is a player or it'll mess up when you use it on a vehicle. maxForwardSpeed isn't stored on individual objects, you need to get it from the player datablock. You misspelled schedule, and have the time and dependency arguments backwards.

For starters: Using the namespace "Projectile" will apply this to all projectiles instead of your specific weapon.
Yeah, I know that. I just didn't want to show you what I was using it for.
Quote from: -Jetz-
OnHitObject isn't an actual callback; you'll want onDamage and its respective arguments.
And it's arguments are?
Quote from: -Jetz-
You need to check if the thing you're damaging is a player or it'll mess up when you use it on a vehicle.
How do I do that? I'm pretty sure I know, but I can't remember.
Quote from: -Jetz-
maxForwardSpeed isn't stored on individual objects, you need to get it from the player datablock.
Yeah I already figured that out.
Quote from: -Jetz-
You misspelled schedule, and have the time and dependency arguments backwards.
:O Typoes. Can you give me something like
Code: [Select]
schedule(%varname, %varname, %varname);?
Also, is it %obj.setMaxForwardSpeed(); or %obj.getDatablock().setMaxForwardSpeed(); ?

maxForwardSpeed isn't stored on individual objects, you need to get it from the player datablock.

Well, since r1956 went public players have individual maxForwardSpeeds. You can set it with Player::setMaxForwardSpeed( int ) and get it with Player::getMaxForwardSpeed().

And it's arguments are?
Figure it out yourself. The proper way would be to run a trace and shoot something, but if you really want to be lazy instead of training your critical thinking skills you can just use the search feature up top and search "onDamage." I'll give you a hit, the method is a member of the "Armor" class and has three arguments. However, this is no good because none of the three arguments are the projectile that hit it, so there's no way of telling what the person got shot by.

What you're looking for is Armor::damage. Once again, use the search feature or trace for the arguments.

How do I do that? I'm pretty sure I know, but I can't remember.
If you can't remember, then you don't know. It's not important whether you know or not, if you're unsure just ask. There are two ways. %object.getType() & $TypeMasks::PlayerObjectType and striPos(%object.getClassName(), "Player") > -1. The first is significantly faster than the second, but the second is easier to understand.

:O Typoes. Can you give me something like
Code: [Select]
schedule(%varname, %varname, %varname);?
He meant you swapped the first and second arguments which are, respectively, delay time and parent object. You have schdule(0, %timeSec, StopSlow, %obj, %oldMS); but it should be schedule(%timeSec, 0, "StopSlow", %obj, %oldMS);

Also, is it %obj.setMaxForwardSpeed(); or %obj.getDatablock().setMaxForwardSpeed(); ?
Both setMaxForwardSpeed and getMaxForwardSpeed are on the player object, not their datablock.

Yeah I already figured that out.
So, no, you didn't.
« Last Edit: March 11, 2015, 02:17:05 PM by $trinick »

Yeah, I know that. I just didn't want to show you what I was using it for.
If you knew that, you should have changed it to something that wasn't wrong. Or just don't change it in the first place because keeping your work a secret is a dumb thing to do when you want someone to help you with it.

Well, since r1956 went public players have individual maxForwardSpeeds. You can set it with Player::setMaxForwardSpeed( int ) and get it with Player::getMaxForwardSpeed().
Didn't realize there was a getter method for it too.

Figure it out yourself. The proper way would be to run a trace and shoot something, but if you really want to be lazy instead of training your critical thinking skills you can just use the search feature up top and search "onDamage." I'll give you a hit, the method is a member of the "Armor" class and has three arguments. However, this is no good because none of the three arguments are the projectile that hit it, so there's no way of telling what the person got shot by.

What you're looking for is Armor::damage. Once again, use the search feature or trace for the arguments.
Actually, I was thinking of a different method, and got the name wrong. The one to use here is WhateverProjectile::damage. You can probably find examples of it in other weapons that do something other than damage to the target.

He meant you swapped the first and second arguments which are, respectively, delay time and parent object. You have schdule(0, %timeSec, StopSlow, %obj, %oldMS); but it should be schedule(%timeSec, 0, "StopSlow", %obj, %oldMS);
schedule(%timeSec, %obj, "StopSlow", %obj, %oldMS); would be even better, so it'll auto cancel if the player gets deleted.

schedule(%timeSec, %obj, "StopSlow", %obj, %oldMS); would be even better, so it'll auto cancel if the player gets deleted.

The reference object variable on schedules is broken right now unfortunately, so you have. to use SimObject::schedule. Above all, he should just use %obj.schedule(%timeSec, "setMaxForwardSpeed", %oldMS); since all StopSlow does anyway is call setMaxForwardSpeed (without a check to see if the player died, by the way).

Actually, I was thinking of a different method, and got the name wrong. The one to use here is WhateverProjectile::damage. You can probably find examples of it in other weapons that do something other than damage to the target.

p.s. (to OP) http://forum.blockland.us/index.php?topic=14090.0
« Last Edit: March 11, 2015, 05:45:30 PM by $trinick »

The reference object variable on schedules is broken right now unfortunately, so you have. to use SimObject::schedule
What? I just tested it, it works just as well as it did back when I was explaining how you are wrong about what that argument is used for. I've used it in tons of scripts to save myself an isObject check.

What? I just tested it, it works just as well as it did back when I was explaining how you are wrong about what that argument is used for. I've used it in tons of scripts to save myself an isObject check.







Your thesis statement appears to be: This is because schedule as a function works as I have described. It does not call methods. It only calls functions. You are wrong.

This is the same statement I made here:
The reference object variable on schedules is broken right now unfortunately, so you have. to use SimObject::schedule.

Let me reiterate with different diction: the reference object variable on the schedule function does nothing right now: schedule can only be used to call functions. To call a method, you must use SimObject::schedule.

The reason this confusion arose is because you put %obj in the second slot which made me think that StopSlow was defined by OP as a method of the player class. It is not; I made an incorrect assumption. However, the second argument slot does absolutely loving nothing because it used to allow you to specify an object upon which to call the third argument as a method. This no longer works. The result is that schedule can only be used to call functions while SimObject::schedule can only be used to call methods. My recommendation was that he take the superfluous function out of the equation altogether and directly call the desired method with a delay using the schedule method instead of the schedule function.

I was wrong about the way schedule functioned then because I did not anticipate that Badspot had broken it at some point, but I'm not wrong about it now.
« Last Edit: March 11, 2015, 10:42:00 PM by $trinick »

This is the same statement I made here:
Let me reiterate with different diction: the reference object variable on the schedule function does nothing right now: schedule can only be used to call functions. To call a method, you must use SimObject::schedule.

The reason this confusion arose is because you put %obj in the second slot which made me think that StopSlow was defined by OP as a method of the player class. It is not; I made an incorrect assumption. However, the second argument slot does absolutely loving nothing because it used to allow you to specify an object upon which to call the third argument as a method. This no longer works. The result is that schedule can only be used to call functions while SimObject::schedule can only be used to call methods. My recommendation was that he take the superfluous function out of the equation altogether and directly call the desired method with a delay using the schedule method instead of the schedule function.

I was wrong about the way schedule functioned then because I did not anticipate that Badspot had broken it at some point, but I'm not wrong about it now.
Honestly I wasn't sure whether you were reading StopSlow as a method or if you still expected it to call methods, but in any case, the torque documentation for the function says nothing about it ever having called methods, so I don't see any reason to think it's broken. All it says is
Quote
If it is associated with an object ID and the object is deleted prior to this event occuring, the event is automatically cancelled.
which is exactly what it does and has done in every case where I've used it.

Unfortunately, trinick is right:

Code: [Select]
==>function test::sayHi(%this){echo("Hello, world.");}
==>new ScriptObject(test);
==>test.sayHi();
Hello, world.
==>schedule(50, test, sayHi);
==>test.schedule(50, sayHi);
Hello, world.

This is a very recent bug.

Unfortunately, trinick is right:

Code: [Select]
==>function test::sayHi(%this){echo("Hello, world.");}
==>new ScriptObject(test);
==>test.sayHi();
Hello, world.
==>schedule(50, test, sayHi);
==>test.schedule(50, sayHi);
Hello, world.

This is a very recent bug.
What. This can't be a recent bug because I just booted up Age of Time and did the exact commands you did and got the exact same result, and the Torque documentation explains why. I've been saying that in that situation, schedule(50, test, sayHi); isn't calling test.sayHi() because it's not supposed to call test.sayHi(). What it does is call sayHi() as a function, but with the condition that if test gets deleted, the schedule is cancelled. This is what the documentation says it does, and where calling methods would be redundant with schedule as a method, this dependency argument is actually useful for calling functions that take an object as an input, like OP's StopSlow. The idea that the argument was ever used to call methods was a misconception, and here's the log from my tests in an old version of torque to dispel the idea that this is in any way new:
Code: [Select]
==>function test::sayHi(%this){echo("Hello, world.");}
==>new ScriptObject(test);
==>test.sayHi();
Hello, world.
==>schedule(50, test, sayHi);
==>test.schedule(50, sayHi);
Hello, world.
==>function sayHi(%obj){if(isObject(%obj))echo("Sup, world");else echo("asdffasasd");}
==>schedule(50, 0, sayHi, 0);
asdffasasd
==>schedule(50, 0, sayHi, test);
Sup, world
==>schedule(50, test, sayHi, test);
Sup, world
==>schedule(50, 0, sayHi, test); test.delete();
asdffasasd
==>new ScriptObject(test);
==>schedule(50, test, sayHi, test); test.delete();
==>new ScriptObject(test);
==>%s = schedule(50, test, sayHi, test); if(isEventPending(%s)) echo("You're good");
You're good
Sup, world
==>%s = schedule(50, test, sayHi, test); test.delete(); if(isEventPending(%s)) echo("You're good"); else echo("OH stuff JETZ WAS RIGHT");
OH stuff JETZ WAS RIGHT

Yeah it looks like both of you misunderstood the purpose of the second argument in the schedule function. I've always used it this way as well and it works just fine. Basically you just specify an object of your choice, and if that object stops existing before the schedule occurs it will cancel the function. It's just a shortcut so you don't have to use an isObject() in the called function or otherwise to prevent calls on a nonexistent object.

:O this:
Figure it out yourself.
And this:
if you're unsure just ask.
Also:
LoL longest coding help discussion I've had.