Enhanced Balance Mod for 3.x

Did you create a mod, map, music, or a tool? Present them here and earn feedback!
Note: addon requests do not belong here.
Note, everything uploaded to this forum, MUST have a license!
Post Reply
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Hey all thanks for the quick replies,
NoQ wrote: To me, some of the biggest flaws of Nexus included inability to counter spam (tank spam, cyborg spam, tower spam, machinegun spam, rocket spam) by countering them with tech and production choices
I definitely agree. The fact that Nexus doesn’t produce good units or choose good research choices means that it’s essentially unplayable for decent players but newbies don’t realize that. I fixed this by statically populating the template and research arrays. This is an example of what I mean when I say fix something and be done with it. Now that the template and research arrays are ordered from the beginning of the tech tree to the end using each weapon path, this AI essentially cannot be out-researched or produced. The arrays can be adjusted a little bit for specific game/map settings but generally speaking it makes the best units and researches the best things at all times for its chosen profile and the profiles are chosen based on map/game settings so it’s not really possible to achieve anything better in regards to droid designs and research objectives, there’s nothing left to do, it’s fixed and done with.

Nexus pursues research objectives regardless of power and I set power management checks on droid production; cyborgs, tanks and VTOLS only produce with minimum of 25, 50 and 700 power I think. Those numbers can be adjusted but the arrays themselves are pretty much finalized.

Profiles are chosen based on 40/40/20 chance of choosing rocket, cannon, flamer for no allies or no shared research. If shared research then flamer if map size < 130, cannons 130 – 170 and rockets 170+. Likelihood of artillery branch uses the linear function with map size 90 = 0

Code: Select all

Code for selecting research profiles

	_ally = 0;
	_count = 0;
	while(_ally < MAX_PLAYERS)
	{
		if(allianceExistsBetween(me, _ally)){
			_count++;
		}
		_ally++;
	}

	if(_count > 0 and multiPlayerAlliancesType == ALLIANCES_TEAMS)
	{	
		if(_mapSize < 130.0)
		{
			curTech = branchFlameVtolLaser;
			dbg("going rockets (" & _y & "/" & _rnd & ")", me);
		}	
		else if(_mapSize  < 170.0)
		{
			curTech = branchCannonMGMortar;
			dbg("going cannons (" & _y & "/" & _rnd & ")", me);
		}
		else
		{
			curTech = branchRocketMGMortar;
			dbg("going Mortar (" & _y & "/" & _rnd & ")", me);
		}	
	}
	else
	{
		//probability to choose artillery branch for map size 90 = 0; probability for map size 200 = 55
		//build a linear function: y = ((y2 - y1) / (x2 - x1)) * x + a depending on two values given (short: y = mx+a)
		_x1 = 90.0; _y1 = 0.0;
		_x2 = 200.0; _y2 = 55.0;
		_m = ((_y2 - _y1) / (_x2 - _x1));
		_a = -(_m * _x1);

		//calculate probability for the current map
		_y = _m * _mapSize + _a;

		dbg("_m = " & _m & ", a = " & _a, me);

		_rnd = (float)random(100);
		if(_rnd  < _y)
		{
			curTech = branchArtillery;
			dbg("going air (" & _y & "/" & _rnd & ")", me);	
		}
		else
		{
			__rnd = random(10);
			if(__rnd  < 4)
			{
				curTech = branchRocket;
				dbg("going rockets (" & _y & "/" & _rnd & ")", me);
			}	
			else if(__rnd > 6)
			{
				curTech = branchCannon;
				dbg("going cannons (" & _y & "/" & _rnd & ")", me);
			}
			else
			{
				curTech = branchFlamer;
				dbg("going flamer (" & _y & "/" & _rnd & ")", me);
			}
		}
	}


The same goes for the base building. I set base build sequence to factory, research, power, derrick and then the base building triggers for each structure are called every < 7 - 10 seconds. Structure modules are upgraded from nearest to furthest as soon as modules are available. You can attempt to make a bot that builds a better base but programmatically I don’t see how it can be improved much.

There are 4 things I can think of that still need fixing with base building before I would declare that it’s close to perfection. The first is building base structures in the closest spot location instead of elsewhere in the base, the second is to check if there is a cliff between the truck and proposed building location, the third is to set a 3 truck minimum when upgrading structures and the 4th is to create multiple build groups. If I fix those 4 things then base building behavior is essentially done with, it’s not really possible to build a faster base but even without these 4 items the base building performance is still optimized and better than all other bots. Base building is another one of those things that once it’s fixed it’s done with.
Berserk Cyborg wrote:
MIH-XTC wrote:This bot will smash all other current and foreseeable bots most of the time with the exception of certain small map, low oil rush games.
Naturally. How can you expect other AI, which are only 'balanced' in regards to the base game, to be anywhere near as good as your bot when introduced to all of your changes? It is totally unfair to make that judgement unless the other bots are tweaked for your balance. Anyway, the modified Nexus AI you included is amazing none the less.
It doesn’t have anything to do with the stats but rather 3 of the 4 components of a WZ game are near flawless, base building, research objectives and droid designs are all near optimal performance. It’s really just a matter of not being able to make a better AI outside of droid behaviors. Although my bot does take advantage of the fact that I made mortar arrive earlier (after sensor tower instead of factory).

The only remaining and subjective component of a WZ game is droid handling and that’s where things get complicated. I haven’t done much with unit orders as that is the hardest part of making an AI.
NoQ wrote: , and also inability to group up units before engaging in combat. Most of NullBot's complexity is about these features.

I haven’t touched anything with droid behaviors besides changing most of the DORDER_MOVE’s to SCOUT because too many times I seen Nexus droids suicide into other armies because they don’t know to stop on enemy contact. Actually bonecrusher does a really good job of grouping units and then attacking, bonecrusher’s rally points are very observable prior to attacking. Not sure if Nullbot does the same. Bonecrusher also does a really good job of 1v2’ing.
There is a small bug I created in an attempt to get VTOL’s to attack relentlessly in which the VTOL’s remain idle over their target. Instead of attacking targets I made the VTOL’s patrol to their target coordinates meaning they attack anything in sight on their way to their target. The problem is that the secondary patrol order needs to be set after every new DORDER and once the VTOL’s are done attacking an object in route to their target, they proceed to their target without any attack order. One alternative is to set secondary patrol orders on vtols every time they arrive at their destination but then this overrides the rearming orders and the VTOL’s are stuck flying around without ammo. The solution to that is to check vtol ammo levels but there aren’t any functions available in mp for that. Right now I have the VTOL’s set to attack anything in route to their target but after they kill one object the patrol orders come off and then they’re stuck idling around their target until they die.
NoQ wrote: Note that the former is quite useless in AI vs AI matches, because AIs already avoid spam strategies, but newbie humans don't, and the primary sense of having good AIs is to teach humans to play better.

