From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1005 invoked by alias); 16 Aug 2004 21:34:15 -0000 Mailing-List: contact xconq7-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: xconq7-owner@sources.redhat.com Received: (qmail 997 invoked from network); 16 Aug 2004 21:34:12 -0000 Received: from unknown (HELO av7-2-sn2.hy.skanova.net) (81.228.8.109) by sourceware.org with SMTP; 16 Aug 2004 21:34:12 -0000 Received: by av7-2-sn2.hy.skanova.net (Postfix, from userid 502) id 796BC37E69; Mon, 16 Aug 2004 23:34:12 +0200 (CEST) Received: from smtp2-1-sn2.hy.skanova.net (smtp2-1-sn2.hy.skanova.net [81.228.8.177]) by av7-2-sn2.hy.skanova.net (Postfix) with ESMTP id 4ACE537E42 for ; Mon, 16 Aug 2004 23:34:12 +0200 (CEST) Received: from [212.181.162.155] (h155n1fls24o1048.bredband.comhem.se [212.181.162.155]) by smtp2-1-sn2.hy.skanova.net (Postfix) with ESMTP id BB0BA37E45 for ; Mon, 16 Aug 2004 23:34:11 +0200 (CEST) X-Sender: u22611592@m1.226.comhem.se Message-Id: Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Date: Mon, 16 Aug 2004 21:53:00 -0000 To: xconq7@sources.redhat.com From: Hans Ronne Subject: Major bug and what to do about it (long) X-SW-Source: 2004/txt/msg00901.txt.bz2 I've been doing some heavy game testing and found a large number of bugs. I will check in fixes to most of them soon. However, one bug (or perhaps rather a design flaw) is particularly insidious, and will require major code surgery to fix. I would therefore like to get some feedback before I proceed. The problem has to do with the difference between unit views and real units, and the two types of attacks that are possible (both for normal attacks and fire actions, respectively). Typically, the AI will look for possible targets near a unit and then set a hit_unit task. This task specifies the position, type and side of the target, but not (and this is important) the actual unit. The reason for this is that the AI sees only unit views, which may be real or not. So far so good. However, when do_hit_unit_task is executed, the kernel cheats and looks up the actual unit. The reason for this is that both do_attack_action and do_fire_at_action require a pointer to a real unit as argument. A unit view or just a position will not do. This is because unit views was a rather late addition to Xconq, which was grafted onto the existing code. The bug that I found works like this. First, the AI finds a target at position (x, y) and sets a hit_unit task. However, when do_hit_unit_task looks up the actual unit, it finds that the unit no longer exists or has moved. The call to check_attack_action (or check_fire_at_action) fails and the task itself also fails after 3 attempts (the latter restriction is a recent hack by Eric who may have stumbled across the same bug). Now the ball returns to the AI, who should find something else for our unit to do. However, the AI still sees the same unit view and doesn't know that the task failed, so it sets the same hit_unit task again. Since no acps are consumed by failed tasks, this vicious cycle goes on until we hit the ceiling on plan executions per turn (1000 attempts). At that point, our unit is put into reserve mode, and rests until the next turn. This despite the fact that it has not done anything and therefore not consumed a single acp! So what can we do about this? The obvious solution is to use unit-independent versions of do_attack_action and do_fire_at_action, which already exist in Xconq. They are called do_overrun_action and do_fire_into_action, respectively. Here is how these unit-independent actions work. The unit attacks (or fires into) a cell (x, y). The code then attempts to hit each unit at (x, y) in stack order. One round of ammo is consumed for each unit (whether you hit it or not), so these kinds of attacks are more ammo-expensive then hitting a single unit. OTOH, the same amount of acps are consumed at the end, so you get a free shot at all units at (x, y) for the same acp cost as when you attack a single unit! This is a huge advantage when you are dealing with stacked units, as you are in many games. On the balance, I would therfore say that these attack actions are more efficient than those who target single units. However, the AI does not use unit-independent attacks a lot. It relies mostly on do_hit_unit_task, which targets single units. Hence the above bug. In the human case, unit-indpendent normal attacks (overrun actions) are favoured by the interface code. Thus, clicking on an enemy unit schedules an overrun action into that cell. To schedule an attack on a single unit, you have to use the 'a' command instead. OTOH, if you do the simplest fire command, i.e. press 'f' with a unit that can fire, you will schedule a unit-dependent fire-at action. To do a fire-into action, you must press 'ctrl-f'. So the interface code is not very consistent about what it prefers. I have given the above bug and its consequences some serious thought. Here is what I think should be done: 1. We should eliminate the attack unit/attack position code split. Instead of the four actions that are possible today, we should just have two: do_attack_action and do_fire_action. These actions should be unit-independent, i.e. work pretty much like the old do_overrun_action and do_fire_into_action. This would have a number of advantages. First, we could do away with unit pointers in the combat code. The bug I just found would be fixed, and no doubt many other bugs yet to be discovered. Writing new AI code would be much easier without the code bifurcation. The interface could also be simpler. For example, clicking on an enemy unit could schedule a normal attack (overrun action) and right-clicking on it a fire action. No need to use the keyboard at all. Yet another advantage with this scheme is that it would make combat model 0 more similar to combat model 1, which only uses overrun actions. This in turn would make it a lot easier to improve both the AI and the combat code in the future. 2. I'm not sure, however, that do_attack_action and do_fire_action should work exactly like do_overrun_action and do_fire_into_action do today. Specifically, I don't like the fact that you get a free shot at every unit in the cell for just one acp consumed, even if you have to pay for it in ammo. It seems more logical that one attack (either normal or round of fire) is just that, and that you consume 1 acp and 1 round of ammo each time you attack. As a consequence, you should also be able to hit only one unit (and possibly its occupants) each time you attack. 3. The question is then how to pick the unit to hit. I can see three possibilities. The first is to hit units in stack order. This is easy to implement and is therefore how things frequently work in the kernel, but I don't think it is a good idea in this case. The second possibility is to pick a unit at random, perhaps weighted according to unit-size-in-terrain. The third possibility is to always pick the best defender, on the theory that this is the unit that the defending side would send forward to meet the enemy. Combat model 1 already works like the third alternative (as does Civ2 on which it is modelled). I think this would be a good way to handle normal attacks also in combat model 0. This would make it even easier to deal with the two co-existing combat models. The main difference between them would remain the fact that a model 1 attack continues until death, while a model 0 attack continues only as long as the attacker wishes to continue and has acps left. 4. However, I doubt that this is a good solution for fire actions, which by their very nature are more random. In that case, I'm leaning towards a size-weighted random target, as described above. In addition, the probability of hitting something should be greater if there are several units in the cell (or, in other words, the probability of hitting one unit should not be reduced by the presence of other units in the same cell). One could therefore imagine a scheme similar to do_fire_into_action where the fire code tests all units in the cell. The main difference would be that once a unit is hit, the iteration would stop, since the same round of ammo cannot hit several different units. I think that this scheme would most closely resemble the real life situation of artillery firing into a crowded position occupied by several units. It should be noted that fire actions are currently not supported in combat model 1, so we don't need to worry about that aspect. OTOH, when we add fire actions to combat model 1, which I plan to do, they should preferably work exactly as in combat model 0. These are my thoughts so far. The proposed changes would have profound consequences for all games in the library, so they require some careful thought. I cannot at present see a better way to deal with the underlying problems, though. Hans