/** * Tries to add the closest unit to the current team. * * Stack: *none*. * * @param script The script engine to operate on. * @return The amount of space left in current team. */ uint16 Script_Team_AddClosestUnit(ScriptEngine *script) { Team *t; Unit *closest = NULL; Unit *closest2 = NULL; uint16 minDistance = 0; uint16 minDistance2 = 0; PoolFindStruct find; VARIABLE_NOT_USED(script); t = g_scriptCurrentTeam; if (t->members >= t->maxMembers) return 0; find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; Team *t2; uint16 distance; u = Unit_Find(&find); if (u == NULL) break; if (!u->o.flags.s.byScenario) continue; if (u->o.type == UNIT_SABOTEUR) continue; if (g_table_unitInfo[u->o.type].movementType != t->movementType) continue; if (u->team == 0) { distance = Tile_GetDistance(t->position, u->o.position); if (distance >= minDistance && minDistance != 0) continue; minDistance = distance; closest = u; continue; } t2 = Team_Get_ByIndex(u->team - 1); if (t2->members > t2->minMembers) continue; distance = Tile_GetDistance(t->position, u->o.position); if (distance >= minDistance2 && minDistance2 != 0) continue; minDistance2 = distance; closest2 = u; } if (closest == NULL) closest = closest2; if (closest == NULL) return 0; Unit_RemoveFromTeam(closest); return Unit_AddToTeam(closest, t); }
/** * Gets the distance from the given object to the given encoded index. * @param o The object. * @param encoded The encoded index. * @return The distance. */ uint16 Object_GetDistanceToEncoded(Object* o, uint16 encoded) { Structure* s; tile32 position; s = Tools_Index_GetStructure(encoded); if (s != NULL) { uint16 packed; position = s->o.position; packed = Tile_PackTile(position); packed += g_table_structure_layoutEdgeTiles[g_table_structureInfo[o->type].layout][(Orientation_256To8(Tile_GetDirection(o->position, position)) + 4) & 7]; position = Tile_UnpackTile(packed); } else { position = Tools_Index_GetTile(encoded); } return Tile_GetDistance(o->position, position); }
/** * Unknown function 0788. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Team_Unknown0788(ScriptEngine *script) { Team *t; tile32 tile; PoolFindStruct find; VARIABLE_NOT_USED(script); t = g_scriptCurrentTeam; if (t->target == 0) return 0; tile = Tools_Index_GetTile(t->target); find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; uint16 distance; uint16 packed; int16 orientation; u = Unit_Find(&find); if (u == NULL) break; if (u->team - 1 != t->index) continue; if (t->target == 0) { Unit_SetAction(u, ACTION_GUARD); continue; } distance = g_table_unitInfo[u->o.type].fireDistance << 8; if (u->actionID == ACTION_ATTACK && u->targetAttack == t->target) { if (u->targetMove != 0) continue; if (Tile_GetDistance(u->o.position, tile) >= distance) continue; } if (u->actionID != ACTION_ATTACK) Unit_SetAction(u, ACTION_ATTACK); orientation = (Tile_GetDirection(tile, u->o.position) & 0xC0) + Tools_RandomLCG_Range(0, 127); if (orientation < 0) orientation += 256; packed = Tile_PackTile(Tile_MoveByDirection(tile, orientation, distance)); if (Object_GetByPackedTile(packed) == NULL) { Unit_SetDestination(u, Tools_Index_Encode(packed, IT_TILE)); } else { Unit_SetDestination(u, Tools_Index_Encode(Tile_PackTile(tile), IT_TILE)); } Unit_SetTarget(u, t->target); } return 0; }
/** * Move the Unit to the target, and keep repeating this function till we * arrived there. When closing in on the target it will slow down the Unit. * It is wise to only use this function on Carry-Alls. * * Stack: *none*. * * @param script The script engine to operate on. * @return 1 if arrived, 0 if still busy. */ uint16 Script_Unit_MoveToTarget(ScriptEngine *script) { Unit *u; uint16 delay; tile32 tile; uint16 distance; int8 orientation; int16 diff; u = g_scriptCurrentUnit; if (u->targetMove == 0) return 0; tile = Tools_Index_GetTile(u->targetMove); distance = Tile_GetDistance(u->o.position, tile); if ((int16)distance < 128) { Unit_SetSpeed(u, 0); u->o.position.s.x += clamp((int16)(tile.s.x - u->o.position.s.x), -16, 16); u->o.position.s.y += clamp((int16)(tile.s.y - u->o.position.s.y), -16, 16); Unit_UpdateMap(2, u); if ((int16)distance < 32) return 1; script->delay = 2; script->script--; return 0; } orientation = Tile_GetDirection(u->o.position, tile); Unit_SetOrientation(u, orientation, false, 0); diff = abs(orientation - u->orientation[0].current); if (diff > 128) diff = 256 - diff; Unit_SetSpeed(u, (Tools_AdjustToGameSpeed(min(distance / 8, 255), 25, 255, true) * (255 - diff) + 128) / 256); delay = max((int16)distance / 1024, 1); Unit_UpdateMap(2, u); if (delay != 0) { script->delay = delay; script->script--; } return 0; }
/** * Find a Unit which is within range and not an ally. * * Stack: 1 - Range to find a target in (amount of tiles multiplied with 256). * * @param script The script engine to operate on. * @return The Unit Index of the closest unit within range and not friendly, * or 0 if none exists. */ uint16 Script_Structure_FindTargetUnit(ScriptEngine *script) { PoolFindStruct find; Structure *s; Unit *u; uint32 distanceCurrent; uint32 targetRange; s = g_scriptCurrentStructure; targetRange = STACK_PEEK(1); distanceCurrent = 32000; u = NULL; find.houseID = HOUSE_INVALID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { uint16 distance; Unit *uf; uf = Unit_Find(&find); if (uf == NULL) break; if (House_AreAllied(s->o.houseID, uf->o.houseID)) continue; if (uf->o.type != UNIT_ORNITHOPTER) { if ((uf->o.seenByHouses & (1 << s->o.houseID)) == 0) continue; } distance = Tile_GetDistance(uf->o.position, s->o.position); if (distance >= distanceCurrent) continue; if (uf->o.type == UNIT_ORNITHOPTER) { if (distance >= targetRange * 3) continue; } else { if (distance >= targetRange) continue; } /* ENHANCEMENT -- The original code swapped the assignment, making it do nothing, Now it finds the closest unit to shoot at, what seems to be the intention */ if (g_dune2_enhanced) distanceCurrent = distance; u = uf; } if (u == NULL) return IT_NONE; return Tools_Index_Encode(u->o.index, IT_UNIT); }
/** * Fire a bullet or missile from a (rocket) turret. * * Stack: *none* * Variables: 2 - Target to shoot at. * * @param script The script engine to operate on. * @return The time between this and the next time firing. */ uint16 Script_Structure_Fire(ScriptEngine *script) { Structure *s; Unit *u; tile32 position; uint16 target; uint16 damage; uint16 fireDelay; uint16 type; s = g_scriptCurrentStructure; target = script->variables[2]; if (target == 0) return 0; if (s->o.type == STRUCTURE_ROCKET_TURRET && Tile_GetDistance(Tools_Index_GetTile(target), s->o.position) >= 0x300) { type = UNIT_MISSILE_TURRET; damage = 30; fireDelay = Tools_AdjustToGameSpeed(g_table_unitInfo[UNIT_LAUNCHER].fireDelay, 1, 255, true); } else { type = UNIT_BULLET; damage = 20; fireDelay = Tools_AdjustToGameSpeed(g_table_unitInfo[UNIT_TANK].fireDelay, 1, 255, true); } position.tile = s->o.position.tile; position.s.x += 0x80; position.s.y += 0x80; u = Unit_CreateBullet(position, type, s->o.houseID, damage, target); if (u == NULL) return 0; u->originEncoded = Tools_Index_Encode(s->o.index, IT_STRUCTURE); return fireDelay; }
/** * Calculates the rounded up distance between the two given packed tiles. * * @param from The origin. * @param to The destination. * @return The longest distance between the X or Y coordinates, plus half the shortest. */ uint16 Tile_GetDistanceRoundedUp(tile32 from, tile32 to) { return (Tile_GetDistance(from, to) + 0x80) >> 8; }