Jump to content
Madin

RA Spy behaviour in C&C3? (discussion)

Recommended Posts

I am looking into adding a spy unit into C&C3, and I was wondering what would be doable inside C&C3, when it comes to the spy's abilities from past RA games. I am going to list the abilities that I am interested in. If you have any ideas on thoughts on specific items in the list, then comment on them, there is no need for a total solution. If even a minimal number of these are possible, then it would be great!

If I have any ideas, I will also mention them in italics.

  1. Spy entering any enemy production structure shuts the structure down for a limited period of time. Covered by 'InfiltratorContain'.
  2. Spy entering any enemy unit production structure, will add veterancy for any unit that the player builds from their production structure that matches the type infiltrated by the spy.
  3. If the spy enters an enemy airfield, the player gains a single use support power.
  4. If the spy enters an enemy power plant, it will shut the power down for X amount of time. I guess that you could give the enemy an invisible structure that consumes an enormous amount of power, and that has a 'LifeTime' update.
  5. If the spy enters an enemy power plant, the amount of power that the enemy has is displayed. Not possible.
  6. Spy entering enemy Ore refinery steals a sum of money. Covered by 'InfiltratorContain'.
  7. Spy entering enemy Ore refinery displays the amount of credits that the enemy has. There are scripts that have to do with evaluating how much credit a player has, but I do not know if there is a way to display the result as a message.
  8. If the Spy enters an enemy radar (or whatever structure provides radar), the player will be able to see a limited breakdown of how many units the enemy has. If possible it will broken down by type 'AIRCRAFT', 'VEHICLES', 'INFANTRY' etc. There are scripts that have to do with evaluating how many units a player has, but I do not know if there is a way to display the result as a message.
  9. If the Spy enters an enemy radar (or whatever structure provides radar), the player will be able to see all the enemy units. My thought is that this would be done by triggering a version of the Scrin 'Tiberium vibration scan', that is coded to reveal units.
  10. If the Spy enters an enemy radar (or whatever structure provides radar), it will add shroud for the enemy player. There are scripts pertaining to shroud, but they are probably for mapping only.
  11. If the Spy enters an enemy radar (or whatever structure provides radar), it will disable the enemy radar for a period of time. Covered by 'InfiltratorContain' although there is overlap with disabling structure.
  12. If the Spy enters an enemy Super weapon (or any structure which provides support powers), it will reset the counter on the super weapon (or support powers). There are scripts that pertain to resetting the count on special powers.
  13. If the Spy enter into a tech structure, it will disable all enemy units that are unlocked by that structure for a period of time. Create a weapon with a 'PARALYSE' nugget and an 'ObjectFilter' with the enemy units to effect.
  14. The 'Bribe' ability. Have a special power that broadcast a lua event to enemy units in X radius, and have that event run a script that flips the enemy units side (there are scripts for this, this also may be a preferred solution to the old issue of recreating the KW Prodigy 'Area Of Effect' mind control ability, provided you have a script that returns control after X amount of time).

Once again, there is no expectation that the spy will be able to do all of these at once!

Thanks for your time.

Edited by Madin
Put a line through completed items

Share this post


Link to post

Try the InfiltratorContain. It has basicly 3 options:

Steal Money (not sure how much exactly), Disable the building, Freeze the radar.

  • Upvote 1

Share this post


Link to post

I remember one time when the CNCLabs team had this in The Red Alert in RA3. You might want to ask Blbpaws there how the spy behavior works in theirs.

Lauren had a partial experimentation on this as well: http://pastebin.com/cJJcByfv

Not sure if this will also work with LUA scripting.

Edited by PurpleGaga27
  • Upvote 1

Share this post


Link to post
3 hours ago, Stygs said:

Try the InfiltratorContain. It has basically 3 options:

Steal Money (not sure how much exactly), Disable the building, Freeze the radar.

This is good to know, thanks!