AI vs AI games essentially end up being a spam fast. Testing AI vs AI is almost like creating a droid collider similar to a particle collider. The weapons with longer ranges usually win in AI vs AI, especially grenadier although Nullbot did a really good job of using flamers and mg’s to overcome that. In larger games no AI will be able to stop the spam of this Nexus AI because it’s guaranteed to have superior droid upgrades and designs.

I also agree that the purpose of an AI is not to win but rather to prepare players for mp because mp and base are two totally different games and Nexus does not prepare players for playing in mp. I prioritized variation over winning in terms of droid designs, some of the research choices, some of the strategy choices and decision to build defensive structures. If I wanted to make a bot that would win all of the time then I would just do flamer + truck rush but the default AI should showcase how all of the different strategies are intended to be used.
NoQ wrote: At the same time, winning AI vs AI matches is a good achievement, but i suspect i could easily provide a NullBot personality (~100 lines of code) that would be better than your AI on your test cases (given the test cases);
I think not because the only thing that’s possible to do better is droid handling. The research objectives, droid designs and base building are already optimized to near perfection so the longer the game goes on, the harder it will be to beat this AI. The only time this Nexus AI is vulnerable is in the early base building phase because it takes the gamble of building a base instead of rushing. Other than that, once this bot gets going it will always win in AI vs AI because like I said, the research arrays, template arrays and base building are optimized to the point where you won’t be able to develop a better AI. It’s not really possible unless you have the same or very similar arrays. It’s fixed and done with…


Once I improve the droid behaviors and defend against early rush then this bot will be unbeatable. Actually, the only time it loses now is because some of the droids stand around in the base while it’s being attacked and they don’t do anything. Once that’s fixed, there’s really no chance for this bot to lose vs another bot…
NoQ wrote: Note also that NullBot, with all these features and many other human-oriented tweaks (eg. varied gameplay, and also chat support) has less lines of code than the current Nexus AI, and you are already adding 2000 more lines of code with your patch. From just that i'd conclude that my language choice was correct, and it is a consistent observation that javascript code is generally ~4 times shorter for the same amount of features (we notice it in the campaign as well).

Yea but that stuff is transparent to the end users/players, I don’t mind to use any programming language, I didn’t use .js only because I don't understand how the Nullbot triggers work (where are they?) and I'm very desperate to be finished with this project and move on. I’m under the impression that once I get this stuff “fixed” it’s done with and I’ll never have to return to it. Since I’m already familiar with the .vlo and .slo files I just want to keep going. Someday I will go back and look at the .js for the sake of learning .js but I have too much WZ and IRL stuff to do. I just don't want to invest the time to learn .js right now. I'm actually impressed that you could even pursue something like that. Rewriting the Nexus files in .js sounds like an insane task. Like you said in your dear programmers thread in "other talk" people work on whatever makes them happy.

NoQ wrote: That said, i appreciate your work and i'd approve adding your AI to the game (as long as it's using the base game's data and works without your data mods), probably as an extra AI alongside Nexus if we want to keep Nexus available as a nostalgic "like the old times" option (i personally don't enjoy having Nexus around, so i'd approve replacement as well).
That’s unfortunate you don’t like the stats, I bet it’s about 45% you want to preserve originality in the code and 45% I changed so much stuff that you don’t have any way of verifying the changes, 10% lost credibility of things I might have said in this thread prior to knowing what I know now. The problem with the current stats is that the game is too deterministic in terms of strategy. Everyone thinks that because there are hundreds of research items and thousands of droid designs that WZ offers complex strategy but it’s actually the opposite, you can just straight up calculate the best strategy for any given map/game settings to guarantee victory 100% of the time unless the same exact strategy is employed. That's not obvious to other people but I'm sure I can beat any player in mp. In fact, if you provide me the game and map settings then I can tell you down to the keystroke exactly what I would do before the game begins and still win. The game consists of the 4 components I mentioned above with droid handling being the only subjective one. Here’s an example of the best strategy on Arid map consisting of build order, truck order and research order https://www.youtube.com/watch?v=u8irDuPU7Sk exact instructions are in the description. That’s why I want to change the stats because I already know exactly what to do for all maps and there is no counter strategy. That strategy in the video cannot be countered by flamers or rockets, there’s nothing you can do besides the same thing. I hope you reconsider on the stats. Sorry for coming off as dogmatic but I know WZ very well.
Last edited by MIH-XTC on 18 Apr 2017, 23:51, edited 1 time in total.
User avatar
NoQ
Special
Special
Posts: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Enhanced Balance Mod for 3.x

Post by NoQ »

I appreciate rebalancing either, as balancing flaws are well-known, but currently i'm in no position to discuss that, so i skipped that topic (at the risk of being off-topic and not helpful). Balancing is often a matter of hot discussions, and you can't easily include multiple balances with the base game (without mods), so it's not as simple as the common open-source approach of "it's ok as long as you're committing time into maintaining it" - it's a hard decision to be made. So having AI changes separate from balance changes would certainly help.
the research arrays, template arrays and base building are optimized to the point where you won’t be able to develop a better AI
That's great. In the worst case, i'd have to steal these arrays then to fulfill my claim; apologies for not having time to back up my words with any real evidence...
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

That's great. In the worst case, i'd have to steal these arrays then to fulfill my claim; apologies for not having time to back up my words with any real evidence...
Naw man, no need to apologize, I understand that it's just loose talk and that we don't have time to get caught up in petty claims.

