Or how can worker of various professions be sent to where they are needed.
Training up my soldiers at a trainingsite I noticed that although I don't want to make heroes the evolve as such if I don't swap the occupants of the trainingsite. furthermore there is the now closed bug Improve handling of workers and the resulting feature request Downgrade skilled workers when possible. These show there is some real issue in the sending not just any worker to a requesting site but specific workers.
Excerpt from the mailing list (ToDo: work out the points)
Considerations from Nicolai Hähnle:
- What is the right subsystem in which to tackle this problem?
- How can you integrate this balancing into existing systems?
- Are there other parts of Widelands that can benefit from a balance system?
Step 2 would be to actually implement the balancing. The more I think about it, the more I believe that this should be in the Economy code. The only viable alternative would be inside building code, but I think that would be inferior, mostly for two reasons:
(I) All kinds of buildings need to support and be involved in balancing, and those buildings are not really uniform. So implementing it in buildings would result in code - and therefore bug - duplication.
(II) Players will perceive the system as good if it produces a globally good solution. A decision that seems clever from the point of view of one building could be horrible from a global perspective. So make the decision on a global level (or, to be more precise, on a per-Economy level, since it's not possible to be more global than that)
Note that this doesn't prohibit support code in the buildings - in fact, such support code will be necessary. To avoid code duplication, it could take the form of a "WorkerArray", similar to the already existing WaresQueue. It's just that the main routine that actually makes the decision "Okay, this master-miner should get a replacement from warehouse X" should reside in the transport code.
- A Building or more General a PlayerImovable sends a Request for a Worker ore a WareInstance ==> a Map_Object. A Request contains a Requirement that is list of MinMax attributes. Currently only attributes for soldiers are defined. So a Request can only a soldier of a specific 'quality' any other workers are requested by a specific Transfer object. Therefore the Transfer Object of a miner is different from the one of a chief miner.
A Transfer object is something that only exists when something is actually being transported. A typical lifetime looks like this:
- Building creates a Request object for a ware, say a trunk.
- Economy tries to satisfy the Request, but nothing is currently available.
- Lumberjack creates a trunk WareInstance. This WareInstance creates a Supply object describing itself.
- Economy sees the matching Supply for the Request and starts a Transfer that attaches itself to the WareInstances.
- Now the trunk will be transported to the requesting building.
- The trunk arrives at the building. The Transfer object is destroyed, and the building is notified (via a callback routine; usually, this detail is handled by WaresQueue) and removes the Request, unless it needs even more trunks.
If the Requirement would have attached a attribute minQos to indicate what the minimum requirement must be a Request for a miner with minQos 0 can be answered by a chief miner, but a Request with minQos 1 can only be answered by a chief miner or a master miner. The interpretation of the QoS (mapping of the integer value to the level of the worker) must obviously be defined by the worker itself. Currently this issue is solved as follows but perhaps can be simplified with this approach:
Actually, a plain mine just says "I want a miner". Deep in the bowels of Supply implementations, you will find stuff like the code for Warehouse::count_workers (which is called via WarehouseSupply::nr_supplies). Notice the loop with get_worker_descr(ware)->becomes()? The becomes() indicates the kind of worker that a miner becomes once he collects enough experience - which implies that that type of worker can also be used in place of a normal miner.
Where to implement
The whole transfer of workers (which is the main issue of this discussion) and wares (which may also profit from the idea) is handled with Widelands::Request that are satisfied with Widelands::Supply. The maching of a Supply to a request is handled by the Widelands::Economy. The whole interaction should be handled by improved Request that the economy can handle.
Where to start
So the first (after knowing how the Widelands::Request must be improved) add a branch to the Widelands::Economy::process_requests to handle the improved Widelands::Request and test for regression. Then improve the Widelands::Request. Finally implement the request handling in Widelands::Economy.
Balancing algorithm for requesting soldiers of the trainingsite
initialize counter with 0 and the max_counter with capacity when the capacity is changed reset the counter. when a soldier is updated increase the counter.
initiate exchange soldier
max_counter = ciel(max_counter/2.0)
Common balancing algorithm
Requests can be biased either towards high-end supplies or low-end supplies. For example, one could give each requirement axis (attributes for soldiers, becomes-hierarchy for other workers) an integer, where 0 says "don't care as long as it matches", positive values are biased towards the high end (high-level/high-experience) and negative values are biased towards the low end.
Algorithm to exchange soldiers
(I) if the least trained soldier of the site is better trained then any on the outside: engage exchange
(II) if there is a soldier in the heandquaters or any of the warehouses that is not as well trained as the least trained of the site select this soldier.
(III) if not (II) and if there is a soldier in any militarysite that is not only occupied by himself (and not under attack... ) that is not as well trained as the least trained of the site select this soldier.
(a) if the soldier to be exchanged is a free (case ii) one send this one to the trainingsite. When he arrives there (note that the capacity is full else the soldier would have been requested earlier), the trainingsite kicks out the best trained soldier.
- (b) if the soldier to be exchanged is not free (case iii) (part of military building X), reduce the capacity of the trainingsite by one by kicking out the best soldier. Then a request in the name of X is issued requesting a soldier with the exact specification of the kicked out soldier and a special callback function. When the soldier arrives at X it is consumed by X and the callback is called. The callback then will kick out the least trained soldier. (Note this results in a overpopulated military site as capacity+1 soldiers are present between consuming and the end of the callback.) The callback function will then initiate the increasing of the capacity of the trainingsite. This therefore will request a soldier. If the trainingsite is not set to making heroes it should always request a soldier of the least qualification.
Algorithm to send a higher qualified miner to a lower position
Example: Mine Y requests a Chief Miner 1. look if Chief Miner can be made available as free man (see algo "Free Miner") (send off) 2. if not, look if any mine has one Chief Miner aa in a over-qualified position. 3. if yes, send aa to mine Y and let X request a miner for the vacant position, where X is the request fulfilling mine.