Пример #1
0
void MissileHandlePierce(Missile &missile, const Vec2i &pos)
{
	CUnit *unit = UnitOnMapTile(pos, -1);
	if (unit && unit->IsAliveOnMap()
		&& (missile.Type->FriendlyFire || unit->IsEnemy(*missile.SourceUnit->Player))) {
		missile.MissileHit(unit);
	}
}
Пример #2
0
/**
**	Work for missile hit.
*/
global void MissileHit(int missile)
{
    Unit* goal;

    // FIXME: should I move the PlayMissileSound to here?
    // FIXME: And should the the connected missile be defined in the missile
    // FIXME: structure

    switch( Missiles[missile].Type->Type ) {
    case MissileArrow:
    case MissileAxe:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        break;
    case MissileBallistaBolt:
    case MissileBigCannon:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        MakeMissile(MissileImpact
                    ,Missiles[missile].X
                    ,Missiles[missile].Y
                    ,0,0);
        break;

    case MissileSubmarineMissile:
    case MissileTurtleMissile:
        PlayMissileSound(Missiles+missile,
                         Missiles[missile].Type->ImpactSound.Sound);
        MakeMissile(MissileImpact
                    ,Missiles[missile].X
                    ,Missiles[missile].Y
                    ,0,0);
        break;

    case MissileGreenCross:
        break;
    }

    if( !Missiles[missile].SourceType ) {
        return;
    }

    // FIXME: must choose better goal!
    // FIXME: what can the missile hit?
    goal=UnitOnMapTile(Missiles[missile].X/TileSizeX
                       ,Missiles[missile].Y/TileSizeY);
    if( !goal || !goal->HP ) {
        return;
    }

    HitUnit(goal,CalculateDamage(Missiles[missile].SourceStats,goal));
}
Пример #3
0
/**
**	Handle movement of the cursor.
**
**	@param x	X map tile position.
**	@param y	Y map tile position.
*/
global void HandleMouseMove(int x,int y)
{
    //
    //	Reduce coordinates to window-size.
    //
    if( x<0 ) {
        x=0;
    } else if( x>=VideoWidth ) {
        x=VideoWidth-1;
    }
    if( y<0 ) {
        y=0;
    } else if( y>=VideoHeight ) {
        y=VideoHeight-1;
    }

    CursorX=x;
    CursorY=y;

    //
    //	Selecting units.
    //
    if( CursorState==CursorStateRectangle ) {
        return;
    }

    //
    //	Move map.
    //
    if( CloneCursor==&Cursors[CursorTypeMove] ) {
        int xo = MapX, yo = MapY;

        if ( TheUI.ReverseMouseMove ) {
            if (x < CursorStartX)
                xo++;
            else if (x > CursorStartX)
                xo--;
            if (y < CursorStartY)
                yo++;
            else if (y > CursorStartY)
                yo--;
        } else {
            if (x < CursorStartX)
                xo--;
            else if (x > CursorStartX)
                xo++;
            if (y < CursorStartY)
                yo--;
            else if (y > CursorStartY)
                yo++;
        }
        TheUI.WarpX = CursorStartX;
        TheUI.WarpY = CursorStartY;
        if (xo != MapX || yo != MapY)
            MapSetViewpoint(xo, yo);
        return;
    }

    UnitUnderCursor=NULL;
    CloneCursor=&Cursors[CursorTypePoint];		// Reset
    HandleMouseOn(x,y);
    DebugLevel3("MouseOn %d\n",CursorOn);

    //cade: this is forbidden for unexplored and not visible space
    if( CursorOn==CursorOnMap ) {
        if( MAPVISIBLE(Screen2MapX(x),Screen2MapY(y)) ) {
            UnitUnderCursor=UnitOnScreen(NULL,x-MAP_X+MapX*TileSizeX
                                         ,y-MAP_Y+MapY*TileSizeY);
        }
    } else if( CursorOn==CursorOnMinimap ) {
        if( MAPVISIBLE(Minimap2MapX(x),Minimap2MapY(y)) ) {
            UnitUnderCursor=UnitOnMapTile(Minimap2MapX(x),Minimap2MapY(y));
        }
    }

    //
    //	Selecting target.
    //
    if( CursorState==CursorStateSelect ) {
        if( CursorOn==CursorOnMap || CursorOn==CursorOnMinimap ) {
            CloneCursor=&Cursors[CursorTypeYellowHair];
            if( UnitUnderCursor ) {
                // FIXME: should use IsEnemy here?
                if( UnitUnderCursor->Player==ThisPlayer ) {
                    CloneCursor=&Cursors[CursorTypeGreenHair];
                } else if( UnitUnderCursor->Player->Player!=PlayerNumNeutral ) {
                    CloneCursor=&Cursors[CursorTypeRedHair];
                }
            }
            if( CursorOn==CursorOnMinimap && (MouseButtons&RightButton) ) {
                //
                //	Minimap move viewpoint
                //
                MapSetViewpoint(Minimap2MapX(CursorX)-MapWidth/2
                                ,Minimap2MapY(CursorY)-MapHeight/2);
            }
        }
        // FIXME: must move minimap if right button is down !
        return;
    }

    //
    //	Cursor pointing.
    //
    if( CursorOn==CursorOnMap ) {
        //
        //	Map
        //
        if( UnitUnderCursor ) {
            if( NumSelected==0 ) {
                MustRedraw|=RedrawTopPanel;
            }
            CloneCursor=&Cursors[CursorTypeGlass];
        }

        IfDebug( DrawMouseCoordsOnMap(x,y); );

        return;
    }
Пример #4
0
/**
**	Called when right button is pressed
**
**	@param x	X map tile position.
**	@param y	Y map tile position.
*/
global void DoRightButton(int x,int y)
{
    int i;
    Unit* dest;
    Unit* unit;
    UnitType* type;
    int action;
    int acknowledged;

    //
    // No unit selected
    //
    if( !NumSelected ) {
        return;
    }

    //
    // Unit selected isn't owned by the player.
    // You can't select your own units + foreign unit(s).
    //
    if( Selected[0]->Player!=ThisPlayer ) {
        return;
    }

    acknowledged=0;
    for( i=0; i<NumSelected; ++i ) {
        unit=Selected[i];
        DebugCheck( !unit );
        type=unit->Type;
        if( !acknowledged ) {
            PlayUnitSound(unit,VoiceAcknowledging);
            acknowledged=1;
        }
        action=type->MouseAction;
        DebugLevel3(__FUNCTION__": Mouse action %d\n",action);

        //
        //      Enter transporters?
        //
        dest=UnitOnMapTile(x,y);
        if( dest && dest->Type->Transporter
                && dest->Player==ThisPlayer
                && unit->Type->UnitType==UnitTypeLand ) {
            dest->Blink=3;
            DebugLevel3(__FUNCTION__": Board transporter\n");
            SendCommandBoard(unit,dest);
            continue;
        }

        //
        //      Peon/Peasant
        //
        if( action==MouseActionHarvest ) {
            DebugLevel3("Action %x\n",TheMap.ActionMap[x+y*TheMap.Width]);
            if( type->Type==UnitPeonWithWood
                    || type->Type==UnitPeasantWithWood
                    || type->Type==UnitPeonWithGold
                    || type->Type==UnitPeasantWithGold ) {
                dest=UnitOnMapTile(x,y);
                if( dest ) {
                    dest->Blink=3;
                    if( dest->Type->StoresGold
                            && (type->Type==UnitPeonWithGold
                                || type->Type==UnitPeasantWithGold) ) {
                        DebugLevel3("GOLD-DEPOSIT\n");
                        // FIXME: return to this depot??
                        SendCommandReturnGoods(unit);
                        continue;
                    }
                    if( (dest->Type->StoresWood || dest->Type->StoresGold)
                            && (type->Type==UnitPeonWithWood
                                || type->Type==UnitPeasantWithWood) ) {
                        DebugLevel3("WOOD-DEPOSIT\n");
                        // FIXME: return to this depot??
                        SendCommandReturnGoods(unit);
                        continue;
                    }
                }
            } else {
                if( ForestOnMap(x,y) ) {
                    SendCommandHarvest(unit,x,y);
                    continue;
                }
                if( (dest=GoldMineOnMap(x,y)) ) {
                    dest->Blink=3;
                    DebugLevel3("GOLD-MINE\n");
                    SendCommandMineGold(unit,dest);
                    continue;
                }
            }
            // FIXME: repair/attack/follow/board

            dest=TargetOnMapTile(unit,x,y);
            if( dest ) {
                dest->Blink=3;
                if( dest->Player==ThisPlayer ) {
                    // FIXME: SendCommandFollow(unit,x,y,dest);
                    // FIXME: continue;
                } else {
                    // FIXME: can I attack this unit?
                    SendCommandAttack(unit,x,y,dest);
                    continue;
                }
            }

            // cade: this is default repair action
            dest=UnitOnMapTile(x,y);
            if( dest && dest->Type
                    && dest->Player==ThisPlayer
                    && dest->HP<dest->Stats[dest->Player->Player].HitPoints
                    && dest->Type->Building ) {
                SendCommandRepair(unit,x,y);
            } else {
                SendCommandMoveUnit(unit,x,y);
            }
            continue;
        }

        //
        //      Tanker
        //
        if( action==MouseActionHaulOil ) {
            if( type->Type==UnitTankerOrcFull
                    || type->Type==UnitTankerHumanFull ) {
                DebugLevel2("Should return to oil deposit\n");
            } else {
                if( (dest=PlatformOnMap(x,y)) ) {
                    dest->Blink=3;
                    DebugLevel2("PLATFORM\n");
                    SendCommandHaulOil(unit,dest);
                    continue;
                }
            }

            SendCommandMoveUnit(unit,x,y);
            continue;
        }

        //
        //      Fighters
        //
        if( action==MouseActionAttack ) {
            // FIXME: more units on same tile
            dest=TargetOnMapTile(unit,x,y);
            if( dest ) {
                dest->Blink=3;
                if( dest->Player==ThisPlayer ) {
                    // FIXME: SendCommandFollow(unit,x,y,dest);
                    // FIXME: continue;
                } else {
                    // FIXME: can I attack this unit?
                    SendCommandAttack(unit,x,y,dest);
                    continue;
                }
            }
            if( WallOnMap(x,y) ) {
                DebugLevel3("WALL ON TILE\n");
                if( ThisPlayer->Race==PlayerRaceHuman
                        && OrcWallOnMap(x,y) ) {
                    DebugLevel3("HUMAN ATTACKS ORC\n");
                    SendCommandAttack(unit,x,y,NoUnitP);
                }
                if( ThisPlayer->Race==PlayerRaceOrc
                        && HumanWallOnMap(x,y) ) {
                    DebugLevel3("ORC ATTACKS HUMAN\n");
                    SendCommandAttack(unit,x,y,NoUnitP);
                }
            }
            SendCommandMoveUnit(unit,x,y);
            continue;
        }

        // FIXME: demolish!!!!!!!

        // FIXME: attack/follow/board ...
        if( action==MouseActionMove ) {
        }

//	    if( !unit->Type->Building ) {
        SendCommandMoveUnit(unit,x,y);
//	    }
    }
}
Пример #5
0
/**
**  Compute the cost of crossing tile (dx,dy)
**
**  @param data  The CUnit * that wants to cross the tile.  This is
**               passed in as void * so that the low-level A* code
**               need not know about CUnit.
**  @param x     X tile where to move.
**  @param y     Y tile where to move.
**
**  @pre         The unit's field flags must have been unmarked
**               on the map; see UnmarkUnitFieldFlags.
**
**  @return      -1 -> impossible to cross.
**                0 -> no induced cost, except move
**               >0 -> costly tile
*/
static int STDCALL CostMoveTo(int x, int y, void *data)
{
	int i;
	int j;
	int flag;
	int cost = 0;
	CUnit *goal;
	const CUnit *unit = (const CUnit *)data;
	int mask = unit->Type->MovementMask;

	cost = 0;

	// Doesn't cost anything to move to ourselves :)
	// Used when marking goals mainly.  Could cause speed problems
	if (unit->X == x && unit->Y == y) {
		return 0;
	}

	// verify each tile of the unit.
	for (i = x; i < x + unit->Type->TileWidth; ++i) {
		for (j = y; j < y + unit->Type->TileHeight; ++j) {
			flag = Map.Field(i, j)->Flags & mask;
			if (flag && (AStarKnowUnseenTerrain || Map.IsFieldExplored(unit->Player, i, j))) {
				if (flag & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)) {
					// we can't cross fixed units and other unpassable things
					return -1;
				}
				goal = UnitOnMapTile(i, j, unit->Type->UnitType);
				if (!goal) {
					// Shouldn't happen, mask says there is something on this tile
					Assert(0);
					return -1;
				}

				// The unit must not be blocked by itself.
				// Please use UnmarkUnitFieldFlags and
				// MarkUnitFieldFlags around pathfinder calls.
				Assert(goal != unit);

				if (goal->Moving)  {
					// moving unit are crossable
					cost += AStarMovingUnitCrossingCost;
				} else {
					// for non moving unit Always Fail
					// FIXME: Need support for moving a fixed unit to add cost
					return -1;
					//cost += AStarFixedUnitCrossingCost;
				}
			}
			// Add cost of crossing unknown tiles if required
			if (!AStarKnowUnseenTerrain && !Map.IsFieldExplored(unit->Player, i, j)) {
				// Tend against unknown tiles.
				cost += AStarUnknownTerrainCost;
			}
			if (unit->Type->UnitType != UnitTypeFly) {
				// Add tile movement cost
				cost += Map.Field(i, j)->Cost;
			}
		}
	}
	return cost;
}
Пример #6
0
/**
**  Unit on map tile.
**
**  @param pos   position on map, tile-based.
**  @param type  UnitTypeType, (unsigned)-1 for any type.
**
**  @return      Returns first found unit on tile.
*/
CUnit *UnitOnMapTile(const Vec2i &pos, unsigned int type)
{
	return UnitOnMapTile(Map.getIndex(pos), type);
}
Пример #7
0
/**
**  Find the closest piece of coast you can unload units on
**
**  @param  x     start location for the search
**  @param  y     start location for the search
**  @param  resx  coast x position
**  @param  resy  coast y position
**
**  @return       1 if a location was found, 0 otherwise
*/
static int ClosestFreeCoast(int x, int y, int *resx, int *resy)
{
	int i;
	int addx;
	int addy;
	int nullx;
	int nully;
	int n;

	addx = addy = 1;
	if (Map.CoastOnMap(x, y) &&
			FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
		*resx = x;
		*resy = y;
		return 1;
	}
	--x;
	// The maximum distance to the coast. We have to stop somewhere...
	n = 20;
	while (n--) {
		for (i = addy; i--; ++y) {
			if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
					Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
					FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
				*resx = x;
				*resy = y;
				return 1;
			}
		}
		++addx;
		for (i = addx; i--; ++x) {
			if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
					Map.CoastOnMap(x, y) && !UnitOnMapTile(x ,y) &&
					FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
				*resx = x;
				*resy = y;
				return 1;
			}
		}
		++addy;
		for (i = addy; i--; --y) {
			if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
					Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
					FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
				*resx = x;
				*resy = y;
				return 1;
			}
		}
		++addx;
		for (i = addx; i--; --x) {
			if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
					Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
					FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
				*resx = x;
				*resy = y;
				return 1;
			}
		}
		++addy;
	}
	DebugPrint("Try clicking closer to an actual coast.\n");
	return 0;
}