Page MenuHomeWildfire Games

Allow entities to be affected by Status Effects
ClosedPublic

Authored by wraitii on Jan 23 2018, 9:14 PM.

Details

Reviewers
Stan
Mate-86
Group Reviewers
Restricted Owners Package(Owns No Changed Paths)
Commits
rP22304: Allow entities to be affected by Status Effects from ranged attacks.
Trac Tickets
#1912
Summary

Discussion about the requirement can be read in the Trac ticket.
@fatherbushido suggested to follow this approach: "flaming projectile 'ignites' (or a poisonous one poisons) the target which suffers damage for a while regardless of running away."

Nice nomenclature defined on DOTA wiki which I'd follow in this patch.

This Diff is in progress. If you like the approach I can extend it with melee and ranged splash attacks. Sound or animation would be nice because right now it's not that obvious why the unit is being damaged over time.

Test Plan

Testing scenarios:

  • ranged point attack
  • ranged splash attack
  • melee attack
  • attack without continuous damage

Would be nice to add some unit tests too.

Diff Detail

Repository
rP 0 A.D. Public Repository
Lint
Lint Skipped
Unit
Unit Tests Skipped
Build Status
Buildable 7490
Build 12200: Vulcan BuildJenkins

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Mate-86 updated this revision to Diff 7941.EditedMay 8 2019, 9:37 PM

@wraitii I like your proposal about the separate components. Please review my latest patch! It contains the basic components which can be enhanched further (testing in-game, more unit tests, burning effect, particle, sound, optimizations, etc.)

The template change is for demonstration purpose only, the poisoning status effect can be moved into a specific unit template (if you know any good candidate for it).

Currently the StatusEffects is defined directly in the entity template and not as part of the attack template and used when any kind of attack causes damage to any units. This can be changed if needed.

You said the poison effect should not be stacked. This is supported now but I think multiple poisonous attacks should reset the timer (keeping the effect longer).

Hey @Mate-86 , this is going the right way ? but I think I wasn't 100% clear: I meant that <StatusEffects> should go in the Attack specification, like you did in the first place, not as a separate Component (Status is indeed the separate component).

Then in "Cause Damage" you check if the attack had status effects, and if yes you adjust "Status" of the attacked entity.

Is that clear? Feel free to ask questions if not.

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 111| 111| 
| 112| 112| 	// Do this first in case the direct hit kills the target
| 113| 113| 	if (data.isSplash)
| 114|    |-	{
|    | 114|+	
| 115| 115| 		this.CauseSplashDamage({
| 116| 116| 			"attacker": data.attacker,
| 117| 117| 			"origin": Vector2D.from3D(data.position),
| 124| 124| 			"type": data.type,
| 125| 125| 			"attackerOwner": data.attackerOwner
| 126| 126| 		});
| 127|    |-	}
|    | 127|+	
| 128| 128| 
| 129| 129| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 130| 130| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 212| 212| 				damageMultiplier = 0;
| 213| 213| 		}
| 214| 214| 		else // In case someone calls this function with an invalid shape.
| 215|    |-		{
|    | 215|+		
| 216| 216| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 217|    |-		}
|    | 217|+		
| 218| 218| 
| 219| 219| 		if (data.splashBonus)
| 220| 220| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1348/display/redirect

Stan added a comment.May 8 2019, 10:21 PM

Might want to use the Iberian mercenary skirmisher as the entity to test as it is able to throw fire javelins

binaries/data/mods/public/simulation/components/Damage.js
268

Comments start with Capitals as per the coding conventions. Might want to turn poisoning into burning as it is more common.

Mate-86 updated this revision to Diff 7949.May 9 2019, 9:16 PM

As discussed moving the StatusEffects inside the Attack component and changing the posioning to burning. Open questions:

  1. Should multiple status effects reset the timer?
  2. Should the status effects be added to other attack types? (melee, splash, indirect ranged attack)
  3. Should there be an animation played or an icon to be shown? I assume for a flaming animation on the target C++ change is needed too.

Feel free to comment!

