/** ** Repairable unit on screen map position. ** ** @param x X position on screen map, pixel-based. ** @param y Y position on screen map, pixel-based. ** ** @return Returns repairable unit found on screen map position. */ global Unit* RepairableOnScreenMapPosition(int x,int y) { Unit* table[UnitMax]; int tx; int ty; int n; int i; tx = x / TileSizeX; ty = y / TileSizeY; n = UnitCacheSelect(tx-2,ty-2, tx+2, ty+2, table); for( i=0; i<n; ++i ) { // FIXME: could use more or less for repair? Repair of ships/catapults. // Only repairable if target is a building or tansporter and it's HP is // not at max if( (table[i]->Type->Building || table[i]->Type->Transporter) && table[i]->HP < table[i]->Stats->HitPoints ) { if (InsideUnitSprite(table[i], x, y)) { return table[i]; } } } return NoUnitP; }
/** ** Searches for unit whose sprite is drawn at (x,y) pixel map position. ** ** @param x X position on screen map, pixel-based. ** @param y Y position on screen map, pixel-based. ** ** @return Returns unit found at this pixel map coordinates */ global Unit* UnitOnScreenMapPosition(int x,int y) { Unit* table[UnitMax]; int tx; int ty; int n; int i; // this code runs quite often (e.g. upon each motion notify) so this // little optimization could be appropriate tx = x / TileSizeX; ty = y / TileSizeY; // fast path, should work most of the time n = SelectUnitsOnTile(tx, ty, table); for( i=0; i<n; ++i ) { if( !table[i]->Type->Vanishes && InsideUnitSprite(table[i], x, y)) { return table[i]; } } // if we got here we have to search for our unit in the neighborhood // ships and flyers could be 2 fields away n = UnitCacheSelect(tx-2,ty-2, tx+2, ty+2, table); for( i=0; i<n; ++i ) { if( !table[i]->Type->Vanishes && InsideUnitSprite(table[i], x, y)) { return table[i]; } } return NoUnitP; }
/** ** Select units in rectangle range. ** ** @param x1 Left column of selection rectangle ** @param y1 Top row of selection rectangle ** @param x2 Right column of selection rectangle ** @param y2 Bottom row of selection rectangle ** @param table All units in the selection rectangle ** ** @return Returns the number of units found */ global int SelectUnits(int x1,int y1,int x2,int y2,Unit** table) { if ( x1 == x2 && y1 == y2 ) { return UnitCacheOnTile(x1,y1,table); } else { return UnitCacheSelect(x1,y1,x2,y2,table); } }
/** ** Change unit owner ** ** @param l Lua state. */ static int CclChangeUnitsOwner(lua_State *l) { CUnit *table[UnitMax]; int n; int oldp; int newp; int x1; int y1; int x2; int y2; LuaCheckArgs(l, 4); if (!lua_istable(l, 1) || !lua_istable(l, 2)) { LuaError(l, "incorrect argument"); } if (luaL_getn(l, 1) != 2) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, 1, 1); x1 = LuaToNumber(l, -1); lua_pop(l, 1); lua_rawgeti(l, 1, 1); y1 = LuaToNumber(l, -1); lua_pop(l, 1); if (luaL_getn(l, 2) != 2) { LuaError(l, "incorrect argument"); } lua_rawgeti(l, 2, 1); x2 = LuaToNumber(l, -1); lua_pop(l, 1); lua_rawgeti(l, 2, 1); y2 = LuaToNumber(l, -1); lua_pop(l, 1); n = UnitCacheSelect(x1, y1, x2 + 1, y2 + 1, table); oldp = LuaToNumber(l, 3); newp = LuaToNumber(l, 4); while (n) { if (table[n - 1]->Player->Index == oldp) { table[n - 1]->ChangeOwner(&Players[newp]); } --n; } return 0; }
/** ** Choose target at pixel map coordinates. ** ** @param source Unit which wants to attack. ** @param x X position on the display map, pixel-based. ** @param y Y position on the display map, pixel-based. ** ** @return Returns ideal target */ global Unit* TargetOnScreenMapPosition(const Unit* source,int x,int y) { Unit* table[UnitMax]; Unit* unit; Unit* best; int tx; int ty; int n; int i; // this code runs upon right button action only so it can affort being a // little inefficient. tx = x / TileSizeX; ty = y / TileSizeY; // ships and flyers could be 2 fields away n = UnitCacheSelect(tx-2,ty-2, tx+2, ty+2, table); best=NoUnitP; for( i=0; i<n; ++i ) { unit=table[i]; // unusable unit ? // if( UnitUnusable(unit) ) can't attack constructions // FIXME: did SelectUnitsOnTile already filter this? // Invisible and not Visible if( unit->Removed || unit->Invisible || !(unit->Visible&(1<<source->Player->Player)) || unit->Orders[0].Action==UnitActionDie ) { continue; } if ( !InsideUnitSprite(table[i], x, y)) { continue; } if( !CanTarget(source->Type,unit->Type) ) { continue; } // // Choose the best target. // if( !best || best->Type->Priority < unit->Type->Priority ) { best=unit; } } return best; }
/** ** Transporter unit on screen map position. ** ** @param x X position on screen map, pixel-based. ** @param y Y position on screen map, pixel-based. ** ** @return Returns transporter unit found on tile. */ global Unit* TransporterOnScreenMapPosition(int x,int y) { Unit* table[UnitMax]; int tx; int ty; int n; int i; tx = x / TileSizeX; ty = y / TileSizeY; // n=SelectUnitsOnTile(tx,ty,table); n = UnitCacheSelect(tx-2,ty-2, tx+2, ty+2, table); for( i=0; i<n; ++i ) { if( table[i]->Type->Transporter && InsideUnitSprite(table[i], x, y)) { return table[i]; } } return NoUnitP; }
/** ** Find all units to draw in viewport. ** ** @param vp Viewport to be drawn. ** @param table Table of units to return in sorted order ** */ int FindAndSortUnits(const CViewport *vp, CUnit **table) { int i; int n; // // Select all units touching the viewpoint. // n = UnitCacheSelect(vp->MapX - 1, vp->MapY - 1, vp->MapX + vp->MapWidth + 1, vp->MapY + vp->MapHeight + 1, table); for (i = 0; i < n; i++) { if (!table[i]->IsVisibleInViewport(vp)) { table[i--] = table[--n]; } } if (n) { qsort((void *)table, n, sizeof(CUnit *), DrawLevelCompare); } return n; }