[ACTION MAKER][WEAPON][SOLVED] Alternative for Sleep function in MP4

Moderator: NADEO

User avatar
weerwolf
Posts: 630
Joined: 15 Jun 2010, 21:21
Location: Wijchen, Netherlands
Contact:

[ACTION MAKER][WEAPON][SOLVED] Alternative for Sleep function in MP4

Post by weerwolf »

So, here is the working script in MP3 for a Meteor Shower:

Code: Select all

#RequireContext CSmAction

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib

#Setting C_Cooldown			20000
#Setting C_EnergyCost		6400
#Setting C_EnergyMax			6400
#Setting C_EnergyReload	True

#Setting C_Fragments			200

#Const C_ProjectileName1	"Projectile 1"
#Const C_AnimName			"Anim1"


Cooldown = C_Cooldown;
EnergyMax = C_EnergyMax;
EnergyCost = C_EnergyCost;
EnergyReload = C_EnergyReload;

declare AnimId0 = GetAnimModelId(C_AnimName);
declare ProjectileId1 = GetProjectileModelId(C_ProjectileName1);

while (True) {
	foreach (Event in PendingEvents) {
		switch (Event.Type) {
			case CSmActionEvent::EType::OnHitPlayer : {
				SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Player);
			}
		}
	}

	if (Owner.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned && IsActive && (Energy >= EnergyCost) && Cooldown_IsReady(Now) && !Owner.IsOnTechNoWeapon && !Owner.IsInWater ) {
		Cooldown_Start();
		Energy -= EnergyCost;
		//PlayAnimOnPlayer(AnimId0, Owner);
		//CreateShoot(Owner, ProjectileId1);

		//Mapsize is 48x48 blocks == 384x384 meters
		declare Integer Counter = 1;
		while (Counter <= C_Fragments) {	
			declare Real PPX	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Real PPY	= 192.0;
			declare Real PPZ	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
			declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
			declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
			declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
			declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
			CreateProjectile(Owner, ProjectileId1, P_Pos, P_Dir, P_Speed);
			SendRulesEvent("fire", Text[], Owner, Null);
			Counter += 1;
			sleep(C_Cooldown / C_Fragments);
		}
	}
	yield;
}
I was using the sleep command to spawn the fragments at intervals.
Thus far i have rewritten it to MP4 :

Code: Select all

// MeteorShower 
// Unleashes a devestating meteor shower on the whole map 
// Version  01.03.2019

// Changes  MP3 > MP4 :
// GetAnimModelId			replaced by Anim_GetModelId
// GetProjectileModelId	replaced by Projectile_GetModelId
// Event.Player					replaced by Event.Victim
// PlayAnimOnPlayer		replaced by Anim_PlayOnPlayer

//  Bug C_EnergyReload. Tmp workaround (Eole) 01.03.2019
//  Replace EnergyReload = C_EnergyReload; with 
// if (Energy < EnergyMax) {
//	Energy += 10;
//	if (Energy > EnergyMax) {
//		Energy = EnergyMax;
//	}

#RequireContext CSmAction

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib

#Setting C_Cooldown			20000
#Setting C_EnergyCost		6400
#Setting C_EnergyMax			6400
#Setting C_EnergyReload	True

#Setting C_Fragments			200

#Const C_ProjectileName1	"Projectile 1"
#Const C_AnimName			"Anim1"