2 hours ago, PurpleGaga27 said:

Lauren had a partial experimentation on this as well: http://pastebin.com/cJJcByfv

Not sure if this will also work with LUA scripting.

That is certainly interesting.

Share this post


Link to post

1. Via dummy object that shots emp effect weapon with very little radius or via lua with ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Enabled", 0) or ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Powered", 0) in combination with a script timer.

2. Create lua object list filtered by object type and give veterancy via ExecuteAction("UNIT_GIVE_EXPERIENCE_LEVEL", ObjectStringName, ExperienceLevelTemplateName)

3. Spawn speical power provider dummy. The special power then also creates a killer dummy that kills itself and the provider.

4. Your solution.

5. We cannot directly know how much power the player has (scripts unusable). An overcomplicated solution could be to calculate the energy production - consumption manually via lua object lists + power events lua calculation coroutine. We can only know directly if one of these events happened in the last n seconds: "BuildingManuallyPoweredDown","BuildingManuallyPoweredUp","LowPower" (Use EvaluateCondition("HAS_EVA_EVENT_PLAYED_IN_LAST_N_SECONDS",EvaEvent,TimeIntervall) for that)

6. Via a dummy that provides an invisible special power that costs money. This SP gets executed via lua. I'll do that in meta mod to reset the credits for some gamemodes and handle credit income then only by scripts (sidenote: tiberium fields can also be removed permanently from the map).

7. Scripts not usable to know the amount of credits. We can only get to know the start ressources or if one of these events happened: "BuildQueuePausedDueToFunds","CannotRepairDueToFunds","CannotUsePowerDueToFunds" (Use EvaluateCondition("HAS_EVA_EVENT_PLAYED_IN_LAST_N_SECONDS",EvaEvent,TimeIntervall) for that)

Of course you can write your own lua coroutine that calculates the credits manually (very complicated but not impossible)

8. That's very possible. See meta mod function CountObjectTypeOfTeam(ObjectType,team). Usage example to display would be something like: ExecuteAction("SHOW_MILITARY_CAPTION", "Vehicles: " .. CountObjectTypeOfTeam("VEHICLE","Player_1/teamPlayer_1"),10). You can also display the counts via a typical counters and hide them after n seconds via script timer.

9. You can spawn an invisible unnattackable dummy on each enemy unit that has a little sight radius via lua meta mod special spawn functions.

10. No idea. The script won't work (they all depend on the player parameter, which is unusable atm).

11. Your solution or ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Powered", 0) applied on the radar providing structure temporarily via script timer.

12. ExecuteAction("NAMED_SET_SPECIAL_POWER_COUNTDOWN",...) or one of the other countdown scripts.

13. Your solution or via lua by creating an object table and using one or more parts of this:

function DisableObject(object)  
    local Status = {"NO_ATTACK","UNSELECTABLE","NO_COLLISIONS","UNATTACKABLE","CANNOT_BE_SOLD","IN_STASIS","IGNORE_AI_COMMAND","USER_PARALYZED","POWERED_DOWN_EMP","TEMPORARILY_DEFECTED"}
    for i=1,getn(),1 do
	  ObjectSetObjectStatus(GetObj.Table(object),Status[i])
    end
	ExecuteAction("NAMED_SET_HELD", object, 1)
	ExecuteAction("NAMED_SET_STRICT_CONTROL_ENABLED", object, 1)
	ExecuteAction("NAMED_SET_SLEEP_STATUS", object, 1)
	ExecuteAction("UNIT_SET_STANCE", object, "HOLD_POSITION") 
	ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Enabled", 0) 		  
	ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Indestructible", 1)	 
	ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Selectable", 0)	
	ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Player Targetable", 0)	
	ExecuteAction("UNIT_AFFECT_OBJECT_PANEL_FLAGS", object, "Unsellable", 1)
	ObjectForbidPlayerCommands(GetObj.Table(object),true)
