Skip to content

Commit 6082c63

Browse files
committed
bots have option to preselect map and start; more code samples in docs
1 parent d4c4cf1 commit 6082c63

File tree

4 files changed

+138
-40
lines changed

4 files changed

+138
-40
lines changed

csharp/bot/main.cs

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Threading;
45

56
namespace Unnatural
67
{
@@ -15,11 +16,9 @@ void AttackNearestEnemies()
1516
var ownUnits = World.Entities().Values.Where(x => x.Own && x.ProtoUnit?.dps > 0);
1617
if (ownUnits.Count() == 0)
1718
return;
18-
1919
var enemyUnits = World.Entities().Values.Where(x => x.Enemy && x.Unit.HasValue);
2020
if (enemyUnits.Count() == 0)
2121
return;
22-
2322
foreach (Entity own in ownUnits)
2423
{
2524
if (Commands.Orders(own.Id).Length == 0)
@@ -47,27 +46,37 @@ void AssignRandomRecipes()
4746

4847
void Configure()
4948
{
50-
if (isConfigured)
49+
// auto start the game if available
50+
if (isConfigured && Game.GameState() == Interop.UwGameStateEnum.Session && World.IsAdmin())
51+
{
52+
Thread.Sleep(3000); // give the observer enough time to connect
53+
Admin.StartGame();
54+
return;
55+
}
56+
// is configuring possible?
57+
if (isConfigured || Game.GameState() != Interop.UwGameStateEnum.Session || World.MyPlayerId() == 0)
5158
return;
5259
isConfigured = true;
53-
60+
Game.LogInfo("configuration start");
5461
Game.SetPlayerName("bot-cs");
5562
Game.PlayerJoinForce(0); // create new force
5663
Game.SetForceColor(1f, 0f, 0f);
57-
// todo choose race
64+
// Game.SetForceRace(RACE_ID); // todo
65+
if (World.IsAdmin())
66+
{
67+
// Admin.SetMapSelection("planets/tetrahedron.uwmap");
68+
Admin.SetMapSelection("special/risk.uwmap");
69+
Admin.AddAi();
70+
Admin.SetAutomaticSuggestedCameraFocus(true);
71+
}
72+
Game.LogInfo("configuration done");
5873
}
5974

6075
void Updating(object sender, bool stepping)
6176
{
62-
if (Game.GameState() == Interop.UwGameStateEnum.Session)
63-
{
64-
Configure();
65-
return;
66-
}
67-
77+
Configure();
6878
if (!stepping)
6979
return;
70-
7180
switch (workStep++ % 10) // save some cpu cycles by splitting work over multiple steps
7281
{
7382
case 1:
@@ -84,9 +93,15 @@ void Run()
8493
Game.LogInfo("bot-cs start");
8594
if (!Game.TryReconnect())
8695
{
87-
Game.SetConnectStartGui(true);
96+
Game.SetConnectStartGui(true, "--observer 2");
8897
if (!Game.ConnectEnvironment())
89-
Game.ConnectNewServer();
98+
{
99+
// automatically select map and start the game from here in the code
100+
if (false)
101+
Game.ConnectNewServer(0, "", "--allowUwApiAdmin 1");
102+
else
103+
Game.ConnectNewServer();
104+
}
90105
}
91106
Game.LogInfo("bot-cs done");
92107
}

python/bot/bot.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import random
2+
import time
23
from uwapi import *
34

45

@@ -40,23 +41,39 @@ def assign_random_recipes(self):
4041
uw_commands.set_recipe(own.id, recipe)
4142

4243
def configure(self):
43-
if self.is_configured:
44+
# auto start the game if available
45+
if (
46+
self.is_configured
47+
and uw_game.game_state() == GameState.Session
48+
and uw_world.is_admin()
49+
):
50+
time.sleep(3) # give the observer enough time to connect
51+
uw_admin.start_game()
52+
return
53+
# is configuring possible?
54+
if (
55+
self.is_configured
56+
or uw_game.game_state() != GameState.Session
57+
or uw_world.my_player_id() == 0
58+
):
4459
return
4560
self.is_configured = True
46-
61+
uw_game.log_info("configuration start")
4762
uw_game.set_player_name("bot-py")
4863
uw_game.player_join_force(0) # create new force
4964
uw_game.set_force_color(1, 0, 0)
50-
# todo choose race
65+
# uw_game.set_force_race(RACE_ID) # todo
66+
if uw_world.is_admin():
67+
# uw_admin.set_map_selection("planets/tetrahedron.uwmap")
68+
uw_admin.set_map_selection("special/risk.uwmap")
69+
uw_admin.add_ai()
70+
uw_admin.set_automatic_suggested_camera_focus(True)
71+
uw_game.log_info("configuration done")
5172

5273
def on_update(self, stepping: bool):
53-
if uw_game.game_state() == GameState.Session:
54-
self.configure()
55-
return
56-
74+
self.configure()
5775
if not stepping:
5876
return
59-
6077
self.work_step += 1
6178
match self.work_step % 10: # save some cpu cycles by splitting work over multiple steps
6279
case 1:
@@ -67,7 +84,11 @@ def on_update(self, stepping: bool):
6784
def run(self):
6885
uw_game.log_info("bot-py start")
6986
if not uw_game.try_reconnect():
70-
uw_game.set_connect_start_gui(True)
87+
uw_game.set_connect_start_gui(True, "--observer 2")
7188
if not uw_game.connect_environment():
72-
uw_game.connect_new_server()
89+
# automatically select map and start the game from here in the code
90+
if False:
91+
uw_game.connect_new_server(0, "", "--allowUwApiAdmin 1")
92+
else:
93+
uw_game.connect_new_server()
7394
uw_game.log_info("bot-py done")

sphinx/source/concepts/economy.rst

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
Economy
22
=======
33

4+
Recipes And Constructions
5+
-------------------------
6+
47
Resources are mined from deposits, or processed from other resources.
5-
Producing units or researching upgrades works the same way as recipes.
8+
Producing units and researching upgrades works the same as recipes.
69

710
.. tab-set::
811
:sync-group: language
@@ -38,8 +41,8 @@ Producing units or researching upgrades works the same way as recipes.
3841
Commands.PlaceConstruction(DRILL_CONSTRUCTION_ID, p, 0, METAL_RECIPE_ID, UwPriorityEnum.High); // yaw, recipe, and priority are optional
3942
4043
// recipe and priority can be changed later:
41-
Commands.SetRecipe(own_id, ANOTHER_RECIPE_ID)
42-
Commands.SetPriority(own_id, UwPriorityEnum.Normal)
44+
Commands.SetRecipe(ownId, ANOTHER_RECIPE_ID)
45+
Commands.SetPriority(ownId, UwPriorityEnum.Normal)
4346
4447
.. tab-item:: C++
4548
:sync: cpp
@@ -73,9 +76,35 @@ They will fulfill tasks by their priority, and on first-come-first-serve basis.
7376
// percentage of trucks that are idle:
7477
100.0 * World.MyForceStatistics().logisticsUnitsIdle / World.MyForceStatistics().logisticsUnitsTotal
7578
79+
Expansion Bases
80+
---------------
81+
82+
Each map contains predefined set of starting positions.
83+
These can have some additional conditions to be used as starting base, eg. actual number of forces in the game.
84+
Anyway, these positions can be used to easily find suitable expansion bases.
85+
86+
.. tab-set::
87+
:sync-group: language
88+
89+
.. tab-item:: Python
90+
:sync: python
91+
92+
.. code-block:: python
93+
94+
# potential expansion bases:
95+
list({p.position for p in uw_map.starting_positions()}) # make the positions unique
96+
97+
.. tab-item:: C#
98+
:sync: csharp
99+
100+
.. code-block:: csharp
101+
102+
// potential expansion bases:
103+
Map.StartingPositions().Select(p => p.position).Distinct().ToList();
104+
76105
.. tab-item:: C++
77106
:sync: cpp
78107

79108
.. code-block:: cpp
80109
81-
// nothing
110+
// todo

sphinx/source/concepts/military.rst

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ You can have multiple orders queued for each unit.
2323
# order own unit to attack enemy unit (cancels all previous orders):
2424
uw_commands.order(own_id, uw_commands.fight_to_entity(enemy_id))
2525
26-
# alternatively, enqueue attack order:
27-
o = uw_commands.fight_to_entity(enemy_id)
26+
# enqueue move order:
27+
o = uw_commands.run_to_position(tile_index)
2828
o.priority = o.priority | OrderPriority.Enqueue
2929
uw_commands.order(own_id, o)
3030
@@ -34,22 +34,55 @@ You can have multiple orders queued for each unit.
3434
.. code-block:: csharp
3535
3636
// get list of orders of own unit:
37-
var os = Commands.Orders(own_id);
37+
var os = Commands.Orders(ownId);
3838
3939
// order own unit to attack enemy unit (cancels all previous orders):
40-
Commands.Order(own_id, Commands.FightToEntity(enemy_id));
40+
Commands.Order(ownId, Commands.FightToEntity(enemyId));
4141
42-
// alternatively, enqueue attack order:
43-
Order o = Commands.FightToEntity(enemy_id);
42+
// enqueue move order:
43+
Order o = Commands.RunToPosition(tileIndex);
4444
o.priority |= UwOrderPriorityFlags.Enqueue;
45-
Commands.Order(own_id, o);
45+
Commands.Order(ownId, o);
4646
47-
.. tab-item:: C++
48-
:sync: cpp
47+
Tips For Military Maneuvers
48+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
4949

50-
.. code-block:: cpp
50+
.. tab-set::
51+
:sync-group: language
52+
53+
.. tab-item:: Python
54+
:sync: python
55+
56+
.. code-block:: python
57+
58+
# position of enemy military unit that is closest to any of our own units:
59+
uw_world.my_force_statistics().closestDangerPosition
60+
61+
# position that is specific distance from target, and closest to us
62+
surrounding_positions = uw_map.area_neighborhood(target_position, 200)
63+
specific_distance_position = min(surrounding_positions, key=lambda x: uw_map.distance_estimate(my_position, x))
64+
65+
# flanking position around target
66+
surrounding_positions = uw_map.area_neighborhood(target_position, 200)
67+
surrounding_positions = sorted(surrounding_positions, key=lambda x: uw_map.distance_estimate(my_position, x))
68+
flanking_position = surrounding_positions[len(surrounding_positions) // 2] # note that this picks left or right flanking position at random
69+
70+
.. tab-item:: C#
71+
:sync: csharp
72+
73+
.. code-block:: csharp
74+
75+
// position of enemy military unit that is closest to any of our own units:
76+
World.MyForceStatistics().closestDangerPosition
77+
78+
// position that is specific distance from target, and closest to us
79+
var surroundingPositions = Map.AreaNeighborhood(targetPosition, 200);
80+
var specificDistancePosition = surroundingPositions.OrderBy(x => Map.DistanceEstimate(myPosition, x)).First();
5181
52-
// nothing
82+
// flanking position around target
83+
var surroundingPositions = Map.areaNeighborhood(targetPosition, 200);
84+
surroundingPositions.Sort((a, b) => Map.DistanceEstimate(myPosition, a).CompareTo(Map.DistanceEstimate(myPosition, b)));
85+
var flankingPosition = surroundingPositions[surroundingPositions.Count / 2]; // note that this picks left or right flanking position at random
5386
5487
Shooting
5588
--------
@@ -111,7 +144,7 @@ Upgrades
111144
Research usually consumes some resources to produce upgrades.
112145
Upgrades will stack, up to a specified limit.
113146
This means that the upgrades have a ramp-up phase.
114-
When research stops, the upgrades will dissipate after some time.
147+
When research stops, the upgrades will dissipate over time.
115148

116149
Most upgrades apply percentage increase to one or more of the properties of a unit.
117150

0 commit comments

Comments
 (0)