main() {

	Cooldown = C_Cooldown;
	EnergyMax = C_EnergyMax;
	EnergyCost = C_EnergyCost;
	if (Energy < EnergyMax) {
		Energy += 10;
		if (Energy > EnergyMax) {
			Energy = EnergyMax;
		}
	}

	declare AnimId0 = Anim_GetModelId(C_AnimName);
	declare ProjectileId1 = Projectile_GetModelId(C_ProjectileName1);

	foreach (Event in PendingEvents) {
		switch (Event.Type) {
			case CSmActionEvent::EType::OnHitPlayer : {
				SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Victim);
			}
		}
	}

	if (Owner != Null && Owner.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned && IsActive && (Energy >= EnergyCost) && Cooldown_IsReady() && !Owner.IsOnTechNoWeapon && !Owner.IsInWater ) {
		Cooldown_Start();
		Energy -= EnergyCost;
		//Mapsize is 48x48 blocks == 384x384 meters
		declare Integer Counter = 1;
		while (Counter <= C_Fragments) {	
			declare Real PPX	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Real PPY	= 192.0;
			declare Real PPZ	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
			declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
			declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
			declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
			declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
			Projectile_CreateAtLocation(ProjectileId1, Owner, P_Pos, P_Dir, P_Speed);
			SendRulesEvent("fire", [], Owner, Null);
			Counter += 1;
			//sleep(C_Cooldown / C_Fragments);
		}
	}
}
Sleep may not be used anymore. So it blows out at every tick, 100x per sec? 1000x ?
I was coding something like Timer +1 on every tick and then evaluate if counter x 100 > timer, but i got quite lost in that code
This is my latest try on that:

Code: Select all

// MeteorShower 
// Unleashes a devestating meteor shower on the whole map 
// Version  01.03.2019

// Changes  MP3 > MP4 :
// GetAnimModelId			replaced by Anim_GetModelId
// GetProjectileModelId	replaced by Projectile_GetModelId
// Event.Player					replaced by Event.Victim
// PlayAnimOnPlayer		replaced by Anim_PlayOnPlayer

//  Bug C_EnergyReload. Tmp workaround (Eole) 01.03.2019
//  Replace EnergyReload = C_EnergyReload; with 
// if (Energy < EnergyMax) {
//	Energy += 10;
//	if (Energy > EnergyMax) {
//		Energy = EnergyMax;
//	}

#RequireContext CSmAction

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib

#Setting C_Cooldown			20000
#Setting C_EnergyCost		6400
#Setting C_EnergyMax		6400
#Setting C_EnergyReload	True

#Setting C_Fragments		200

#Const C_ProjectileName1	"Projectile 1"
#Const C_AnimName			"Anim1"

main() {

	Cooldown = C_Cooldown;
	EnergyMax = C_EnergyMax;
	EnergyCost = C_EnergyCost;
	if (Energy < EnergyMax) {
		Energy += 10;
		if (Energy > EnergyMax) {
			Energy = EnergyMax;
		}
	}

	declare AnimId0 = Anim_GetModelId(C_AnimName);
	declare ProjectileId1 = Projectile_GetModelId(C_ProjectileName1);

	foreach (Event in PendingEvents) {
		switch (Event.Type) {
			case CSmActionEvent::EType::OnHitPlayer : {
				SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Victim);
			}
		}
	}

	if (Owner.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned && IsActive && (Energy >= EnergyCost) && Cooldown_IsReady() && !Owner.IsOnTechNoWeapon && !Owner.IsInWater ) {
		Cooldown_Start();
		Energy -= EnergyCost;
		//Mapsize is 48x48 blocks == 384x384 meters
		declare Integer Counter = 1;
		declare Integer Time = 1000;
		while (Counter <= C_Fragments) {
			Time +=1;
				if (Counter * 1000 >= Time) {
					declare Real PPX	= MathLib::Rand(0.0, 384.0); // 192.0
					declare Real PPY	= 192.0;
					declare Real PPZ	= MathLib::Rand(0.0, 384.0); // 192.0
					declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
					declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
					declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
					declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
					declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
					Projectile_CreateAtLocation(ProjectileId1, Owner, P_Pos, P_Dir, P_Speed);
					SendRulesEvent("fire", [], Owner, Null);
					Counter += 1;
				}
			//sleep(C_Cooldown / C_Fragments);
		}
	}
}
'Script is taking up to many resources' ; logically :roflol:

Any one can give me a heads up on this?

14.03.2019 Solution (based on script mention in this topic)

Code: Select all

