 |
|  |
 |
|
Solver
|
|
Apolyton Duke Of Something
|
 |
Latvia, Riga
Sep 2000 time: 07:22
|
|
Thanks a lot Fromafar. I had previously looked through the gameevent code, but not found the right place to look.
ArmyData::PerformOrderHere looks interesting. I'm not sure, but I hope I'll have time in some three hours to look at it. There are, as I see it, several ways to change bombard to range. First - pay attention to the order_rec->GetRange(range); line and modify the GEV_BOMBARD order to have its range equal to bombarding unit's bombard range. Other ways seem to be not so clean, so this way is, I am sure, the best, just gotta check the OrderRecord or whatever class it is then.
I am not sure yet, but I suspect that it might create a situation where the game wouldn't let ranged bombard units bombard targets they couldn't reach (such as over a strip of water they can't cross).
If I have time this evening, I'll report on my findings in ~4 hours.
|
|
|  |
 |
|
LStanley
|
 |
Lubbock Texas
Sep 2004 time: 23:22
|
|
IDEA!
Ranged bombardment = good
add 2 things to it...
1- the paradrop has a part of the code that allows a paradrop to "miss" its drop and land its drop in an adjacent tile (as long as they can land there and its vacant)
USE THIS CODE somehow,... (I haven't looked at it) for the ranged bombardment give it a chance to miss
2- say, every 1 tile past adjacent, scale the previous chance and add a +20% chance to miss, therefore the max distance for firing is 4 squares away to guarantee a chance of a direct hit
which gave me an idea for a new unit type...
remember railway cannons in WW2???
railroad + explosives = railway cannons
limit the cannons to movement to railroads ONLY and (for future maglev's too) and drop its max movement to 1 square.
give them some insane range like 15 tiles, a very powerful shell hell even two shells, and a 20% accuracy at max range.
this kind of unit could decimate a city from afar, and would require a ranged means of engagement, LIKE BOMBERS!... I never really used bombers much in the origional game, but this unit would give it a reason to.
and the levithan, give it the same ranged ability, but no limitation on where to move.
just my .02$ 
|
|
|  |
 |
|
Peter Triggs
|
|
Gone Fishin, Canada
Jan 2000 time: 05:22
|
|
Actually, it turns out to be more complicated than that.
It's not that difficult to get an army to bombard from range, provided that it's within it's range of the target. Where it gets hairy is when the army is outside of that range. I have a feeling that it may be necessary to change UnitAstar::FindPath so that it can return a 'ranged path': visualize this as solid lines from the army's position to the point at which it is within bombarding range of the target and then, say, dotted lines from that point to the target. If the army is out of range we then insert a move order to that firing point.
Comments greatly appreciated (especially if someone can come up with an easier way of doing this).
|
|
|  |
 |
|
Peter Triggs
|
|
Gone Fishin, Canada
Jan 2000 time: 05:22
|
|
Yup, that's the way it used to work in CTP1.
|
|
|  |
 |
|  |
 |
|
Fromafar
|
|
I just had a quick look at the changes you made to ArmyData.cpp. Unfortunately, I have been too busy this week to do much coding and compiling. And I am not sure whether I will get around to do anything on CtP2 in the next 2 weeks.
The change in Bombard looks OK to me. However, the change in PerformOrderHere is probably not needed. Actually, reinstating the original code may already go a large step towards what you are looking for. Note that the "SnipEnd" for-loop will have removed the last "range" steps of the path before inserting the move order - so you will stop moving when "range" steps from the target, and start the actual bombarding from there. When the path is straight, this is most likely just what you want. When the path is bent (around unpassable or higher move cost tiles), you may want to replace the simple for-loop with something more intelligent, so you will stop at the first step of the path that allows you to bombard the target.
Even better would be to make a specialised BombardAStar - as suggested by Peter Triggs - to be used e.g. in the SelectedItem class when the path is computed and you have the bombard order selected.
|
|
|  |
 |
|
Peter Triggs
|
|
Gone Fishin, Canada
Jan 2000 time: 05:22
|
|
This hasn't been extensively tested but, fingers crossed, so far so good. That is, it seems to work.
The first thing I did was to add a function that lets you get the army's min and max bombarding ranges as determined by Units.txt:
code:
#if !defined(ACTIVISION_ORIGINAL)
//----------------------------------------------------------------------------
//
// Name : ArmyData::GetBombardRange
//
// Description: Test if this army can bombard. Fill in min_rge and max_rge.
//
// Parameters : sint32 & min_rge : the min of the bombard ranges of this army's units
// : sint32 & max_rge : the max of the bombard ranges of this army's units
//
// Globals : -
//
// Returns : bool
//
// Remark(s) : min_rge is not used yet, pft
//
// Called by : ArmyData::PerformOrderHere, ArmyData::Bombard
//
//----------------------------------------------------------------------------
bool ArmyData::GetBombardRange(sint32 & min_rge, sint32 & max_rge)
{
sint32 i;
min_rge = 99999;
max_rge = 0;
for(i = 0; i < m_nElements; i++) {
const UnitRecord *rec = g_theUnitDB->Get(m_array[i]->GetType());
sint32 rge;
rec->GetBombardRange(rge);
if(rge){
if(rgemax_rge)
max_rge = rge;
}
}
if(max_rge > 0)
return true;
return false;
}
#endif
This is used in Bombard as follows:
code:
#if defined(ACTIVISION_ORIGINAL)
if(!point.IsNextTo(m_pos)) {
#else
sint32 dist = MapPoint::GetSquaredDistance(m_pos,point);
dist = sqrt(dist);
sint32 min_rge, max_rge;
GetBombardRange(min_rge,max_rge);
if(dist > max_rge) {//the target is out of this army's bombarding range
#endif
return ORDER_RESULT_ILLEGAL;
}
Like I said above, the hairy bit is where you're ordering an army to bombard but it's outside of it's
bombarding range. It's basically just like Fromafar described except that I used the straight line
distance between the army and it's target rather than the path length.
code:
void ArmyData::PerformOrderHere(const OrderRecord * order_rec, const Path * path)
{
Assert(path != NULL);
if (path == NULL)
return ;
if (m_flags & k_CULF_IN_SPACE)
return;
Path *tmp_path = new Path((Path *) path);
MapPoint target_pos;
if (tmp_path->GetMovesRemaining() > 0)
{
target_pos = tmp_path->GetEnd();
}
else
{
target_pos = m_pos;
}
if (s_orderDBToEventMap == NULL)
AssociateEventsWithOrdersDB();
Assert(s_orderDBToEventMap != NULL);
sint32 game_event = s_orderDBToEventMap[order_rec->GetIndex()];
sint32 range = 0;
sint32 moves = tmp_path->GetMovesRemaining();
//order_rec: range = 0 (army must be on top of tile) or range = 1 (can execute order from adjacent tile)
if (order_rec->GetRange()) {
order_rec->GetRange(range);
Assert(range <= moves || order_rec->GetTargetPretestAdjacentPosition());
}
#if !defined(ACTIVISION_ORIGINAL)
sint32 min_rge, max_rge=0;
MapPoint move_pos = m_pos;//move_pos will become a position to move to if trying to bombard out of range
Path *move_path = tmp_path;//copy tmp_path
if (strcmp (order_rec->GetEventName(),"BombardOrder") == 0){
if(GetBombardRange(min_rge, max_rge)){
sint32 dist = MapPoint::GetSquaredDistance(m_pos,target_pos);
dist=sqrt(dist);
if(dist > max_rge){//target is out of range
for(sint32 i=0;iIncDir();
tmp_path->GetCurrentPoint(move_pos);
dist = MapPoint::GetSquaredDistance(move_pos,target_pos);
dist = sqrt(dist);
if(dist <= max_rge){ //we're now within range
tmp_path->Start(m_pos);//reset tmp_path
for(sint32 j=1; jSnipEnd();
}
i=moves;//exit the loop and continue
}
}
}
}
}
else{
#endif
for (sint32 i = 0; moves > 0 && i < range; i++){
tmp_path->SnipEnd();
moves--;
}
#if !defined(ACTIVISION_ORIGINAL)
}
#endif
g_gevManager->Pause();
//insert order's game_event here
if (game_event > 0) {
if (range > 0 || order_rec->GetIsTeleport() || order_rec->GetIsTarget())//event needs target pos
{
g_gevManager->AddEvent( GEV_INSERT_AfterCurrent,
static_cast(game_event),
GEA_Army, Army(m_id),
GEA_MapPoint, target_pos,
GEA_End);
}
else {
g_gevManager->AddEvent( GEV_INSERT_AfterCurrent,
static_cast(game_event),
GEA_Army, Army(m_id),
GEA_End);
}
}
//insert GEV_MoveOrder here, i.e., move adjacent to target pos or within bombarding range of target pos
if (tmp_path->GetMovesRemaining() > 0 && !order_rec->GetIsTeleport() && !order_rec->GetIsTarget()) {
#if !defined(ACTIVISION_ORIGINAL)
if(max_rge){//max_rge >0 implys BombardOrder and army has bombarding units
if(move_pos != m_pos){//then first move army to move_pos
g_gevManager->AddEvent(GEV_INSERT_AfterCurrent, GEV_MoveOrder,
GEA_Army, Army(m_id),
GEA_Path, move_path,
GEA_MapPoint, move_pos,
GEA_Int, (game_event == -1),
GEA_End);
}
//bombard target_pos
g_gevManager->AddEvent( GEV_INSERT_AfterCurrent,
static_cast(game_event),
GEA_Army, Army(m_id),
GEA_MapPoint, target_pos,
GEA_End);
}
else{//not a bombard order
#endif
g_gevManager->AddEvent(GEV_INSERT_AfterCurrent,
GEV_MoveOrder,
GEA_Army, Army(m_id),
GEA_Path, tmp_path,
GEA_MapPoint, target_pos,
GEA_Int, (game_event == -1),
GEA_End);
#if !defined(ACTIVISION_ORIGINAL)
}
#endif
}
else {
delete tmp_path;
}
g_gevManager->AddEvent(GEV_INSERT_AfterCurrent, GEV_ClearOrders,
GEA_Army, Army(m_id),
GEA_End);
g_gevManager->Resume();
}
|
|
|  |
 |
|  |
 |
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:22
|
|
Peter do you have this in a cpp already? I'm a little lost to see where I should paste this code. I'm guessing that getbombardrange is a new function (I didnt see it anywhere) but is there somewhere it has to be placed? And the bombard bitof code is that pasting over something or a new bunch of code?
quote: Originally posted by Peter Triggs
This hasn't been extensively tested but, fingers crossed, so far so good. That is, it seems to work.
The first thing I did was to add a function that lets you get the army's min and max bombarding ranges as determined by Units.txt:
code:
#if !defined(ACTIVISION_ORIGINAL)
//----------------------------------------------------------------------------
//
// Name : ArmyData::GetBombardRange
//
// Description: Test if this army can bombard. Fill in min_rge and max_rge.
//
// Parameters : sint32 & min_rge : the min of the bombard ranges of this army's units
// : sint32 & max_rge : the max of the bombard ranges of this army's units
//
// Globals : -
//
// Returns : bool
//
// Remark(s) : min_rge is not used yet, pft
//
// Called by : ArmyData::PerformOrderHere, ArmyData::Bombard
//
//----------------------------------------------------------------------------
bool ArmyData::GetBombardRange(sint32 & min_rge, sint32 & max_rge)
{
sint32 i;
min_rge = 99999;
max_rge = 0;
for(i = 0; i < m_nElements; i++) {
const UnitRecord *rec = g_theUnitDB->Get(m_array[i]->GetType());
sint32 rge;
rec->GetBombardRange(rge);
if(rge){
if(rgemax_rge)
max_rge = rge;
}
}
if(max_rge > 0)
return true;
return false;
}
#endif
This is used in Bombard as follows:
code:
#if defined(ACTIVISION_ORIGINAL)
if(!point.IsNextTo(m_pos)) {
#else
sint32 dist = MapPoint::GetSquaredDistance(m_pos,point);
dist = sqrt(dist);
sint32 min_rge, max_rge;
GetBombardRange(min_rge,max_rge);
if(dist > max_rge) {//the target is out of this army's bombarding range
#endif
return ORDER_RESULT_ILLEGAL;
}
[/code] |
|
|
|  |
 |
|  |
 |
|  |
 |
|  |
 |
|  |
 |
|  |
 |
|
Fromafar
|
|
Some observations about the ranged bombarding code:
We have to be more precise when defining what ranged bombarding should do. At the moment, the code is mixing 2 different concepts when comparing the range.
The value that is computed by GetSquaredDistance is using a (x, y) map grid with (2,0) coordinate difference for each step east, and a (1,1) coordinate difference for each step southeast. The value returned is 0.5 * (x-difference^2 + y-difference^2) where ^ is denoting the power operation. Example: 0.5 * (4^2 + 0^2) = 8 for 2 steps east, and 0.5 * (3^2 + 1^2) = 5 for 1 step east and 1 step southeast.
When this function is used in other contexts (vision range, city range), this value is compared to (0.5 + range)^2.
This will give you the familiar civilization city "range 2" shape with blind spots in the 4 corners, because the range compare value is 6.25 (being larger than 5, but smaller than 8).
However, the path steps are just 1 step for any direction. There is no difference in steps east or southeast. The actual path computation is based on terrain type and terrain improvents.
So the question is: do you want to be able to bombard from/into the blind spots with a unit with bombard range "2"?
Another problem will be how to handle stacks with bombarders with different range. Do you want to stop moving at the largest range - so part of your stack is unable to bombard? Or do you get closer, risking short range counter bombardments? I fear that introducing ranged bombardment will just result in weakening the AI, because human players are way better in making this decision.
|
|
|  |
 |
|  |
All times are GMT. The time now is 05:22. Apolyton Time is 00:22. |
top of page
|
|
|
Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is ON
vB code is ON
Smilies are ON
[IMG] code is ON
|
|
|
|
|
|