Vulcan added a comment.May 9 2019, 9:23 PM

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 112| 112| 
| 113| 113| 	// Do this first in case the direct hit kills the target
| 114| 114| 	if (data.isSplash)
| 115|    |-	{
|    | 115|+	
| 116| 116| 		this.CauseSplashDamage({
| 117| 117| 			"attacker": data.attacker,
| 118| 118| 			"origin": Vector2D.from3D(data.position),
| 125| 125| 			"type": data.type,
| 126| 126| 			"attackerOwner": data.attackerOwner
| 127| 127| 		});
| 128|    |-	}
|    | 128|+	
| 129| 129| 
| 130| 130| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 131| 131| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 220| 220| 				damageMultiplier = 0;
| 221| 221| 		}
| 222| 222| 		else // In case someone calls this function with an invalid shape.
| 223|    |-		{
|    | 223|+		
| 224| 224| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 225|    |-		}
|    | 225|+		
| 226| 226| 
| 227| 227| 		if (data.splashBonus)
| 228| 228| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 516| 516| 
| 517| 517| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 518| 518| 		let gravity = +this.template[type].Projectile.Gravity;
| 519|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 519|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 520| 520| 
| 521| 521| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 522| 522| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 563| 563| 		// TODO: Use unit rotation to implement x/z offsets.
| 564| 564| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 565| 565| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 566|    |-		
|    | 566|+
| 567| 567| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 568| 568| 		if (cmpVisual)
| 569| 569| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 635| 635| 			});
| 636| 636| 	}
| 637| 637| 	else
| 638|    |-	{
|    | 638|+	
| 639| 639| 		// Melee attack - hurt the target immediately
| 640| 640| 		cmpDamage.CauseDamage({
| 641| 641| 			"strengths": this.GetAttackStrengths(type),
| 645| 645| 			"type": type,
| 646| 646| 			"attackerOwner": attackerOwner
| 647| 647| 		});
| 648|    |-	}
|    | 648|+	
| 649| 649| };
| 650| 650| 
| 651| 651| /**

binaries/data/mods/public/simulation/components/Attack.js
| 506| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 610| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1353/display/redirect

Silier added a comment.May 9 2019, 9:41 PM

To point 3:
I think yes. It should not be restricted just to ranged attacks.

binaries/data/mods/public/simulation/components/Status.js
18

you need to reset it back to false when effect ends

31
/**
 * Returns time since the start of the game in milliseconds.
 */
Timer.prototype.GetTime = function()

what you are calling is not even defined :)

38

you should call deal damage, or to handle target killed message ( unless you do not want to give attacker no experiences for this way of killing). At least you have to update statistics of player who looses this unit. See CauseDamage and TargetKilled in Damage.js.

We're approaching something that can be committed imo.
What you should do now is make the 'Status' component more generic. What I recommend is doing everything on a per-status basis, using a dictionary in Status.

Should multiple status effects reset the timer?

I think in most games once you're poisoned adding more poison does nothing, so I would say no by default.

Should the status effects be added to other attack types? (melee, splash, indirect ranged attack)

Melee should definitely support it in the end - but that can/should be done in a later revision.

Should there be an animation played or an icon to be shown? I assume for a flaming animation on the target C++ change is needed too.

Indeed you would need to wrap the component in C++ for actually rendering custom stuff.
Ideally units would switch into a specific "Poisoned" variant for example, but we are going to run into limitations of our variant system quickly with this.
For now I think it's fine if nothing happens. We'll add the GUI interface and possibly the C++ rendering in later differentials.

binaries/data/mods/public/simulation/components/Status.js
6

Replace this with something like:

this.currentStatuses = {}

Then for each status we get added, you'll have something like

this.currentStatuses["burn"] = { "duration" : X, "damage": Y }
9

StartEffect should only start one effect.

You should call a "StartEffects" function from Damage.js, which calls StartEffect(statusName, statusData) for every key in statusEffects.
So if statusEffects is { "burn": {...}, "poison" {...} } you call StartEffect twice, once with "burn", {data} and another with "poison",{data}

22

Instead of hardcoding this to burning, set this data on this.currentStatuses[statusName].

This way we can have several statuses at once.

25

Since we can have several statuses, you need to specify which to apply, so instead of passing null as data pass the status nam (the key that you used for currentStatuses)
Also don't call this.timer but this.currentStatuses[statusName].timer or something like that.

31

ExecuteEffect will receive data, lateness as parameters. You know how often it gets called (interval).

What you should do is count the time yourself (status.timeElapsed += status.interval + lateness) and compare that with status.duration (where status is this.currentStatuses[data.status])

38

Indeed. Thanks fo D865 'no armor defined' means 'take full damage', so you can do something like:

CauseDamage({ [status]: this.damage })
Mate-86 updated this revision to Diff 7999.EditedMay 13 2019, 6:48 PM