main() {
declare Integer Delay = C_Cooldown / C_Fragments // Can of course be hardcode too
declare Integer TimeToAddFragment for This = Now + Delay

if (Now >= TimeToAddFragment) {
	DO STUFF HERE (fire, animate etc)
	} else {
	TimeToAddFragment = Now + Delay;
}
Last edited by weerwolf on 14 Mar 2019, 20:07, edited 2 times in total.
User avatar
maxi031
Posts: 378
Joined: 17 Jul 2011, 00:55

Re: [ACTION MAKER][WEAPON] Alternative for Sleep function in MP4

Post by maxi031 »

Always add yield; in your while loops and you should not get that message.
My specs:
MOBO: MB AM3+ 970 Gigabyte GA-970A-DS3P
CPU: AM3+ AMD FX-8320E
GPU: Nvidia GeForce GTX750-Ti ASUS 2GB DDR5
RAM: DDR3 8GB 1866MHz Kingston HyperX
SSD: SATA3 120gb SanDisk
OS: Ubuntu 19.04
TY MICMO
User avatar
maxi031
Posts: 378
Joined: 17 Jul 2011, 00:55

Re: [ACTION MAKER][WEAPON] Alternative for Sleep function in MP4

Post by maxi031 »

Something like this might work:

Code: Select all

declare Integer LastDing = Now + C_Cooldown / C_Fragments;
while (Counter <= C_Fragments && LastDing >= Now) {
			LastDing = Now + C_Cooldown / C_Fragments;
			yield;
			declare Real PPX	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Real PPY	= 192.0;
			declare Real PPZ	= MathLib::Rand(0.0, 384.0); // 192.0
			declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
			declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
			declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
			declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
			declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
			Projectile_CreateAtLocation(ProjectileId1, Owner, P_Pos, P_Dir, P_Speed);
			SendRulesEvent("fire", [], Owner, Null);
			Counter += 1;
		}
My specs:
MOBO: MB AM3+ 970 Gigabyte GA-970A-DS3P
CPU: AM3+ AMD FX-8320E
GPU: Nvidia GeForce GTX750-Ti ASUS 2GB DDR5
RAM: DDR3 8GB 1866MHz Kingston HyperX
SSD: SATA3 120gb SanDisk
OS: Ubuntu 19.04
TY MICMO
User avatar
weerwolf
Posts: 630
Joined: 15 Jun 2010, 21:21
Location: Wijchen, Netherlands
Contact:

Re: [ACTION MAKER][WEAPON] Alternative for Sleep function in MP4

Post by weerwolf »

Yield isn't used anymore. It's now written in a main function that is called upon each yield of the main engine. 1 of more reasons i am rewriting.
I do see u use a thing called Now. Is that like requesting a sort of timestamp?
User avatar
maxi031
Posts: 378
Joined: 17 Jul 2011, 00:55

Re: [ACTION MAKER][WEAPON] Alternative for Sleep function in MP4

Post by maxi031 »

Yes Now is something like timestamp.
Are you sure Yield is not used anymore? i just tried in editor plugin and without it got same error: Script is taking up to many resource, but with it works like charm.
My specs:
MOBO: MB AM3+ 970 Gigabyte GA-970A-DS3P
CPU: AM3+ AMD FX-8320E
GPU: Nvidia GeForce GTX750-Ti ASUS 2GB DDR5
RAM: DDR3 8GB 1866MHz Kingston HyperX
SSD: SATA3 120gb SanDisk
OS: Ubuntu 19.04
TY MICMO
User avatar
weerwolf
Posts: 630
Joined: 15 Jun 2010, 21:21
Location: Wijchen, Netherlands
Contact:

Re: [ACTION MAKER][WEAPON] Alternative for Sleep function in MP4

Post by weerwolf »

Well, took me 3 days, but i figured it out

Code: Select all

#RequireContext CSmAction

#Const Version "2019-03-07"
#Const Author "weerwolf"
#Const Description "Unleashes a devestating meteor shower over the whole map"

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib

#Setting C_Cooldown			20000
#Setting C_EnergyCost		6400
#Setting C_EnergyMax		6400
#Setting C_EnergyReload	True
#Setting C_Fragments		200

#Const C_ProjectileName1	"Projectile 1"
#Const C_AnimName			"Anim1"

main() {

	Cooldown = C_Cooldown;
	EnergyMax = C_EnergyMax;
	EnergyCost = C_EnergyCost;
	// Energy reload workaround
	// C_EnergyReload True/False yet to be implemented
	if (Energy < EnergyMax) {
		Energy += 10;
		if (Energy > EnergyMax) {
			Energy = EnergyMax;
		}
	}

	// Declarations ->
	declare AnimId0 = Anim_GetModelId(C_AnimName);
	declare ProjectileId1 = Projectile_GetModelId(C_ProjectileName1);
	declare Integer Counter for This;
	declare Integer Stage for This;

	// Handeling events ->
	foreach (Event in PendingEvents) {
		switch (Event.Type) {
			case CSmActionEvent::EType::OnHitPlayer : {
				SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Victim);
			}
			case CSmActionEvent::EType::OnProjectileEnd: {
				SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Victim);
			}
			case CSmActionEvent::EType::OnHitObject : {
			SendRulesEvent("damage", [TextLib::ToText(Event.Damage)], Owner, Event.Victim);
			}
		}
	}
	
	// Shoot weapon on left mouse click ->
	if (Owner != Null && Owner.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned && IsActive && (Energy >= EnergyCost) && Cooldown_IsReady() && !Owner.IsOnTechNoWeapon && !Owner.IsInWater ) {
		Cooldown_Start();
		Energy -= EnergyCost;
		//disabled to prevent first shot originating from player
		//declare Proj1 = Projectile_CreateOnPlayer(ProjectileId1, Owner);
		Stage = 1;
	}

	// After fire weapon set stage 1 and start counting fragments ->
	if (Stage == 1) {
		declare Integer TimeStamp;
		declare Integer Delay;
		TimeStamp = Now;
		// Set the delay between fragments ->
		Delay = C_Cooldown / C_Fragments;
		if (TimeStamp % Delay == 0 && Counter < C_Fragments) {
			log("Fire fragment");
			Counter += 1;
			log(Counter);
				// need to put this into a function ->
				declare Real PPX	= MathLib::Rand(96.0, 288.0); // 0.0,384.0
				declare Real PPY	= 192.0; // 192.0
				declare Real PPZ	= MathLib::Rand(96.0, 288.0); //  0.0,384.0
				declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
				declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
				declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
				declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
				declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
				declare Proj1 = Projectile_CreateAtLocation(ProjectileId1, Owner, P_Pos, P_Dir, P_Speed);
			SendRulesEvent("fire", [], Owner, Null);
		}
		// if  all  fragments have fired, return to stage 0 and reset counter ->
		if (Counter == C_Fragments) {
			Stage = 0;
			Counter = 0;
		}
	}
}
declare Integer TimeStamp;
declare Integer Delay;
TimeStamp = Now;
Delay = C_Cooldown / C_Fragments; (for other scripters, could be static number here)
TimeStamp % Delay == 0