end

14. Very possible. I'll do that in meta mod via a diplomacy menu option where you can toggle control for allied units. The function used for that is TemporaryMergeTeam(team1,team2,forcemerge). To toggle back you can use a script timer that calls the function again after n seconds. The function will toggle the units team automatically back. An example to use a script timer: SetScriptTimer(10,'ExecuteAction("SHOW_MILITARY_CAPTION","Hello World!",5 '). It takes a string and even a function for the second parameter.

So except for number 10 everything is somehow doable from my point of view.

 

Edited by Mjjstral
  • Upvote 1

Share this post


Link to post
36 minutes ago, Mjjstral said:

 

So except for number 10 everything is somehow doable from my point of view.

This is good to know, I will start on some of the simpler ones tomorrow.

Share this post


Link to post

The 'InfiltratorContain' has covered 3 of the items.

On to the more difficult items!

Edited by Madin
Duh!

Share this post


Link to post

The 'Bribe' support power is giving me issues (of course!). The script is received by units, but it does not transfer ownership.

The Bribe ability is a 'WeaponFireSpecialAbilityUpdate' that fires a weapon that has a lua nugget that targets enemies. the scripted event triggers this Lua code in the enemy unit:

<ScriptedEvent Name="AlliedSpyBribeEvent" /> 

<EventHandler EventName="AlliedSpyBribeEvent"	ScriptFunctionName="UnitSwitchAllegiance" DebugSingleStep="false"/>
function UnitSwitchAllegiance(self,other)
	ExecuteAction("NAMED_TRANSFER_OWNERSHIP_PLAYER", GetObj.String(self), GetObj.String(other))
	ExecuteAction("SHOW_MILITARY_CAPTION", "SCRIPT_COMPLETED", 5)
end

The test message plays, which indicates that the enemy units has received the scripted event, and executed the script.

Share this post


Link to post

 

Use this (You don't even need GetObj.String here I think):

ExecuteAction("UNIT_SET_TEAM",GetObj.String(other),GetTeamName(self))    

Or this, depending on who's self and who's other:

ExecuteAction("UNIT_SET_TEAM",GetObj.String(self),GetTeamName(other))    

Also use this to flash the unit for testing (very usefull):

ExecuteAction("NAMED_FLASH_WHITE", self, 2)

Needed dependencies:

function GetTeamName(teamobject) 
	local TeamName = ""
	local TeamDescription= ""
	if type(teamobject) == "string" then TeamDescription = ObjectTeamName(GetObj.Table(teamobject))
	else TeamDescription = ObjectTeamName(teamobject) end
	local TeamNumber = gsub(TeamDescription, "%a+%p+", "")
	if TeamNumber == nil then 
		return error("no team found")																						--"unknownTeam" 	
	end
	if strfind(TeamDescription, "SkirmishTeamPlayer") ~= nil then											--"Player_2/defaultSkirmishTeamPlayer_2"
		TeamName = "Player_" .. TeamNumber .. "/defaultSkirmishTeamPlayer_" .. TeamNumber .. ""    
		return TeamName			
	elseif strfind(TeamDescription, "teamPlayer") ~= nil then													--"Player_1/teamPlayer_1"   
		TeamName = "Player_" .. TeamNumber .. "/teamPlayer_" .. TeamNumber .. ""  
		return TeamName	
	elseif strfind(TeamDescription, "Civilian") ~= nil then														--"PlyrCivilian/teamPlyrCivilian"
		TeamName = "PlyrCivilian/teamPlyrCivilian"
		return TeamName	
	elseif strfind(TeamDescription, "Creeps") ~= nil then														--"PlyrCreeps/teamPlyrCreeps"
		TeamName = "PlyrCreeps/teamPlyrCreeps"
		return TeamName	
	elseif strfind(TeamDescription, "teamPlyr") ~= nil then														--"PlyrNOD/teamPlyrNOD"
		TeamName = strsub(TeamDescription, 5, -1) .. "/" .. TeamDescription .. ""
		return TeamName	
	elseif strfind(TeamDescription, "SkirmishTeam") ~= nil then												--"Nod_Enemy_Main/defaultSkirmishTeamNod_Enemy_Main"
		TeamName = strsub(TeamDescription, 20, -1) .. "/" .. TeamDescription .. ""
		return TeamName			
	elseif strfind(TeamDescription, "/team") ~= nil and strlen(TeamDescription) == 4 then	--"/team" for neutrals
		TeamName = "/team"   
		return TeamName	
	else
		TeamName = gsub(strsub(ObjectDescription(teamobject),strfind(ObjectDescription(teamobject), "player ")+10),"%p","") .. "/" .. TeamDescription .. ""
		return TeamName	
	end
end

function GetObj.Table(object) 
    if type(object) == "table" then return object
	else  
		for k,v in globals() do
		  if strfind(k,"ObjID") ~= nil and strfind(ObjectDescription(v),object) then
			return rawget(globals(),k)
		  end
		end
		return object
	end
end

 

Edited by Mjjstral
  • Upvote 1

Share this post


Link to post
1 hour ago, Mjjstral said:

Or this, depending on who's self and who's other:


ExecuteAction("UNIT_SET_TEAM",GetObj.String(self),GetTeamName(other))    

Also use this to flash the unit for testing (very usefull):


ExecuteAction("NAMED_FLASH_WHITE", self, 2)

 

Success!  excellent.

I will leave the Spy as is, basic, but there is enough to test here. Once everything is stable, I will add more (at a later date).

Thanks!

Share this post


Link to post

i know there ar mapscripts to display a money counter, in theory alot of the map scripts should/could be re-creatable with lua...

Might want to have a look at this tutorial , Mjjstral might be able to adapt it?

 

Share this post


Link to post
20 hours ago, Ravendark said:

i know there ar mapscripts to display a money counter, in theory alot of the map scripts should/could be re-creatable with lua...

Might want to have a look at this tutorial , Mjjstral might be able to adapt it?

 

It will not work because it is part of the 'PLAYER SCRIPT ACTIONS'.

Share this post


Link to post
8 hours ago, Madin said:

It will not work because it is part of the 'PLAYER SCRIPT ACTIONS'.

A workaround would be to call the map scripts that have a player parameter from lua with this special command:

ExecuteAction("TEAM_EXECUTE_SEQUENTIAL_SCRIPT_LOOPING","/team",MapScriptName,1)

If we set the player in the map script to <this player> then we can even choose the player by changing "/team" to the team of that player. This is a very neat trick.

And in KW we can insert a map script into ALL official maps in one move by adding it to a library map (lib_mg_tacticalplay_skirmish).

Share this post


Link to post
On 11/06/2017 at 1:41 AM, Madin said:

Success!  excellent.

I will leave the Spy as is, basic, but there is enough to test here. Once everything is stable, I will add more (at a later date).

Thanks!

function UnitSwitchAllegiance(self,other)
	ExecuteAction("UNIT_SET_TEAM",GetObj.String(self),GetTeamName(other))
	ExecuteAction("NAMED_FLASH_WHITE", self, 2)
	-- ExecuteAction("SHOW_MILITARY_CAPTION", "SCRIPT_COMPLETED", 5)
end

While this code will work with human players, it will not work if the AI attempts to use it, as units are auto assigned into random new teams by AI (This is from CNCisDead):

-- Dont use ObjectTeamName() command because it fails with AI players (units are auto assigned into new teams by AI)

He uses:

	local p1 = strsub(ObjectDescription(other),strfind(ObjectDescription(other), "owned by ") + 9)
	local p2 = strsub(ObjectDescription(self),strfind(ObjectDescription(self), "owned by ") + 9)

I will try something around that.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×