NoQ wrote:I appreciate rebalancing either, as balancing flaws are well-known, but currently i'm in no position to discuss that, so i skipped that topic (at the risk of being off-topic and not helpful). Balancing is often a matter of hot discussions, and you can't easily include multiple balances with the base game (without mods), so it's not as simple as the common open-source approach of "it's ok as long as you're committing time into maintaining it" - it's a hard decision to be made. So having AI changes separate from balance changes would certainly help.
Ah okay, I thought you meant that you wanted the stats separate from the AI because you didn't like them. It would take a couple of hours to separate them but I'm done with WZ for awhile, that's why I posted what I have yesterday. I also wasn't mindful that as staff the topic may be out of scope and I don't blame you for avoiding the politics.

I suppose this is an executive decision then? The board of directors? I won't name names but basically the 6 people on the Github splash.

I understand that changing the stats is altering the game at a fundamental level. Heck, I realized that before I started this thread and all of the unnecessary verbosity is me just lobbying for credibility to make such changes. Just to be clear, the stats that I have are only for mp/skirmish games, they don't affect base.

I'm open to adding/removing anything in particular, it doesn't have to come in one package. What is good about the stats and what is bad? I've tried several approaches at how to best categorize and explain stat changes to no avail. If you're not able to open the stats editor in Excel 2010/2013 then it might be hard for that person to understand how to identify what has changed.

I'm done for awhile, too much typing here.
User avatar
Prot
Trained
Trained
Posts: 242
Joined: 29 Nov 2010, 12:41

Re: Enhanced Balance Mod for 3.x

Post by Prot »

I found some time to test your bot, I will say it was a very entertaining match and a little bit not fair.
I have used my unpublished bot which is under development.
I was very surprised when my builders just die next to the oil extractors which are not protected, then I noticed that your extractors are shot by themselves from a machine gun. Whoooaaa?!
Despite the fact that my bot was holding about 90% of the resources, your bot continued indefinitely to produce an army, how many resources? My bot took about 40 minutes to keep Nexus under siege for the victory.
Too much new technology, which my bot doesn't know, particularly amused by the speed of the units in ~2.5 times the speed of my bot.
Despite such an unfair match, it was very fun to watch.
https://youtu.be/nxntfAP9Uu4
Last edited by Prot on 20 Apr 2017, 06:08, edited 1 time in total.
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Thanks a lot for uploading a video
I was very surprised when my builders just die next to the oil extractors which are not protected, then I noticed that your extractors are shot by themselves from a machine gun. Whoooaaa?!
Yea, I added a new “guarded” oil derrick that automatically becomes available after researching MG “guard” tower. The stats of the guarded derrick are supposed to be in between a derrick and an MG tower. I got the idea from NoQ here viewtopic.php?f=42&t=11552

Here are the stats for the derricks and guarded tower.
Image

It's very lame that I don't have a different graphical .pie model for the guarded derrick, I don't know how .pie files work. It is a little bit weird to see a magical mg appear from the derrick.

Despite the fact that my boat was holding about 90% of the resources, your bot continued indefinitely to produce an army, how many resources?
That is because the base power on power generators increased from 55 power per minute to 80 and the power module was increased from 28 power per minute to 40 (with 4 derricks). The reason for this is to allow for more power on low oil maps, that’s why there are more units, more research and more “activity” in general when playing with my bot, there is more power. Since all players currently play with the high power setting then they can change it to medium power or low power if it’s too much for them but there’s no such option for players who currently want more power on low oil maps because the high power setting is already maxed out. That’s probably why the AI was able to survive off 4 – 6 derricks and why low oil maps are more fun.

EDIT: hey by the way, when you test, do you use 100X speed?
Last edited by MIH-XTC on 20 Apr 2017, 04:33, edited 1 time in total.
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Here's complete documentation to stat changes from editor for those who can't view excel 2010/2013 (which I have a feeling is everyone).

Green = improvement
Red = nerfed
Yellow = change to text (non-integer)

Unfortunately the editor only shows what has changed, not by how much.

Changes to bodies:
Image


New research items added to the tech tree. Please tell me which ones to remove if you don't like them. Also the names I don't care about, that's overhead to me. I re-used the existing icons to display on the research menu. So range upgrades for weapon lines use icons heavy mg, MRA, medium cannon, bombard, inferno.

Image


Changes to research pre-requisites:
Image

Complete list of all tech tree items with dependencies and upgrade values
Image


Changes to propulsions:
Image

Changes to repair:
Image

Changes to construction:
Image

Changes to sensors:
Image

Changes to structure damage modifiers:
Image


Changes to structures:
Image

New templates added for AI use:
Image

Changes to weapon modifiers:
Image