That last line, i picked that up somewhere googling, and without even understanding well, just coded it in :roflol:
Someone may explain me that in lame terms :P
BSO
Posts: 118
Joined: 08 Oct 2018, 08:49

Re: [ACTION MAKER][WEAPON][SOLVED] Alternative for Sleep function in MP4

Post by BSO »

Hi weerwolf,
Now is a "TimeStamp " in millisecond that start when you launch Maniaplanet (so you can use Now to know the time that has elapsed since the game was started)
The % (modulo operator) is used in math to check if an unsigned integer (a number between 0 and the infinite) can be divided by another number without rest, in another term in A % B does A a multiple of B.
So the code

Code: Select all

TimeStamp % Delay == 0
will be true when TimeStamp is a multiple of Delay.
In conclusion this isn't a bad idea but with won't work all the time because of the yield. With the code you shared you check if Now is exactly a multiple of Delay, let's see an exemple :
Delay = 100
- your function is executed at Now == 52, 52 isn't a multiple of Delay (100), so you don't enter in

Code: Select all

if (TimeStamp % Delay == 0 && Counter < C_Fragments)
- your function reach it's end
- your function is executed at Now == 104, 104 isn't a multiple of Delay (100), you won't enter in the if
- your function reach it's end
- your function is executed at Now == 300, 300 is a multiple of Delay, so you will enter in the if

