/** * Kill a unit. When it was a saboteur, expect a big explosion. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_Die(ScriptEngine *script) { const UnitInfo *ui; Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; ui = &g_table_unitInfo[u->o.type]; Unit_Remove(u); if (ui->movementType != MOVEMENT_WINGER) { uint16 credits; credits = max(ui->o.buildCredits / 100, 1); if (u->o.houseID == g_playerHouseID) { g_scenario.killedAllied++; g_scenario.score -= credits; } else { g_scenario.killedEnemy++; g_scenario.score += credits; } } Unit_HouseUnitCount_Remove(u); if (u->o.type != UNIT_SABOTEUR) return 0; Map_MakeExplosion(EXPLOSION_SABOTEUR_DEATH, u->o.position, 300, 0); return 0; }
/** * Make an explosion at the coordinates of the unit. * It does damage to the surrounding units based on the unit. * * Stack: 1 - Explosion type * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_ExplosionSingle(ScriptEngine *script) { Unit *u; u = g_scriptCurrentUnit; Map_MakeExplosion(STACK_PEEK(1), u->o.position, g_table_unitInfo[u->o.type].o.hitpoints, Tools_Index_Encode(u->o.index, IT_UNIT)); return 0; }
/** * Make the structure explode. * * Stack: *none* * * @param script The script engine to operate on. * @return unknown. */ uint16 Script_Structure_Explode(ScriptEngine *script) { Structure *s; uint16 position; uint16 layout; uint16 i; VARIABLE_NOT_USED(script); s = g_scriptCurrentStructure; layout = g_table_structureInfo[s->o.type].layout; position = Tile_PackTile(s->o.position); for (i = 0; i < g_table_structure_layoutTileCount[layout]; i++) { tile32 tile; tile = Tile_UnpackTile(position + g_table_structure_layoutTiles[layout][i]); Map_MakeExplosion(EXPLOSION_STRUCTURE, tile, 0, 0); } return 0; }
/** * Makes the current unit fire a bullet (or eat its target). * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 1 if the current unit fired/eat, 0 otherwise. */ uint16 Script_Unit_Fire(ScriptEngine *script) { const UnitInfo *ui; Unit *u; uint16 target; UnitType typeID; uint16 distance; bool fireTwice; uint16 damage; u = g_scriptCurrentUnit; target = u->targetAttack; if (target == 0 || !Tools_Index_IsValid(target)) return 0; if (u->o.type != UNIT_SANDWORM && target == Tools_Index_Encode(Tile_PackTile(u->o.position), IT_TILE)) u->targetAttack = 0; if (u->targetAttack != target) { Unit_SetTarget(u, target); return 0; } ui = &g_table_unitInfo[u->o.type]; if (u->o.type != UNIT_SANDWORM && u->orientation[ui->o.flags.hasTurret ? 1 : 0].speed != 0) return 0; if (Tools_Index_GetType(target) == IT_TILE && Object_GetByPackedTile(Tools_Index_GetPackedTile(target)) != NULL) Unit_SetTarget(u, target); if (u->fireDelay != 0) return 0; distance = Object_GetDistanceToEncoded(&u->o, target); if ((int16)(ui->fireDistance << 8) < (int16)distance) return 0; if (u->o.type != UNIT_SANDWORM && (Tools_Index_GetType(target) != IT_UNIT || g_table_unitInfo[Tools_Index_GetUnit(target)->o.type].movementType != MOVEMENT_WINGER)) { int16 diff = 0; int8 orientation; orientation = Tile_GetDirection(u->o.position, Tools_Index_GetTile(target)); diff = abs(u->orientation[ui->o.flags.hasTurret ? 1 : 0].current - orientation); if (ui->movementType == MOVEMENT_WINGER) diff /= 8; if (diff >= 8) return 0; } damage = ui->damage; typeID = ui->bulletType; fireTwice = ui->flags.firesTwice && u->o.hitpoints > ui->o.hitpoints / 2; if ((u->o.type == UNIT_TROOPERS || u->o.type == UNIT_TROOPER) && (int16)distance > 512) typeID = UNIT_MISSILE_TROOPER; switch (typeID) { case UNIT_SANDWORM: { Unit *u2; Unit_UpdateMap(0, u); u2 = Tools_Index_GetUnit(target); if (u2 != NULL) { u2->o.script.variables[1] = 0xFFFF; Unit_RemovePlayer(u2); Unit_HouseUnitCount_Remove(u2); Unit_Remove(u2); } Map_MakeExplosion(ui->explosionType, u->o.position, 0, 0); Voice_PlayAtTile(63, u->o.position); Unit_UpdateMap(1, u); u->amount--; script->delay = 12; if ((int8)u->amount < 1) Unit_SetAction(u, ACTION_DIE); } break; case UNIT_MISSILE_TROOPER: damage -= damage / 4; /* FALL-THROUGH */ case UNIT_MISSILE_ROCKET: case UNIT_MISSILE_TURRET: case UNIT_MISSILE_DEVIATOR: case UNIT_BULLET: case UNIT_SONIC_BLAST: { Unit *bullet; bullet = Unit_CreateBullet(u->o.position, typeID, Unit_GetHouseID(u), damage, target); if (bullet == NULL) return 0; bullet->originEncoded = Tools_Index_Encode(u->o.index, IT_UNIT); Voice_PlayAtTile(ui->bulletSound, u->o.position); Unit_Deviation_Decrease(u, 20); } break; default: break; } u->fireDelay = Tools_AdjustToGameSpeed(ui->fireDelay * 2, 1, 0xFFFF, true); if (fireTwice) { u->o.flags.s.fireTwiceFlip = !u->o.flags.s.fireTwiceFlip; if (u->o.flags.s.fireTwiceFlip) u->fireDelay = Tools_AdjustToGameSpeed(5, 1, 10, true) & 0xFF; } else { u->o.flags.s.fireTwiceFlip = false; } u->fireDelay += Tools_Random_256() & 1; Unit_UpdateMap(2, u); return 1; }