Notes regarding the new diff:

  1. Did you mean calling cmpDamage.CauseDamage? Because in that case I have to construct the strengths object and need pass the attacker and attackerOwner as parameters to the Status.
  2. Currently the first occurance of the effect is hard-coded to 0 sec. Not sure if it's OK for now.
  3. Would it make sense to make the statusEffectsSchema in Attack.js more generic? Eg. using
<oneOrMore>
	<element name='Effect'> ...
		<element name='Name'>...
		<element name='Duration' >...

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 112| 112| 
| 113| 113| 	// Do this first in case the direct hit kills the target
| 114| 114| 	if (data.isSplash)
| 115|    |-	{
|    | 115|+	
| 116| 116| 		this.CauseSplashDamage({
| 117| 117| 			"attacker": data.attacker,
| 118| 118| 			"origin": Vector2D.from3D(data.position),
| 125| 125| 			"type": data.type,
| 126| 126| 			"attackerOwner": data.attackerOwner
| 127| 127| 		});
| 128|    |-	}
|    | 128|+	
| 129| 129| 
| 130| 130| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 131| 131| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 220| 220| 				damageMultiplier = 0;
| 221| 221| 		}
| 222| 222| 		else // In case someone calls this function with an invalid shape.
| 223|    |-		{
|    | 223|+		
| 224| 224| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 225|    |-		}
|    | 225|+		
| 226| 226| 
| 227| 227| 		if (data.splashBonus)
| 228| 228| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 516| 516| 
| 517| 517| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 518| 518| 		let gravity = +this.template[type].Projectile.Gravity;
| 519|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 519|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 520| 520| 
| 521| 521| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 522| 522| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 563| 563| 		// TODO: Use unit rotation to implement x/z offsets.
| 564| 564| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 565| 565| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 566|    |-		
|    | 566|+
| 567| 567| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 568| 568| 		if (cmpVisual)
| 569| 569| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 635| 635| 			});
| 636| 636| 	}
| 637| 637| 	else
| 638|    |-	{
|    | 638|+	
| 639| 639| 		// Melee attack - hurt the target immediately
| 640| 640| 		cmpDamage.CauseDamage({
| 641| 641| 			"strengths": this.GetAttackStrengths(type),
| 645| 645| 			"type": type,
| 646| 646| 			"attackerOwner": attackerOwner
| 647| 647| 		});
| 648|    |-	}
|    | 648|+	
| 649| 649| };
| 650| 650| 
| 651| 651| /**

binaries/data/mods/public/simulation/components/Attack.js
| 506| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 610| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1388/display/redirect

This looks good, I think we're close to committable.

Notes regarding the new diff:

  1. Did you mean calling cmpDamage.CauseDamage? Because in that case I have to construct the strengths object and need pass the attacker and attackerOwner as parameters to the Status.

I do mean that. I don't think it's a problem, you can pass something like:

{
    "strengths" : { [StatusName] : number },
    "target" : -the target-,
    "attacker": null,
    "multiplier": -1,
    "type" : StatusName,
    "attackerOwner": -1,
}

Admittedly this function looks like it could use a cleanup.

  1. Currently the first occurance of the effect is hard-coded to 0 sec. Not sure if it's OK for now.

OK for now in my opinion.

  1. Would it make sense to make the statusEffectsSchema in Attack.js more generic?

If would, in fact you should do something similar to Upgrade where you can pass any name. That name will be the name of the status (your code is already handling this generically now)

binaries/data/mods/public/simulation/components/Status.js
46

You probably want >= here

52–53

This cleanup could be moved to a "stopStatus" function, so we can call that directly (imagine a priest healing a status for example)

Stan requested changes to this revision.May 14 2019, 4:07 PM

One should try loading a savegame and see if everything goes back to normal. A rejointest might be good too :)

binaries/data/mods/public/simulation/components/Damage.js
170

Might want to remove this as it's not adding anything :)

binaries/data/mods/public/simulation/components/Status.js
6

Missing semicolon

this.currentStatuses = {};
7

missing semicolon after brace.

13

missing semicolon after brace.

30

missing semicolon after brace.

44

Check for non system components before using them.

binaries/data/mods/public/simulation/templates/template_unit.xml
3

Do you need this ?

This revision now requires changes to proceed.May 14 2019, 4:07 PM
Mate-86 updated this revision to Diff 8029.May 14 2019, 9:28 PM
Mate-86 marked 22 inline comments as done.May 14 2019, 9:34 PM

Thanks for the comments @wraitii and @Stan ! I've addressed those expect the testing of saved game because I could not open the test map I've created. Is there any trick to make it visible in the scenario selector?

A rejointest might be good too :)

Does this mean testing in multiplayer? Can I do it locally somehow or in real multiplayer only?

binaries/data/mods/public/simulation/components/Status.js
13

Thanks for noting this! Shouldn't be there a lint check done by Jenkins for this?

46

when the duration is 10 sec then damage should be inflicted at the 10th sec too, or no?

binaries/data/mods/public/simulation/templates/template_unit.xml
3

Yep, needed otherwise the cmpStatus for the entity is 0 (similarily the empty <AIProxy/> is needed to initialize the component)

Silier added inline comments.May 14 2019, 9:40 PM
binaries/data/mods/public/simulation/components/Status.js
33

you should check if the status is defined, one can call this function twice by accident

35

remove return

40

the same, check if status actually exists

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 112| 112| 
| 113| 113| 	// Do this first in case the direct hit kills the target
| 114| 114| 	if (data.isSplash)
| 115|    |-	{
|    | 115|+	
| 116| 116| 		this.CauseSplashDamage({
| 117| 117| 			"attacker": data.attacker,
| 118| 118| 			"origin": Vector2D.from3D(data.position),
| 125| 125| 			"type": data.type,
| 126| 126| 			"attackerOwner": data.attackerOwner
| 127| 127| 		});
| 128|    |-	}
|    | 128|+	
| 129| 129| 
| 130| 130| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 131| 131| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 219| 219| 				damageMultiplier = 0;
| 220| 220| 		}
| 221| 221| 		else // In case someone calls this function with an invalid shape.
| 222|    |-		{
|    | 222|+		
| 223| 223| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 224|    |-		}
|    | 224|+		
| 225| 225| 
| 226| 226| 		if (data.splashBonus)
| 227| 227| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 515| 515| 
| 516| 516| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 517| 517| 		let gravity = +this.template[type].Projectile.Gravity;
| 518|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 518|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 519| 519| 
| 520| 520| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 521| 521| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 562| 562| 		// TODO: Use unit rotation to implement x/z offsets.
| 563| 563| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 564| 564| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 565|    |-		
|    | 565|+
| 566| 566| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 567| 567| 		if (cmpVisual)
| 568| 568| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 634| 634| 			});
| 635| 635| 	}
| 636| 636| 	else
| 637|    |-	{
|    | 637|+	
| 638| 638| 		// Melee attack - hurt the target immediately
| 639| 639| 		cmpDamage.CauseDamage({
| 640| 640| 			"strengths": this.GetAttackStrengths(type),
| 644| 644| 			"type": type,
| 645| 645| 			"attackerOwner": attackerOwner
| 646| 646| 		});
| 647|    |-	}
|    | 647|+	
| 648| 648| };
| 649| 649| 
| 650| 650| /**

binaries/data/mods/public/simulation/components/Attack.js
| 505| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 609| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1408/display/redirect

Stan added a comment.May 14 2019, 10:47 PM

Good work, keep it up ;)

binaries/data/mods/public/simulation/components/Status.js
5

Any reason for using an object over an array ?

13

There is. It's in the log vulcan posts as comment It's long though cause you are editing offending files :)

binaries/data/mods/public/simulation/components/tests/test_Status.js
8

Maybe you can find some way to reuse code ? Since you seem to be doing the same init multiple times :)

binaries/data/mods/public/simulation/templates/template_unit.xml
3

Yeah i guess we can't add components on the fly.

Does this mean testing in multiplayer? Can I do it locally somehow or in real multiplayer only?

There is a way to do it from the command line though off-hand I won't be able to tell you how exactly. It's documented in binaries/system/readme.txt I think.

What you an easily test is saving a game, loading it up and checking if statuses still apply.

I'll let you do the changes @Angen wrote and then I'll accept it and get it committed (though not the template change, yet anyways). If we have further developments we'll do it then. Thanks for the patch @Mate-86 !

binaries/data/mods/public/simulation/components/Status.js
5

We use it such this.currentStatuses[statusName] so an array wouldn't do.

60

Still needs to be >= I think.

Stan added inline comments.May 15 2019, 3:14 PM
binaries/data/mods/public/simulation/components/Status.js
5

Key can be a string no ?

Mate-86 marked 3 inline comments as done.May 16 2019, 9:31 PM
Mate-86 updated this revision to Diff 8046.May 16 2019, 10:00 PM

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 112| 112| 
| 113| 113| 	// Do this first in case the direct hit kills the target
| 114| 114| 	if (data.isSplash)
| 115|    |-	{
|    | 115|+	
| 116| 116| 		this.CauseSplashDamage({
| 117| 117| 			"attacker": data.attacker,
| 118| 118| 			"origin": Vector2D.from3D(data.position),
| 125| 125| 			"type": data.type,
| 126| 126| 			"attackerOwner": data.attackerOwner
| 127| 127| 		});
| 128|    |-	}
|    | 128|+	
| 129| 129| 
| 130| 130| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 131| 131| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 219| 219| 				damageMultiplier = 0;
| 220| 220| 		}
| 221| 221| 		else // In case someone calls this function with an invalid shape.
| 222|    |-		{
|    | 222|+		
| 223| 223| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 224|    |-		}
|    | 224|+		
| 225| 225| 
| 226| 226| 		if (data.splashBonus)
| 227| 227| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 515| 515| 
| 516| 516| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 517| 517| 		let gravity = +this.template[type].Projectile.Gravity;
| 518|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 518|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 519| 519| 
| 520| 520| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 521| 521| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 562| 562| 		// TODO: Use unit rotation to implement x/z offsets.
| 563| 563| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 564| 564| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 565|    |-		
|    | 565|+
| 566| 566| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 567| 567| 		if (cmpVisual)
| 568| 568| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 634| 634| 			});
| 635| 635| 	}
| 636| 636| 	else
| 637|    |-	{
|    | 637|+	
| 638| 638| 		// Melee attack - hurt the target immediately
| 639| 639| 		cmpDamage.CauseDamage({
| 640| 640| 			"strengths": this.GetAttackStrengths(type),
| 644| 644| 			"type": type,
| 645| 645| 			"attackerOwner": attackerOwner
| 646| 646| 		});
| 647|    |-	}
|    | 647|+	
| 648| 648| };
| 649| 649| 
| 650| 650| /**

binaries/data/mods/public/simulation/components/Attack.js
| 505| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 609| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1425/display/redirect

Mate-86 marked 10 inline comments as done.May 16 2019, 10:04 PM

There is a way to do it from the command line though off-hand I won't be able to tell you how exactly. It's documented in binaries/system/readme.txt I think.

I can look into this later.

What you an easily test is saving a game, loading it up and checking if statuses still apply.

(As I asked on chat) I wanted to test but when I created some maps in the Atlas those are not shown up in the scenario selector of the game. Is there any hidden trick like I have to add the new maps to some text files, or only maps with specific conditions are listed (eg. there needs to be at least an AI player, victory condition, or idk)

binaries/data/mods/public/simulation/components/Status.js
5

an array with string key is called object :)

Stan added inline comments.May 17 2019, 7:44 AM
binaries/data/mods/public/simulation/components/Status.js
5

That can also be a dictionnary or a map :)

wraitii added inline comments.May 17 2019, 8:59 AM
binaries/data/mods/public/simulation/components/Status.js
5

Yea in JS you basically have Arrays, which can only be accessed by an index (numeric), and objects, which are basically everything else, and can be accessed by strings. However since JS is weakly typed, most things can get converted to strings.

In this instance we use an object as a Map, but the Map() Javascript interface is a tad annoying, so I'd rather not use it unless the performance feels necessary (and it doesn't here).

Stan added inline comments.May 17 2019, 10:02 AM
binaries/data/mods/public/simulation/components/Status.js
5

Ah I see

Array["StringIndex"] = Array.StringIndex which is not part of the array, but of the object containing said array, like Array["length"]. Thanks.

elexis added a subscriber: elexis.May 17 2019, 11:47 AM

A rejointest might be good too

They are mostly useful to reproduce a known bug, but if you don't know what to test for, the rejointest is not likely going to reveal something (other than bugs that break it every single time as opposed to bugs that are only triggered under certain conditions).
If you want to make sure that the game is serialized and deserialized properly, one has to read the code.
From a quick look, I don't see any reason to suspect an OOS, since there is only one component property added, that is serialized and deserialized by the default functions (i.e. the affected component doesn't have a Serialize and Deserialize function) and the GUIInterface.js does not call modified simulation code. (The nice thing about OOS however is that they can always teach one new ways how they can occur, so I can't ensure absence of OOS with a quick look.)

Name:
I didn't read above discussion, but the component name "Status" seems undescriptive. Entities have Owner status, Capture status, Health status, territory status, resource status, so what is Status?

Schema:
A component and its properties are described in a Schema property that should not be missed.

I guess the purpose of the component is to store previous attacks that still do damage, so something relating to Attack or Damage might be a direction for renaming (one may also consider the pros and cons of storing it in an existing component, but I guess Attack doesn't work since it has to be stored per attacked entity and Health isn't about managing how damage is inflicted)

In D1252#78363, @elexis wrote:

Name:
I didn't read above discussion, but the component name "Status" seems undescriptive. Entities have Owner status, Capture status, Health status, territory status, resource status, so what is Status?

The purpose of this component is to allow entities to suffer from status effects, a very standard concept. We could rename it to "StatusEffects", though I feared that would imply this was the bit giving status effects when it's actually receiving them.

Schema:
I guess the purpose of the component is to store previous attacks that still do damage, so something relating to Attack or Damage might be a direction for renaming (one may also consider the pros and cons of storing it in an existing component, but I guess Attack doesn't work since it has to be stored per attacked entity and Health isn't about managing how damage is inflicted)

See above, I'll rename the diff since it has changed at this point.

wraitii retitled this revision from Continuous damage after hit detection to Allow entities to be affected by Status Effects.May 17 2019, 12:02 PM

Is the component to implement Health changes (the code looks a lot like it) or every stat (everything that aura/tech can modify or all entity component properties)?

In D1252#78367, @elexis wrote:

Is the component to implement Health changes (the code looks a lot like it) or every stat (everything that aura/tech can modify or all entity component properties)?

Both. Long-term, for me, the intention is that this will be able to deal damage or heal units, apply Modifiers, so that we could inflict "slowness/paralysis" status effects for example, and other things we can think of, possibly.

However, before this code an apply modifiers, we need D274 imo, since that would end up being much easier then.
Short-term, only damage is implemented.

Mate-86 marked an inline comment as done.May 17 2019, 9:46 PM

I renamed the my map file to an existing map so that I could play on it. :) Save game/load game works, the builings hit by the burning attack continued receiving damage after loading the game.
I did a multi player test via localhost and the damage dealt are in sync in both player session: https://imgur.com/a/PKXNvMt

Please let me know if anything else is missing!

wraitii accepted this revision.May 25 2019, 10:09 AM

Think this looks good, should probably rename Status to StatusEffectReceiver or something similar (following the DamageReceiver nomenclature), but that can be done before committing.

Thanks for the patch @Mate-86 !

Think this looks good, should probably rename Status to StatusEffectReceiver or something similar (following the DamageReceiver nomenclature), but that can be done before committing.

Thanks for the patch @Mate-86 !

Thanks @wraitii for accepting the patch! :)

Stan added a comment.May 26 2019, 12:18 PM

Thank you for finishing this ! Do you plan to work on something else next ?

In D1252#79344, @Stan wrote:

Thank you for finishing this ! Do you plan to work on something else next ?

Yes, to make this feature complete I would add these parts we discusses but in a separate patch:

  • melee support
  • grapichal part (icon or animation)
  • UI info (tooltip, unit stats)

Either the original trac ticket could be reused or a new to be created it's up to you: https://trac.wildfiregames.com/ticket/1912

wraitii commandeered this revision.May 26 2019, 2:14 PM
wraitii edited reviewers, added: Mate-86; removed: wraitii.

Commandeering for final upload before committing - I've 'explicited' the name and presumably fixed linting.

wraitii updated this revision to Diff 8152.May 26 2019, 2:14 PM

Successful build - Chance fights ever on the side of the prudent.

Linter detected issues:
Executing section Source...
Executing section JS...
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  25|  25| 
|  26|  26| 	let cmpDamage = ConstructComponent(SYSTEM_ENTITY, "Damage");
|  27|  27| 	let cmpTimer = ConstructComponent(SYSTEM_ENTITY, "Timer");
|  28|    |-	cmpTimer.OnUpdate({ turnLength: 1 });
|    |  28|+	cmpTimer.OnUpdate({ "turnLength": 1 });
|  29|  29| 	let attacker = 11;
|  30|  30| 	let atkPlayerEntity = 1;
|  31|  31| 	let attackerOwner = 6;
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1, 0,0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|  63|  63| 		"position": targetPos,
|  64|  64| 		"isSplash": false,
|  65|  65| 		"projectileId": 9,
|  66|    |-		"direction": new Vector3D(1,0,0)
|    |  66|+		"direction": new Vector3D(1,0, 0)
|  67|  67| 	};
|  68|  68| 
|  69|  69| 	AddMock(atkPlayerEntity, IID_Player, {
|    | [NORMAL] ESLintBear (quote-props):
|    | Unquoted property 'turnLength' found.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 114| 114| 
| 115| 115| 	function TestDamage()
| 116| 116| 	{
| 117|    |-		cmpTimer.OnUpdate({ turnLength: 1 });
|    | 117|+		cmpTimer.OnUpdate({ "turnLength": 1 });
| 118| 118| 		TS_ASSERT(damageTaken);
| 119| 119| 		damageTaken = false;
| 120| 120| 	}
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 156| 156| 		"origin": origin,
| 157| 157| 		"radius": 10,
| 158| 158| 		"shape": "Linear",
| 159|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 159|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 160| 160| 		"direction": new Vector3D(1, 747, 0),
| 161| 161| 		"playersToDamage": [2],
| 162| 162| 		"type": "Ranged",
|    | [NORMAL] ESLintBear (comma-spacing):
|    | A space is required after ','.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 163| 163| 		"attackerOwner": attackerOwner
| 164| 164| 	};
| 165| 165| 
| 166|    |-	let fallOff = function(x,y)
|    | 166|+	let fallOff = function(x, y)
| 167| 167| 	{
| 168| 168| 		return (1 - x * x / (data.radius * data.radius)) * (1 - 25 * y * y / (data.radius * data.radius));
| 169| 169| 	};
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'hack'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack": 100, "pierce" : 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1
|    | [NORMAL] ESLintBear (key-spacing):
|    | Extra space after key 'pierce'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 315| 315| 		"origin": new Vector2D(3, 4),
| 316| 316| 		"radius": radius,
| 317| 317| 		"shape": "Circular",
| 318|    |-		"strengths": { "hack" : 100, "pierce" : 0, "crush": 0 },
|    | 318|+		"strengths": { "hack" : 100, "pierce": 0, "crush": 0 },
| 319| 319| 		"playersToDamage": [2],
| 320| 320| 		"type": "Ranged",
| 321| 321| 		"attackerOwner": 1

binaries/data/mods/public/simulation/components/tests/test_Damage.js
| 125| »   type·=·data.type·=·"Ranged";
|    | [NORMAL] ESLintBear (no-multi-assign):
|    | Unexpected chained assignment.
|    | [NORMAL] ESLintBear (spaced-comment):
|    | Expected space or tab after '//' in comment.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 515| 515| 
| 516| 516| 		let horizSpeed = +this.template[type].Projectile.Speed;
| 517| 517| 		let gravity = +this.template[type].Projectile.Gravity;
| 518|    |-		//horizSpeed /= 2; gravity /= 2; // slow it down for testing
|    | 518|+		// horizSpeed /= 2; gravity /= 2; // slow it down for testing
| 519| 519| 
| 520| 520| 		let cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
| 521| 521| 		if (!cmpPosition || !cmpPosition.IsInWorld())
|    | [NORMAL] ESLintBear (no-trailing-spaces):
|    | Trailing spaces not allowed.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 562| 562| 		// TODO: Use unit rotation to implement x/z offsets.
| 563| 563| 		let deltaLaunchPoint = new Vector3D(0, this.template[type].Projectile.LaunchPoint["@y"], 0.0);
| 564| 564| 		let launchPoint = Vector3D.add(selfPosition, deltaLaunchPoint);
| 565|    |-		
|    | 565|+
| 566| 566| 		let cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
| 567| 567| 		if (cmpVisual)
| 568| 568| 		{
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Attack.js
| 634| 634| 			});
| 635| 635| 	}
| 636| 636| 	else
| 637|    |-	{
|    | 637|+	
| 638| 638| 		// Melee attack - hurt the target immediately
| 639| 639| 		cmpDamage.CauseDamage({
| 640| 640| 			"strengths": this.GetAttackStrengths(type),
| 644| 644| 			"type": type,
| 645| 645| 			"attackerOwner": attackerOwner
| 646| 646| 		});
| 647|    |-	}
|    | 647|+	
| 648| 648| };
| 649| 649| 
| 650| 650| /**

binaries/data/mods/public/simulation/components/Attack.js
| 505| ·»   let·cmpDamage·=·Engine.QueryInterface(SYSTEM_ENTITY,·IID_Damage);
|    | [NORMAL] ESLintBear (no-mixed-spaces-and-tabs):
|    | Mixed spaces and tabs.

binaries/data/mods/public/simulation/components/Attack.js
| 609| »   »   cmpTimer.SetTimeout(SYSTEM_ENTITY,·IID_Damage,·"MissileHit",·timeToTarget·*·1000·+·+this.template[type].Delay,·data);
|    | [NORMAL] JSHintBear:
|    | Confusing plusses.
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  23|  23| 	let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|    |-			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|    |  26|+		(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  24|  24| 	let turnLength = cmpTimer.GetLatestTurnLength();
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|    |-			0,
|    |  27|+		0,
|  28|  28| 			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|    | [NORMAL] ESLintBear (indent):
|    | Expected indentation of 2 tabs but found 3.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|  25|  25| 	return new Vector3D(
|  26|  26| 			(curPos.x * (turnLength - lateness) + prevPos.x * lateness) / turnLength,
|  27|  27| 			0,
|  28|    |-			(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|    |  28|+		(curPos.z * (turnLength - lateness) + prevPos.z * lateness) / turnLength);
|  29|  29| };
|  30|  30| 
|  31|  31| /**
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'if' condition.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 112| 112| 
| 113| 113| 	// Do this first in case the direct hit kills the target
| 114| 114| 	if (data.isSplash)
| 115|    |-	{
|    | 115|+	
| 116| 116| 		this.CauseSplashDamage({
| 117| 117| 			"attacker": data.attacker,
| 118| 118| 			"origin": Vector2D.from3D(data.position),
| 125| 125| 			"type": data.type,
| 126| 126| 			"attackerOwner": data.attackerOwner
| 127| 127| 		});
| 128|    |-	}
|    | 128|+	
| 129| 129| 
| 130| 130| 	let cmpProjectileManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ProjectileManager);
| 131| 131| 
|    | [NORMAL] ESLintBear (curly):
|    | Unnecessary { after 'else'.
|----|    | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
|    |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/components/Damage.js
| 218| 218| 				damageMultiplier = 0;
| 219| 219| 		}
| 220| 220| 		else // In case someone calls this function with an invalid shape.
| 221|    |-		{
|    | 221|+		
| 222| 222| 			warn("The " + data.shape + " splash damage shape is not implemented!");
| 223|    |-		}
|    | 223|+		
| 224| 224| 
| 225| 225| 		if (data.splashBonus)
| 226| 226| 			damageMultiplier *= GetDamageBonus(ent, data.splashBonus);
Executing section cli...

Link to build: https://jenkins.wildfiregames.com/job/differential/1506/display/redirect

This revision was not accepted when it landed; it landed in state Needs Review.May 26 2019, 2:45 PM
This revision was automatically updated to reflect the committed changes.

@Mate-86 I would suggest working on a simple graphical icon next, so that this can actually be used in-game without looking super weird and confusing players.

There are a bunch of options, I would recommend have at least an icon in the top-row of the unit's portrait when it's selected.
Then you can think of adding:

  • an icon on top of the unit when it's selected (like auras)
  • actual graphical effects (I think the best thing here would be to spawn an actor of some kind?)

@Mate-86 I would suggest working on a simple graphical icon next, so that this can actually be used in-game without looking super weird and confusing players.

There are a bunch of options, I would recommend have at least an icon in the top-row of the unit's portrait when it's selected.
Then you can think of adding:

  • an icon on top of the unit when it's selected (like auras)
  • actual graphical effects (I think the best thing here would be to spawn an actor of some kind?)

FYI: I've joined another project recently and I won't have time to work on this one in the near future. It was fun to work on this feature but feel free to take over any upcoming changes. I've set Trac #1912 to unassigned. Cheers! :)

Stan added a comment.Aug 11 2019, 9:46 PM

@Mate-86 Sad to hear that but I hope you'll have fun with your new project. What is it called ?

In D1252#90261, @Stan wrote:

@Mate-86 Sad to hear that but I hope you'll have fun with your new project. What is it called ?

It's an indie RTS written in JS/Phaser called Five Nations. You can checkout here: https://gamejolt.com/games/fivenations/389358