You will enter in the IF only one time instead of three

A good way:

Add a global variable at begginning of your script:

Code: Select all

declare Integer TimeToAddFragment;

Initialize this to zero or the to Now + Delay in the main :

Code: Select all

main() {
	declare Integer Delay = C_Cooldown / C_Fragments;
	TimeToAddFragment = 0;
	OR
	TimeToAddFragment = Now + Delay;

Code: Select all

if (Stage == 1 && Now >= TimeToAddFragment) {
	log("Fire fragment");
	Counter += 1;
	log(Counter);
	// need to put this into a function ->
	declare Real PPX	= MathLib::Rand(96.0, 288.0); // 0.0,384.0
	declare Real PPY	= 192.0; // 192.0
	declare Real PPZ	= MathLib::Rand(96.0, 288.0); //  0.0,384.0
	declare Vec3 P_Pos		= <PPX, PPY, PPZ>;
	declare Real Angle1		= MathLib::Rand(-0.4, 0.4);
	declare Real Angle2		= MathLib::Rand(-0.4, 0.4);
	declare Vec3 P_Dir		= <Angle1, -1.0, Angle2>;
	declare Vec3 P_Speed	= <0.0, 0.0, 0.0>;
	declare Proj1 = Projectile_CreateAtLocation(ProjectileId1, Owner, P_Pos, P_Dir, P_Speed);
	SendRulesEvent("fire", [], Owner, Null);
	if (Counter == C_Fragments) {
		Stage = 0;
		Counter = 0;
	} else {
		// Set the next "TimeStamp"
		TimeToAddFragment = Now + Delay;
	}
}
The code below (not tested) will do what you want.
Tell me of you have others questions.
User avatar
weerwolf
Posts: 630
Joined: 15 Jun 2010, 21:21
Location: Wijchen, Netherlands
Contact:

Re: [ACTION MAKER][WEAPON][SOLVED] Alternative for Sleep function in MP4

Post by weerwolf »

Hi BSO,

Thanks for your post.
I think i understand now correctly what % does, still need the clarity of why all desired fragments where logged.

I do have a question:
In MP3 i declared global variables in this way is was then

Code: Select all

// Globals ->
declare Integer TimeToAddFragment;
// Main ->
while (True) {
I do not have that anymore because

Code: Select all

// Globals ->
declare Integer TimeToAddFragment;
main() {
will throw a syntax error, unexpected MANIASCRIPT_MAIN
BSO
Posts: 118
Joined: 08 Oct 2018, 08:49

Re: [ACTION MAKER][WEAPON][SOLVED] Alternative for Sleep function in MP4

Post by BSO »

Hi, in your case the main function will be executed not once but a lot of time so I think you need to declare a variable that will not be reset every time like this :

Code: Select all

Void main() {
	declare Integer TimeToAddFragment for This; // Will keep its previous value
But I don't know how you can know if it's the first time this main is call so you can set the default value (0 OR Now + Delay).
Or declare the global like you did but at the same time as

Code: Select all

G_MyCustomWeapon
on the Match_StartServer section of your script and initialize to 0 at the same time as

Code: Select all

G_MyCustomWeapon
.

I am not familiar with Action Maker but if you send me in PM your file(s) (script) I can do a proper investigation or you can ping/contact Eolehe know better than me the Action Maker if he's not busy he can look and give you a better answer :)
Post Reply

Return to “ActionMaker and Item editor”

Who is online

Users browsing this forum: No registered users and 1 guest