Changes to weapons: (Note that I created another instance of the weapons for the structures so that they can be modified independently. Programmatically it's ugly but gameplay wise it's the ticket.
Image


I also had to model the cyborg speeds to help make sure they were balanced. Thanks again to crab for showing me this formula
Image
Last edited by MIH-XTC on 20 Apr 2017, 06:01, edited 1 time in total.
User avatar
Prot
Trained
Trained
Posts: 242
Joined: 29 Nov 2010, 12:41

Re: Enhanced Balance Mod for 3.x

Post by Prot »

New research items added to the tech tree. Please tell me which ones to remove if you don't like them.
here you can't just say "I don't like it, remove it," every change of stats, research, armor, radius, etc. will greatly affect the game overall, as at the beginning and at the end. Here we need many matches to spend with different people, to understand where the imbalance is and then convincingly say "remove it".

as soon as I have free time again, I will continue work on the bot, I was interested in the mod, because there is something new and I think will do a separate tuning my bot, designed straight for your modification.
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Status Update:

Still working on improving Nexus AI, I only have a couple of more things I want to improve. I added some behaviors that are outlined below in code chunks

Summary:
- knows how to defend now (automatically attacks anything within 15 tiles of base if we have at least 10 attack droids).
- no longer has droids accumulating in base doing nothing. (caused stalemates in long/big games)
- knows how to help allies and builds base even faster by selecting optimal build locations.

Details are below:

--------- Added some constants for easily modding power management checks

Code: Select all

			#define	MIN_BUILDPOWER_CYBFACTORY		25
			#define MIN_BUILDPOWER_FACTORY			400
			#define MIN_BUILDPOWER_RESCENTER		250
			#define MIN_BUILDPOWER_VTOLFACTORY		600 // except VTOL research profile
			
			#define MIN_PRODUCTIONPOWER_FACTORY			25
			#define MIN_PRODUCTIONPOWER_CYBFACTORY		10
			#define MIN_PRODUCTIONPOWER_VTOLFACTORY		100
			#define MIN_PRODUCTIONPOWER_TRUCK			150		
			
			#define MIN_BUILDPOWER_DEFENSE				200
			#define MIN_BUILDPOWER_EXTRASTRUCTS			200
			#define MIN_BUILDPOWER_ARTILLERY			0	// only artillery and shared allied research profiles build artillery



-------- Improved buildPowerGenerators() to find the closest truck to the closest available location in a 10x10 area centered on base. Then I copied this event and swapped out the power generators for other base structures. The most optimal location might be off by 2 - 3 tiles (at most) due to how it loops (on diagonal) but it's still a huge improvement over previous Nexus.

I also tried like heck to figure out how to detect a cliff in between a constructor droid and target build location but concluded it's not possible with current WZscript. Below is my failed attempt in the commented out section at the bottom of the code using droidCanReach()


Here's how often I'm calling the base build structure triggers using the code below and the power management checks above. This is how Nexus sets up a base.

(40 = 4 seconds for those who don't know)

trigger upgradeStructuresTr (every, 40);
trigger buildPowerGeneratorsTr (every, 50 ); // for every 4 derricks we have
trigger buildResearchCentersTr (every, 70 ); // for every 4 derricks we have
trigger buildFactoryTr (every, 120 ); // for every 5 derricks we have
trigger buildDerrickTr (every, 140 );
trigger buildCyborgFactoryTr (every, 150 ); // for every 5 derricks we have
trigger finishStructsTr (every, 210);
trigger buildVTOLFactoryTr (every, 350 );

Code: Select all

	
			/////////////////////////////////////////////////////////////////////
// build a power gen for every 4 derricks. VITAL!
event buildPowerGenerators(buildPowerGeneratorsTr)
{
	local	INT		_count,_bestDist,_newDist,_closestX,_closestY,_truckX,_truckY,_buildGenX,_buildGenY;
	local 	DROID   _closestTruck;
	local 	bool	_obstacle;

	_buildGenX = buildX;
	_buildGenY = buildY;
	
	if (!isStructureAvailable(powGen, me))
	{
		exit;
	}
	initEnumStruct(FALSE,derrick,me,me);					// count = numderricks
	structure= enumStruct();
	count	 = 0;
	while(structure != NULLOBJECT)
	{
		count = count + 1;
		structure= enumStruct();
	}
	
	initEnumStruct(FALSE,gderrick,me,me);					// count = num Guarded derricks
	structure= enumStruct();
	_count	 = 0;
	while(structure != NULLOBJECT)
	{
		_count = _count + 1;
		structure= enumStruct();
	}
	
	count = _count + count;

	initEnumStruct(FALSE,powGen,me,me);					// count2 = numpowgens
	structure= enumStruct();
	count2	 = 0;
	while(structure != NULLOBJECT)
	{
		count2 = count2 + 1;
		structure= enumStruct();
	}

	if( (count2 * 4) < count )								// if we need powergen
	{
		_closestX = 0;
		_closestY = 0;
		_bestDist = 99999;
		
		initIterateGroup(buildGroup);
		droid = iterateGroup(buildGroup);
		while(droid != NULLOBJECT)
		{
			if (droid.order != DORDER_HELPBUILD and droid.order != DORDER_BUILD and droid.order != DORDER_LINEBUILD)
			{
			
			_count = 1;
			while(_count < 10) // this loop checks a 10x10 area centered on the base for the truck that is closest to an available location for a power generator
			{
					// Negative X coordinate checks to the left of the base
					// Positive X coordinate checks to the right of the base
					// Negative Y coordinate checks below the base
					// Positive Y coordinate checks above the base
					
					// Positive X, Positive Y
					_buildGenX = baseX + _count;
					_buildGenY = baseY + _count;
					if (pickDroidStructLocation(droid, powGen, ref _buildGenX, ref _buildGenY, me, 1))
					{
						_newDist = distBetweenTwoPoints(droid.x, droid.y, _buildGenX, _buildGenY);
				
						if (_newDist < _bestDist and droidCanReach(droid, _buildGenX, _buildGenY))	// this one is closer
						{
							_bestDist = _newDist;
							_closestX = _buildGenX;
							_closestY = _buildGenY;
							_closestTruck = droid;
						}
					}
					
					// Positive X, Negative Y
					_buildGenY = baseY + (_count * -1);
					if(_buildGenY > 0 and _buildGenY < mapHeight)
					{
					if (pickDroidStructLocation(droid, powGen, ref _buildGenX, ref _buildGenY, me, 1))
					{
						_newDist = distBetweenTwoPoints(droid.x, droid.y, _buildGenX, _buildGenY);
				
						if (_newDist < _bestDist and droidCanReach(droid, _buildGenX, _buildGenY))	// this one is closer
						{
							_bestDist = _newDist;
							_closestX = _buildGenX;
							_closestY = _buildGenY;
							_closestTruck = droid;
						}
					}
					}
					
					// Negative X, Negative Y
					_buildGenX = baseX + (_count * -1);
					if(_buildGenX > 0 and _buildGenX < mapWidth)
					{
					if (pickDroidStructLocation(droid, powGen, ref _buildGenX, ref _buildGenY, me, 1))
					{
						_newDist = distBetweenTwoPoints(droid.x, droid.y, _buildGenX, _buildGenY);
				
						if (_newDist < _bestDist and droidCanReach(droid, _buildGenX, _buildGenY))	// this one is closer
						{
							_bestDist = _newDist;
							_closestX = _buildGenX;
							_closestY = _buildGenY;
							_closestTruck = droid;
						}
					}
					}
					
					// Negative X, Positive Y
					_buildGenY = baseY + (_count * -1);
					if(_buildGenY > 0 and _buildGenY < mapHeight)
					{
					if (pickDroidStructLocation(droid, powGen, ref _buildGenX, ref _buildGenY, me, 1))
					{
						_newDist = distBetweenTwoPoints(droid.x, droid.y, _buildGenX, _buildGenY);
				
						if (_newDist < _bestDist and droidCanReach(droid, _buildGenX, _buildGenY))	// this one is closer
						{
							_bestDist = _newDist;
							_closestX = _buildGenX;
							_closestY = _buildGenY;
							_closestTruck = droid;
						}
					}
					}
					_count++;
				}
			}
			droid = iterateGroup(buildGroup);
		}
		
		// this checks the reachability of every tile in between the truck that is closest to the nearest available build location for any obstacles on the path e.g. cliffs
		// DOES NOT WORK - The logic is correct but droidCanReach was not intended to be used like this, it's not able to detect cliffs.
		// I think cliffs are still reachable via the adjacent tile so droidCanReach is not able to detect cliffs with less than 3 tile width.
//		_obstacle = FALSE;
//		if(_closestTruck != NULLOBJECT)
//		{
//			_count = _closestTruck.x;  // = x coordinate of proposed constructor droid
//			count = _closestTruck.y;
//			
//			if(_closestX > _count)  // _closestX = x coordinate of proposed building location
//			{
//				while(_count < _closestX)
//				{
//					_count = _count + 1;
//					
//					if(_closestY > count)
//					{
//						while(count < _closestY)
//						{
//							count = count + 1;
//							if(!droidCanReach(_closestTruck, _count, count))
//							{
//								_obstacle = TRUE;
//								count = _closestY;
//								_count = _closestX;
//							}
//						}
//					}
//					else
//					{
//						while(count > _closestY)
//						{
//							count = count - 1;
//							if(!droidCanReach(_closestTruck, _count, count))
//							{
//								_obstacle = TRUE;
//								count = _closestY;
//								_count = _closestX;
//							}
//						}
//					}
//				}
//			}
//			else
//			{
//				while(_count > _closestX)
//				{
//					_count = _count - 1;
//					
//					if(_closestY > count)
//					{
//						while(count < _closestY)
//						{
//							count = count + 1;
//							if(!droidCanReach(_closestTruck, _count, count))
//							{
//								_obstacle = TRUE;
//								count = _closestY;
//								_count = _closestX;
//							}
//						}
//					}
//					else
//					{
//						while(count > _closestY)
//						{
//							count = count - 1;
//							if(!droidCanReach(_closestTruck, _count, count))
//							{
//								_obstacle = TRUE;
//								count = _closestY;
//								_count = _closestX;
//							}
//						}
//					}
//				}
//			}
//		}

		// if there are no obstacles then have the truck closest to the nearest available location build a generator
		if (pickDroidStructLocation(_closestTruck, powGen, ref _closestX, ref _closestY, me, 1) and _closestTruck != NULLOBJECT and _obstacle != TRUE)
		{
			orderDroidStatsLoc(_closestTruck, DORDER_BUILD, powGen, _closestX, _closestY);
		}
	}
}
		



-------- Created event enemyNearBaseTr to manage defending the base. It beacons the closest enemy droid within 15 tiles of the base and automatically requests help from other Nexus allies. Since I have it triggered every 5 seconds I ended up using this for some other house keeping items that need to be frequently checked e.g. make sure all trucks belong to buildGroup, make sure repair droids in our base are repairing instead of getting hung on DORDER_RTR, prevent droids from accumulating in base while doing nothing.

Code: Select all

event enemyNearBase(enemyNearBaseTr)
{
	local DROID _droid,_giveTruck,_enemy;
	local int _count,_droidAtHq,_numTruck,_powerTransfer,_myPower,_allyPower,_targetX,_targetY,_findEnemyX,_findEnemyY;
	local bool _haveTarget,_haveTruck,_droidInRange;

			_count = 0;
			while(_count < 10) 
			{
				if(!allianceExistsBetween(me, _count))
				{
					_droidInRange = FALSE;
					if(droidInRange(_count, baseX, baseY, (15 * TILE))) // find enemy droids within 15 tiles below and to the right of our base
					{
						_findEnemyY = baseY + (15 * TILE);
						_findEnemyX = baseX + (15 * TILE);

						//Positive X, Positive Y
						if(_findEnemyY > 0 and _findEnemyY < (mapHeight * TILE) and _findEnemyX > 0 and _findEnemyX < (mapWidth * TILE))
						{
							_enemy = droidTargetInArea(_count, me, baseX, baseY, _findEnemyX, _findEnemyY);
							if (_enemy != NULLOBJECT)
							{
								_droidInRange = TRUE;
								_targetX = _enemy.x;
								_targetY = _enemy.y;
							}
						}
						
						//Positive X, Negative Y
						_findEnemyY = baseY + (15 * TILE * -1); // find enemy droids within 15 tiles above and to the right of our base
					
						if(_findEnemyY > 0 and _findEnemyY < (mapHeight * TILE))
						{
							_enemy = droidTargetInArea(_count, me, baseX, baseY, _findEnemyX, _findEnemyY);
							if (_enemy != NULLOBJECT)
							{
								_droidInRange = TRUE;
								_targetX = _enemy.x;
								_targetY = _enemy.y;
							}
						}
					
						// Negative X, Negative Y
						_findEnemyX = baseX + (15 * TILE * -1); // find enemy droids within 15 tiles above and to the left of our base
					
						if(_findEnemyX > 0 and _findEnemyX < (mapWidth * TILE))
						{
							_enemy = droidTargetInArea(_count, me, baseX, baseY, _findEnemyX, _findEnemyY);
							if (_enemy != NULLOBJECT)
							{
								_droidInRange = TRUE;
								_targetX = _enemy.x;
								_targetY = _enemy.y;
							}
						}
						
						// Negative X, Positive Y
						_findEnemyY = baseY + (15 * TILE * -1); // find enemy droids within 15 tiles below and to the left of our base
					
						if(_findEnemyY > 0 and _findEnemyY < (mapHeight * TILE))
						{
							_enemy = droidTargetInArea(_count, me, baseX, baseY, _findEnemyX, _findEnemyY);
							if (_enemy != NULLOBJECT)
							{
								_droidInRange = TRUE;
								_targetX = _enemy.x;
								_targetY = _enemy.y;
							}
						}
						//setEventTrigger(findEnemy,attackStuffTr);
					}

				}
				
				if(_droidInRange)
				{
					count = 0;
					while(count < 10) 
					{
						if(allianceExistsBetween(me, count))
						{
							if(!haveBeacon(me))
							{
								dropBeacon(getPlayerName(me), count, me, _targetX, _targetY, 0); // if we found an enemy droid within 15 tiles drop a beacon on that droid
							}
						}
					count++;
					}
				
				}
				_count++;
			}
		
	
	_droidAtHq = 0;
	InitEnumDroids(me,me);
	_droid = EnumDroid();
	while (_droid != NULLOBJECT) 
	{
		if(_droid.order == DORDER_RTR or _droid.order == DORDER_GUARD or _droid.action == DACTION_WAITFORREPAIR and _droid.health > 80) // this prevent droids from accumulating in the base while standing around doing nothing
		{
			_droidAtHq++;
			orderDroid(_droid, DORDER_STOP);
			groupAddDroid(attackGroup, _droid);
		}
		
		if(_droid.droidType == DROID_CONSTRUCT or _droid.droidType == DROID_CYBORG_CONSTRUCT) // make sure all construction droids belong to buildGroup. If ally gives us a truck, this is how it's added to build group
		{
			groupAddDroid(buildGroup, _droid);
		}

		if(_droid.droidType == DROID_REPAIR or _droid.droidType == DROID_CYBORG_REPAIR) // sometimes repair droids in our base don't repair because they're waiting for someone to repair them. Let's check for these circumstances and reset orders if so.
		{
			if(distBetweenTwoPoints(_droid.x,_droid.x,baseX,baseY) <= (15 * TILE))
			{
				orderDroidLoc(_droid, DORDER_SCOUT, baseX, baseY);
			}
		}
		
		_droid = EnumDroid();	
	}
	
	if(_droidAtHq > 9) // if we have 10 weapon droids at the base doing nothing send them into combat. Should never have more then 10 droids in base with full health
	{
		setEventTrigger(findEnemy,attackStuffTr);
	}
}
------ Disabled difficultyModifierTr since it cheat finishes research, I don't like cheat research. Instead I created my own difficulty function by increasing the veterancy/experience of the Nexus AI droids every few minutes but then I realized there's no way to access the chosen difficulty settings from the skirmish menu. I would only want to increase droid experience levels on hard or insane so I disabled abandoned this. GameLevel is for base???

This logic is a little bit mundane but that's because I was trying to debug why it wasn't working at one point.

Code: Select all

event droidBuiltAssign(droidBuiltTr)
{
//	local int	_difficulty;
//	
//	_difficulty = gameTime/3000;
//	
//	if(_difficulty == 1)
//	{
//		setDroidKills(droid, 4);
//	}
//	else if(_difficulty == 2)
//	{
//		setDroidKills(droid, 8);
//	}
//	else if(_difficulty == 3)
//	{
//		setDroidKills(droid, 16);
//	}
//	else if(_difficulty == 4)
//	{
//		setDroidKills(droid, 32);
//	}
//	else if(_difficulty == 5)
//	{
//		setDroidKills(droid, 64);
//	}
//	else if(_difficulty == 6)
//	{
//		setDroidKills(droid, 128);
//	}
//	else if(_difficulty == 7)
//	{
//		setDroidKills(droid, 256);
//	}
//	else if(_difficulty == 8)
//	{
//		setDroidKills(droid, 512);
//	}

------ Improved VTOL behavior to attack all droids in sight on way to their target although the VTOL's still retreat after killing an object despite still having extra ammo. I sunk many hours into VTOL behavior trying to figure out how to simultaneously get VTOL's to attack anything in sight AND pursue another target after killing an object but came to the conclusion it's not possible unless there is a way to access VTOL ammo levels. The problem is that
VTOL's go to DACTION_MOVETOREARMPOINT after 1. destroying an object and 2. when they're out of ammo therefore there is no way to distinguish between the two states. The only solution is to have the VTOL's attack despite DACTION_MOVETOREARMPOINT but then the VTOL's will never rearm. I basically set
setDroidSecondary(droid, DSO_PATROL, DSS_PATROL_SET); when a VTOL is produced, when a VTOL arrives at their destination and when a VTOL attacks to achieve the relentless attack behavior. I use scout to x/y coordinates as opposed to attack an object.


------ Added logic to find oils (not to be confused with derricks) with enemy droids in range. It has superior performance over closest oil in beginning of t1 no base rush games. I can improve this by finding the closest oil out of this subset too. I also pursue MG Guard Tower if an oil is found with enemy droid in range. All of this emerged out of my attempts to beat Bonecrusher in low oil rush games :).

Code: Select all

_count = 0;
				while(_count < MAX_PLAYERS)
				{
					if(!allianceExistsBetween(me, _count))
					{
						_numEnemy++;
						initGetFeature(oilRes, -1, me);
						_oil = getFeatureB(me);
						while (_oil != NULLOBJECT)
						{	
							_droidInRange = FALSE;
							if(droidInRange(_count, _oil.x, _oil.y, (8 * TILE)))
							{
								_enemyOil = _oil;
							}
							_oil = getFeatureB(me);
						}
					}
					_count++;
				}
			
			
------ finishStructs() was only being applied to factories. Fixed this to include research centers and power generators. It was an easy copy/paste from the factory code and just replace factory with appropriate structure.

------ on event droidBuiltAssign I put setDroidSecondary(droid, DSO_REPAIR_LEVEL, DSS_REPLEV_LOW); to set all droids to repair at medium damage.

------ on structBuilt event have the trucks build a fortification if the structure was a derrick and there is an enemy droid within 5 tiles. Similar to build fortification if we find an enemy derrick.
Used to protect oils in T1 no base...

Code: Select all

if(structure.stattype == REF_RESOURCE_EXTRACTOR)
	{
		_count = 0;
		while(_count < MAX_PLAYERS)
		{
			if(!allianceExistsBetween(me, _count))
			{
				if(droidInRange(_count, structure.x, structure.y, (5 * TILE)))
				{	
					_bestDist = 99999;
					initIterateGroup(buildGroup);
					droid = iterateGroup(buildGroup);
					while(droid != NULLOBJECT)
					{
						_newDist = distBetweenTwoPoints(droid.x, droid.y, structure.x, structure.y);
					
						if (_newDist < _bestDist)	// this one is closer
						{
							_closestTruck = droid;
							_closestX = droid.x;
							_closestY = droid.y;
						}
						droid = iterateGroup(buildGroup);
					}
					
					if(_closestTruck != NULLOBJECT)
					{
						if (pickDroidStructLocation(_closestTruck, gTower, ref _closestX, ref _closestY, me, 1))
						{
							orderDroidStatsLoc(_closestTruck, DORDER_BUILD, gTower, _closestX, _closestY);
						}
					}
				}			
			}
			_count++;
		}
------ check if allies don't have a truck and if we have at least two then give one away.

Code: Select all

	_count = 0;
	while(_count < 10) 
	{
		if(allianceExistsBetween(me, _count))
		{	
			_haveTruck = FALSE;
			InitEnumDroids(_count,_count);
			_droid = EnumDroid();
			while (_droid != NULLOBJECT)
			{
				if(_droid.droidType == DROID_CONSTRUCT or _droid.droidType == DROID_CYBORG_CONSTRUCT) // check to see if any of our allies don't have a truck
				{
					_haveTruck = TRUE;
				}
				_droid = EnumDroid();
			}
		
			if(!_haveTruck)
			{	
				_numTruck = 0;
				InitEnumDroids(me,me);
				_droid = EnumDroid();
				while (_droid != NULLOBJECT)
				{
					if(_droid.droidType == DROID_CONSTRUCT or _droid.droidType == DROID_CYBORG_CONSTRUCT) // check to see if we have any trucks to give
					{
						_numTruck++;
						_giveTruck = _droid;
					}
					_droid = EnumDroid();
				}
				
				if(_numTruck > 2) // if we have at least two trucks then give one to ally that doesn't
				{
					takeOverSingleDroid(_giveTruck, _count);
				}
			}
		}
		_count++;
	}



------ pass 30% of power to ally if we have 2,000 more power then them. Doesn't work. Seems addPower has been disabled in mp??
I can't get it to work at all, even in initialisedEvent although it does complain about invalid ally when I swapped the POWER and ALLY parameters so it's doing at least something...

Code: Select all

			// Transfer 30% of power to ally if we have 2000 more power then ally
			// This doesn't work because addPower() is only available in campaign - or at least it doesn't work anywhere 
			_powerTransfer = 0;
			
			_myPower = playerPower(me);
			_allyPower = playerPower(_count);
			_powerTransfer = _myPower - _allyPower;
			if(_powerTransfer > 2000)
			{
				_powerTransfer = (int)(((float)playerPower(me)) * .30);
				addPower(_powerTransfer, _count);
				_powerTransfer = _powerTransfer * -1;
				addPower(_powerTransfer,me);
			}
------ Send all Nexus weapon droids to ally beacons. This way humans can easily play/use Nexus AI just by beaconing where you want Nexus to go.
Nexus also beacons any enemy droids within 15 tiles of base every 10 seconds so if you attack this AI, all ally Nexus AI's will come to help. This way Nexus AI's can play as a team and help each other.

It's just a matter of adding a little snippet to beaconEv()

Code: Select all

	if(allianceExistsBetween(me, sender))
	{
		orderGroupLoc(attackGroup, DORDER_SCOUT, beaconX[sender], beaconY[sender]);
	}
------ announce research objectives to allies at 5 second mark. It sounded like a good idea but the message scrolls so fast I hardly even notice. I think I'll abandon this too

Code: Select all


			event announceResearch(inactive)
			{
			
				if(curTech == branchFlameVtolLaser)
				{
					messagePlayer(ALL_ALLIES, "I'm researching Flamers then VTOL and lasers if the game is long.", MAX_PROBABILITY);
				}
				else if(curTech == branchCannonMGMortar)
				{
					messagePlayer(ALL_ALLIES, "I'm researching Cannons, MG's and mortars. Grenadiers for cyborgs.", MAX_PROBABILITY);
				}
				else if(curTech == branchRocketMGMortar)
				{
					messagePlayer(ALL_ALLIES, "I'm researching Rocket MG's and mortars.  Grenadiers for cyborgs.", MAX_PROBABILITY);
				}
				else if(curTech == branchRocket)
				{
					messagePlayer(ALL_ALLIES, "I think I'll use rockets + MG", MAX_PROBABILITY);
				}
				else if(curTech ==  branchMG)
				{
					messagePlayer(ALL_ALLIES, "I'm researching all MG's", MAX_PROBABILITY);
				}
				else if(curTech == branchFlamer)
				{
					messagePlayer(ALL_ALLIES, "I'm going all flamers", MAX_PROBABILITY);
				}
				else if(curTech == branchCannon)
				{
					messagePlayer(ALL_ALLIES, "I'm using cannons this game", MAX_PROBABILITY);
				}
				else if(curTech == branchArtillery)
				{
					messagePlayer(ALL_ALLIES, "I'm researching Mortars and Artillery Research", MAX_PROBABILITY);	
				}
				setEventTrigger(announceResearch,	inactive);
			}
-------- added one more profile - pure MG's. Now all of the weapon lines have a dedicate profile so Nexus can play with all weapons


------ Right now I'm working on code to build an "outpost"(fortifications, repair centers, artillery) at some % (say 30%) the distance between baseX/baseY and closest enemy (enemy HQ). I have it partially working but only for players on the bottom of the map... players on top of the map have problems selecting the Y coordinate. It's still a work in progress but this has other applications too such as building repair centers in between base and enemy instead of random place in base

Code: Select all


		_closestX = 0;
		_closestY = 0;
		_bestDist = 99999;
		
		_count = 0;
		while(_count < MAX_PLAYERS)
		{
			if(!allianceExistsBetween(me,_count))
			{
				structure = getStructure(playerHQ, _count);
				if(structure != NULLOBJECT)
				{
					_newDist = distBetweenTwoPoints(baseX, baseY, structure.x, structure.y);
				
					if (_newDist < _bestDist and droidCanReach(droid, structure.x, structure.y))	// this one is closer
					{
						_bestDist = _newDist;
						_closestX = structure.x;
						_closestY = structure.y;
					}
				}

			}
		_count++;
		}
		
		buildX = 0;
		buildY = 0;
		if(_closestX > baseX and _closestX != 0) 
		{
			buildX = baseX + (int)((float)(_closestX - baseX) * .30); // this means enemy is to the left of us			
		}
		else
		{
			buildX = baseX - (int)((float)(baseX - _closestX) * .30); // this means enemy is the right of us	
		}
		
		if(_closestY > baseY and _closestY != 0)
		{
			buildY = baseY + (int)((float)(_closestY - baseY) * .30); // this means enemy is below us		
		}
		else
		{
			buildY = baseY - (int)((float)(baseY - _closestY) * .30); // this means enemy is above us		
		}
		
		if(buildY > 0 and buildY < mapHeight and buildX > 0 and buildX < mapWidth)
		{
				//if (pickDroidStructLocation(droid, defStructs[count], ref buildX, ref buildY, me, -1))
				boolResult = pickStructLocation(sensorTower, ref buildX, ref buildY,me);	// pick spot.
				if(boolResult == TRUE)
				{
					// find unit
					initIterateGroup(buildGroup);
					droid = iterateGroup(buildGroup);
					while(droid != NULLOBJECT)
					{
						if ((droid.order == DORDER_NONE or droid.order == DORDER_RTB) and droidCanReach(droid, buildX, buildY))
						{
							orderDroidStatsLoc(droid, DORDER_BUILD, sensorTower, buildX, buildY);
							droid = NULLOBJECT;
						}
					droid = iterateGroup(buildGroup);
					}
				}
		}
I've only been working with scripts in warzone for 3 months. Prior to this I made some speculative comments on making an AI that I now realize may not have made sense. I thought making an AI in Warzone was like building a predictive model of best research, build order and weapon choice based on a set of input variables e.g. game and map settings but it's not like that at all :oops:

Come to find out, this predictive model was only a matter of ordering a couple of arrays... I had no idea how WZ AI worked but I do now...
Attachments
EB.wz
(101.94 KiB) Downloaded 200 times
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

I forgot I still need to update the research messages to reflect the new stats and maybe some of the .po files too.

Now that I think of it, that's probably the most appropriate way to communicate the stats. I just never ever look at that screen because it's purely cosmetic to a veteran player playing an mp game. I forgot all about it. I'll get to it sometime in the next month, just wanted to say it's on to-do list.
Admin010
New user
Posts: 1
Joined: 22 May 2017, 06:36

Re: Enhanced Balance Mod for 3.x

Post by Admin010 »

thanks
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Okay I finally finished the research messages, it took a lot longer than I thought. I added 191 new messages so that all mp research items have a unique message on the intelligence screen displaying the new stats.

I also updated the hitpoint changes to reflect the changes here https://github.com/Warzone2100/warzone2 ... ee2d6f4a8a

I didn't get around to implementing the new commander/brain upgrades. I start a new software development job tomorrow so I won't have any time to do WZ stuff for awhile, maybe forever.


On a side note, I re-enabled the idea of Nexus AI passing a truck to ally if they don't have one. The only reason I disabled it before was because takeOverSingleDroid(); logs a non-fatal error in the log file stating "Script interpreter is already running" but it's harmless.

The below attachment will not work on 3.2.3 because it's only compatible with the hitpoint changes that haven't been deployed yet.
Attachments
EB.wz
Latest/Final Version.
(112.35 KiB) Downloaded 183 times
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

whoops, I forgot to uncheck the designable flag on the structure instance of the mortar weapons. (They should not be designable on vehicles).

Image

Also, the stats editor is attached below for the stats in the post above. It's really only possible to analyze the stat changes from the view of the editor because it puts comparable/similar stats into perspective from a single view. From that viewpoint it's easy to see how things are "balanced".

To test EB, just do autogame on and watch Nexus play. 5v5 maps are the best.

I'm going to officially retire on development here for awhile. I started a new software development job today and definitely confirmed I'm going to be busy. I'll come back when I learn to properly use Git on WZ instead of using this thread as my changelog lol. Just j/k.

BTW, Here is my Linkedin profile https://www.linkedin.com/in/jason-breijak-919b0210b/
Attachments
WZ Stats Editor.zip
(1.54 MiB) Downloaded 203 times
weapons.json
Removed "1" flag from 5 mortar weapons
(164.31 KiB) Downloaded 191 times
Legendary
Greenhorn
Posts: 8
Joined: 04 May 2016, 19:59

Re: Enhanced Balance Mod for 3.x

Post by Legendary »

That's very interesting! I have been in deep depresion because of NoQ lack of development on NullBot. Now EB... Hm. Could you please provide some roadmap on what you plan to implement? I would gladly help you to test some games and provide feedback.
User avatar
NoQ
Special
Special
Posts: 6226
Joined: 24 Dec 2009, 11:35
Location: /var/zone

Re: Enhanced Balance Mod for 3.x

Post by NoQ »

Legendary wrote:I have been in deep depresion because of NoQ lack of development on NullBot.
+1.
MIH-XTC
Trained
Trained
Posts: 368
Joined: 31 Jan 2014, 07:06

Re: Enhanced Balance Mod for 3.x

Post by MIH-XTC »

Legendary wrote:That's very interesting! I have been in deep depresion because of NoQ lack of development on NullBot. Now EB... Hm. Could you please provide some roadmap on what you plan to implement? I would gladly help you to test some games and provide feedback.

Well, I've given up on trying to explain what all I changed because it's too hard to classify/categorize/group the changes together and then explain the implications. The mod is stable I know that so there's no need to test that aspect. Testing is just a matter of whether you personally like it or not. I just created a short video a few minutes ago to give an idea of how I go about modding in the stats editor and testing the changes.

https://youtu.be/cIXpL2ZPiG4

If you want to try the mod for yourself then use the attachment in this post. The attachment in the post above is only compatible with changes in future releases.

BTW, in the video I show the log file at 15:20 that has some errors but none of which are due to the mod (Except for script interpreter is already running). The rest of the errors are inherit to the map.
Attachments
EB.wz
Latest Compatible with 3.2.3
(112.3 KiB) Downloaded 188 times
Post Reply