void CCobInstance::TransportDrop(const CUnit* unit, const float3& pos) { vector<int> args; args.push_back(unit->id); args.push_back(PACKXZ(pos.x, pos.z)); Call(COBFN_TransportDrop, args); }
void CTransportCAI::UnloadDrop(Command& c) { //fly over and drop unit if(inCommand){ if(!owner->cob->busy) //if(scriptReady) FinishCommand(); } else { if(((CTransportUnit*)owner)->transported.empty()){ FinishCommand(); return; } float3 pos(c.params[0],c.params[1],c.params[2]); //head towards goal //note that taairmovetype must be modified to allow non stop movement through goals for this to work well if(goalPos.distance2D(pos)>20){ SetGoal(pos,owner->pos); lastDropPos = pos; } if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){ pos.y=ground->GetHeight(pos.x,pos.z); CUnit* unit=((CTransportUnit*)owner)->transported.front().unit; am->maxDrift=1; //if near target or have past it accidentally- drop unit if(owner->pos.distance2D(pos) < 40 || (((pos - owner->pos).Normalize()).distance(owner->frontdir.Normalize()) > 0.5 && owner->pos.distance2D(pos)< 205)) { am->dontLand=true; owner->cob->Call("EndTransport"); //test ((CTransportUnit*)owner)->DetachUnitFromAir(unit,pos); dropSpots.pop_back(); if (dropSpots.empty()) { float3 fix = owner->pos+owner->frontdir*200; SetGoal(fix,owner->pos);//move the transport away after last drop } FinishCommand(); } } else { inCommand=true; scriptReady=false; StopMove(); std::vector<int> args; args.push_back(((CTransportUnit*)owner)->transported.front().unit->id); args.push_back(PACKXZ(pos.x, pos.z)); owner->cob->Call("TransportDrop",args,ScriptCallback,this,0); } } }
int CUnitScript::GetUnitVal(int val, int p1, int p2, int p3, int p4) { // may happen in case one uses Spring.GetUnitCOBValue (Lua) on a unit with CNullUnitScript if (!unit) { ShowScriptError("Error: no unit (in GetUnitVal)"); return 0; } #ifndef _CONSOLE switch (val) { case ACTIVATION: if (unit->activated) return 1; else return 0; break; case STANDINGMOVEORDERS: return unit->moveState; break; case STANDINGFIREORDERS: return unit->fireState; break; case HEALTH: { if (p1 <= 0) return int((unit->health / unit->maxHealth) * 100.0f); const CUnit* u = uh->GetUnit(p1); if (u == NULL) return 0; else return int((u->health / u->maxHealth) * 100.0f); } case INBUILDSTANCE: if (unit->inBuildStance) return 1; else return 0; case BUSY: if (busy) return 1; else return 0; break; case PIECE_XZ: { if (!PieceExists(p1)) { ShowScriptError("Invalid piecenumber for get piece_xz"); break; } const float3 relPos = GetPiecePos(p1); const float3 absPos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; return PACKXZ(absPos.x, absPos.z); } case PIECE_Y: { if (!PieceExists(p1)) { ShowScriptError("Invalid piecenumber for get piece_y"); break; } const float3 relPos = GetPiecePos(p1); const float3 absPos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; return int(absPos.y * COBSCALE); } case UNIT_XZ: { if (p1 <= 0) return PACKXZ(unit->pos.x, unit->pos.z); const CUnit* u = uh->GetUnit(p1); if (u == NULL) return PACKXZ(0, 0); else return PACKXZ(u->pos.x, u->pos.z); } case UNIT_Y: { if (p1 <= 0) return int(unit->pos.y * COBSCALE); const CUnit* u = uh->GetUnit(p1); if (u == NULL) return 0; else return int(u->pos.y * COBSCALE); } case UNIT_HEIGHT: { if (p1 <= 0) return int(unit->radius * COBSCALE); const CUnit* u = uh->GetUnit(p1); if (u == NULL) return 0; else return int(u->radius * COBSCALE); } case XZ_ATAN: return int(RAD2TAANG*math::atan2((float)UNPACKX(p1), (float)UNPACKZ(p1)) + 32768 - unit->heading); case XZ_HYPOT: return int(math::hypot((float)UNPACKX(p1), (float)UNPACKZ(p1)) * COBSCALE); case ATAN: return int(RAD2TAANG*math::atan2((float)p1, (float)p2)); case HYPOT: return int(math::hypot((float)p1, (float)p2)); case GROUND_HEIGHT: return int(ground->GetHeightAboveWater(UNPACKX(p1), UNPACKZ(p1)) * COBSCALE); case GROUND_WATER_HEIGHT: return int(ground->GetHeightReal(UNPACKX(p1), UNPACKZ(p1)) * COBSCALE); case BUILD_PERCENT_LEFT: return int((1.0f - unit->buildProgress) * 100); case YARD_OPEN: if (yardOpen) return 1; else return 0; case BUGGER_OFF: break; case ARMORED: if (unit->armoredState) return 1; else return 0; case VETERAN_LEVEL: return int(100 * unit->experience); case CURRENT_SPEED: return int(unit->speed.Length() * COBSCALE); case ON_ROAD: return 0; case IN_WATER: return (unit->pos.y < 0.0f) ? 1 : 0; case MAX_ID: return uh->MaxUnits()-1; case MY_ID: return unit->id; case UNIT_TEAM: { const CUnit* u = uh->GetUnit(p1); return (u != NULL)? unit->team : 0; } case UNIT_ALLIED: { const CUnit* u = uh->GetUnit(p1); if (u != NULL) { return teamHandler->Ally(unit->allyteam, u->allyteam) ? 1 : 0; } return 0; } case UNIT_BUILD_PERCENT_LEFT: { const CUnit* u = uh->GetUnit(p1); if (u != NULL) { return int((1.0f - u->buildProgress) * 100); } return 0; } case MAX_SPEED: { return int(unit->moveType->GetMaxSpeed() * COBSCALE); } break; case REVERSING: { CGroundMoveType* gmt = dynamic_cast<CGroundMoveType*>(unit->moveType); return ((gmt != NULL)? int(gmt->IsReversing()): 0); } break; case CLOAKED: return !!unit->isCloaked; case WANT_CLOAK: return !!unit->wantCloak; case UPRIGHT: return !!unit->upright; case POW: return int(math::pow(((float)p1)/COBSCALE,((float)p2)/COBSCALE)*COBSCALE); case PRINT: LOG("Value 1: %d, 2: %d, 3: %d, 4: %d", p1, p2, p3, p4); break; case HEADING: { if (p1 <= 0) { return unit->heading; } const CUnit* u = uh->GetUnit(p1); if (u != NULL) { return u->heading; } return -1; } case TARGET_ID: { if (unit->weapons[p1 - 1]) { const CWeapon* weapon = unit->weapons[p1 - 1]; const TargetType tType = weapon->targetType; if (tType == Target_Unit) return unit->weapons[p1 - 1]->targetUnit->id; else if (tType == Target_None) return -1; else if (tType == Target_Pos) return -2; else // Target_Intercept return -3; } return -4; // weapon does not exist } case LAST_ATTACKER_ID: return unit->lastAttacker? unit->lastAttacker->id: -1; case LOS_RADIUS: return unit->realLosRadius; case AIR_LOS_RADIUS: return unit->realAirLosRadius; case RADAR_RADIUS: return unit->radarRadius; case JAMMER_RADIUS: return unit->jammerRadius; case SONAR_RADIUS: return unit->sonarRadius; case SONAR_JAM_RADIUS: return unit->sonarJamRadius; case SEISMIC_RADIUS: return unit->seismicRadius; case DO_SEISMIC_PING: float pingSize; if (p1 == 0) { pingSize = unit->seismicSignature; } else { pingSize = p1; } unit->DoSeismicPing(pingSize); break; case CURRENT_FUEL: return int(unit->currentFuel * float(COBSCALE)); case TRANSPORT_ID: return unit->transporter?unit->transporter->id:-1; case SHIELD_POWER: { if (unit->shieldWeapon == NULL) { return -1; } const CPlasmaRepulser* shield = (CPlasmaRepulser*) unit->shieldWeapon; return int(shield->curPower * float(COBSCALE)); } case STEALTH: { return unit->stealth ? 1 : 0; } case SONAR_STEALTH: { return unit->sonarStealth ? 1 : 0; } case CRASHING: return !!unit->crashing; case ALPHA_THRESHOLD: { return int(unit->alphaThreshold * 255); } case COB_ID: { if (p1 <= 0) { return unit->unitDef->cobID; } else { const CUnit* u = uh->GetUnit(p1); return ((u == NULL)? -1 : u->unitDef->cobID); } } case PLAY_SOUND: { // FIXME: this can currently only work for CCobInstance, because Lua can not get sound IDs // (however, for Lua scripts there is already LuaUnsyncedCtrl::PlaySoundFile) CCobInstance* cob = dynamic_cast<CCobInstance*>(this); if (cob == NULL) { return 1; } const CCobFile* script = cob->GetScriptAddr(); if (script == NULL) { return 1; } if ((p1 < 0) || (static_cast<size_t>(p1) >= script->sounds.size())) { return 1; } switch (p3) { //who hears the sound case 0: //ALOS if (!loshandler->InAirLos(unit->pos,gu->myAllyTeam)) { return 0; } break; case 1: //LOS if (!(unit->losStatus[gu->myAllyTeam] & LOS_INLOS)) { return 0; } break; case 2: //ALOS or radar if (!(loshandler->InAirLos(unit->pos,gu->myAllyTeam) || unit->losStatus[gu->myAllyTeam] & (LOS_INRADAR))) { return 0; } break; case 3: //LOS or radar if (!(unit->losStatus[gu->myAllyTeam] & (LOS_INLOS | LOS_INRADAR))) { return 0; } break; case 4: //everyone break; case 5: //allies if (unit->allyteam != gu->myAllyTeam) { return 0; } break; case 6: //team if (unit->team != gu->myTeam) { return 0; } break; case 7: //enemies if (unit->allyteam == gu->myAllyTeam) { return 0; } break; } if (p4 == 0) { Channels::General.PlaySample(script->sounds[p1], unit->pos, unit->speed, float(p2) / COBSCALE); } else { Channels::General.PlaySample(script->sounds[p1], float(p2) / COBSCALE); } return 0; } case SET_WEAPON_UNIT_TARGET: { const unsigned int weaponID = p1 - 1; const unsigned int targetID = p2; const bool userTarget = !!p3; if (weaponID >= unit->weapons.size()) { return 0; } CWeapon* weapon = unit->weapons[weaponID]; if (weapon == NULL) { return 0; } //! if targetID is 0, just sets weapon->haveUserTarget //! to false (and targetType to None) without attacking CUnit* target = (targetID > 0)? uh->GetUnit(targetID): NULL; return (weapon->AttackUnit(target, userTarget) ? 1 : 0); } case SET_WEAPON_GROUND_TARGET: { const int weaponID = p1 - 1; const float3 pos = float3(float(UNPACKX(p2)), float(p3) / float(COBSCALE), float(UNPACKZ(p2))); const bool userTarget = !!p4; if ((weaponID < 0) || (static_cast<size_t>(weaponID) >= unit->weapons.size())) { return 0; } CWeapon* weapon = unit->weapons[weaponID]; if (weapon == NULL) { return 0; } return weapon->AttackGround(pos, userTarget) ? 1 : 0; } case MIN: return std::min(p1, p2); case MAX: return std::max(p1, p2); case ABS: return abs(p1); case KSIN: return int(1024*math::sinf(TAANG2RAD*(float)p1)); case KCOS: return int(1024*math::cosf(TAANG2RAD*(float)p1)); case KTAN: return int(1024*math::tanf(TAANG2RAD*(float)p1)); case SQRT: return int(math::sqrt((float)p1)); case FLANK_B_MODE: return unit->flankingBonusMode; case FLANK_B_DIR: switch (p1) { case 1: return int(unit->flankingBonusDir.x * COBSCALE); case 2: return int(unit->flankingBonusDir.y * COBSCALE); case 3: return int(unit->flankingBonusDir.z * COBSCALE); case 4: unit->flankingBonusDir.x = (p2/(float)COBSCALE); return 0; case 5: unit->flankingBonusDir.y = (p2/(float)COBSCALE); return 0; case 6: unit->flankingBonusDir.z = (p2/(float)COBSCALE); return 0; case 7: unit->flankingBonusDir = float3(p2/(float)COBSCALE, p3/(float)COBSCALE, p4/(float)COBSCALE).Normalize(); return 0; default: return(-1); } case FLANK_B_MOBILITY_ADD: return int(unit->flankingBonusMobilityAdd * COBSCALE); case FLANK_B_MAX_DAMAGE: return int((unit->flankingBonusAvgDamage + unit->flankingBonusDifDamage) * COBSCALE); case FLANK_B_MIN_DAMAGE: return int((unit->flankingBonusAvgDamage - unit->flankingBonusDifDamage) * COBSCALE); case KILL_UNIT: { //! ID 0 is reserved for the script's owner CUnit* u = (p1 > 0)? uh->GetUnit(p1): this->unit; if (u == NULL) { return 0; } if (u->beingBuilt) { // no explosions and no corpse for units under construction u->KillUnit(false, true, NULL); } else { u->KillUnit(p2 != 0, p3 != 0, NULL); } return 1; } case WEAPON_RELOADSTATE: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return unit->weapons[p1-1]->reloadStatus; } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->reloadStatus; unit->weapons[np1 - 1]->reloadStatus = p2; return old; } else { return -1; } } case WEAPON_RELOADTIME: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return unit->weapons[p1-1]->reloadTime; } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->reloadTime; unit->weapons[np1 - 1]->reloadTime = p2; return old; } else { return -1; } } case WEAPON_ACCURACY: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return int(unit->weapons[p1-1]->accuracy * COBSCALE); } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->accuracy * COBSCALE; unit->weapons[np1 - 1]->accuracy = float(p2) / COBSCALE; return old; } else { return -1; } } case WEAPON_SPRAY: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return int(unit->weapons[p1-1]->sprayAngle * COBSCALE); } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->sprayAngle * COBSCALE; unit->weapons[np1 - 1]->sprayAngle = float(p2) / COBSCALE; return old; } else { return -1; } } case WEAPON_RANGE: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return int(unit->weapons[p1 - 1]->range * COBSCALE); } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->range * COBSCALE; unit->weapons[np1 - 1]->range = float(p2) / COBSCALE; return old; } else { return -1; } } case WEAPON_PROJECTILE_SPEED: { const int np1 = -p1; if (p1 > 0 && static_cast<size_t>(p1) <= unit->weapons.size()) { return int(unit->weapons[p1-1]->projectileSpeed * COBSCALE); } else if (np1 > 0 && static_cast<size_t>(np1) <= unit->weapons.size()) { const int old = unit->weapons[np1 - 1]->projectileSpeed * COBSCALE; unit->weapons[np1 - 1]->projectileSpeed = float(p2) / COBSCALE; return old; } else { return -1; } } case GAME_FRAME: { return gs->frameNum; } default: if ((val >= GLOBAL_VAR_START) && (val <= GLOBAL_VAR_END)) { return globalVars[val - GLOBAL_VAR_START]; } else if ((val >= TEAM_VAR_START) && (val <= TEAM_VAR_END)) { return teamVars[unit->team][val - TEAM_VAR_START]; } else if ((val >= ALLY_VAR_START) && (val <= ALLY_VAR_END)) { return allyVars[unit->allyteam][val - ALLY_VAR_START]; } else if ((val >= UNIT_VAR_START) && (val <= UNIT_VAR_END)) { const int varID = val - UNIT_VAR_START; if (p1 == 0) { return unitVars[varID]; } else if (p1 > 0) { // get the unit var for another unit const CUnit* u = uh->GetUnit(p1); if (u != NULL && u->script != NULL) { return u->script->unitVars[varID]; } } else { // set the unit var for another unit p1 = -p1; CUnit* u = uh->GetUnit(p1); if (u != NULL && u->script != NULL) { u->script->unitVars[varID] = p2; return 1; } } return 0; } else { LOG_L(L_ERROR, "CobError: Unknown get constant %d (params = %d %d %d %d)", val, p1, p2, p3, p4); } } #endif return 0; }
void CLuaCob::CallFunction(const LuaHashString& name, const CUnit* unit, int& argsCount, int args[MAX_LUA_COB_ARGS]) { static int callDepth = 0; if (callDepth >= 16) { logOutput.Print("CLuaCob::CallFunction() call overflow: %s\n", name.GetString().c_str()); args[0] = 0; // failure return; } lua_settop(L, 0); if (!name.GetGlobalFunc(L)) { lua_settop(L, 0); logOutput.Print("CLuaCob::CallFunction() missing function: %s\n", name.GetString().c_str()); args[0] = 0; // failure return; } lua_pushnumber(L, unit->id); lua_pushnumber(L, unit->unitDef->id); lua_pushnumber(L, unit->team); for (int a = 0; a < argsCount; a++) { lua_pushnumber(L, args[a]); } // call the routine callDepth++; const int* oldArgs = currentArgs; currentArgs = args; const bool error = !RunCallIn(name, 3 + argsCount, LUA_MULTRET); currentArgs = oldArgs; callDepth--; // bail on error if (error) { args[0] = 0; // failure return; } // get the results const int retArgs = min(lua_gettop(L), (MAX_LUA_COB_ARGS - 1)); for (int a = 1; a <= retArgs; a++) { if (lua_isnumber(L, a)) { args[a] = (int)lua_tonumber(L, a); } else if (lua_isboolean(L, a)) { args[a] = lua_toboolean(L, a) ? 1 : 0; } else if (lua_istable(L, a)) { lua_rawgeti(L, a, 1); lua_rawgeti(L, a, 2); if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) { const int x = (int)lua_tonumber(L, -2); const int z = (int)lua_tonumber(L, -1); args[a] = PACKXZ(x, z); } else { args[a] = 0; } lua_pop(L, 2); } else { args[a] = 0; } } args[0] = 1; // success return; }
void CLuaRules::Cob2Lua(const LuaHashString& name, const CUnit* unit, int& argsCount, int args[MAX_LUA_COB_ARGS]) { static int callDepth = 0; if (callDepth >= 16) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() call overflow: %s", name.GetString().c_str()); args[0] = 0; // failure return; } LUA_CALL_IN_CHECK(L); const int top = lua_gettop(L); if (!lua_checkstack(L, 1 + 3 + argsCount)) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() lua_checkstack() error: %s", name.GetString().c_str()); args[0] = 0; // failure lua_settop(L, top); return; } if (!name.GetGlobalFunc(L)) { LOG_L(L_WARNING, "CLuaRules::Cob2Lua() missing function: %s", name.GetString().c_str()); args[0] = 0; // failure lua_settop(L, top); return; } lua_pushnumber(L, unit->id); lua_pushnumber(L, unit->unitDef->id); lua_pushnumber(L, unit->team); for (int a = 0; a < argsCount; a++) { lua_pushnumber(L, args[a]); } // call the routine callDepth++; const int* oldArgs = currentCobArgs; currentCobArgs = args; const bool error = !RunCallIn(name, 3 + argsCount, LUA_MULTRET); currentCobArgs = oldArgs; callDepth--; // bail on error if (error) { args[0] = 0; // failure lua_settop(L, top); return; } // get the results const int retArgs = std::min(lua_gettop(L) - top, (MAX_LUA_COB_ARGS - 1)); for (int a = 1; a <= retArgs; a++) { const int index = (a + top); if (lua_isnumber(L, index)) { args[a] = lua_toint(L, index); } else if (lua_isboolean(L, index)) { args[a] = lua_toboolean(L, index) ? 1 : 0; } else if (lua_istable(L, index)) { lua_rawgeti(L, index, 1); lua_rawgeti(L, index, 2); if (lua_isnumber(L, -2) && lua_isnumber(L, -1)) { const int x = lua_toint(L, -2); const int z = lua_toint(L, -1); args[a] = PACKXZ(x, z); } else { args[a] = 0; } lua_pop(L, 2); } else { args[a] = 0; } } args[0] = 1; // success lua_settop(L, top); return; }
void CTransportCAI::SlowUpdate(void) { if(commandQue.empty()){ CMobileCAI::SlowUpdate(); return; } CTransportUnit* transport=(CTransportUnit*)owner; Command& c=commandQue.front(); switch(c.id){ case CMD_LOAD_UNITS: if(c.params.size()==1){ //load single unit if(transport->transportCapacityUsed >= owner->unitDef->transportCapacity){ FinishCommand(); return; } if(inCommand){ if(!owner->cob->busy) FinishCommand(); return; } CUnit* unit=uh->units[(int)c.params[0]]; if(unit && CanTransport(unit)){ toBeTransportedUnitId=unit->id; unit->toBeTransported=true; if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass){ FinishCommand(); return; } if(goalPos.distance2D(unit->pos)>10){ float3 fix = unit->pos; SetGoal(fix,owner->pos,64); } if(unit->pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9){ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){ //handle air transports differently float3 wantedPos=unit->pos+UpVector*unit->model->height; SetGoal(wantedPos,owner->pos); am->dontCheckCol=true; am->ForceHeading(unit->heading); am->SetWantedAltitude(unit->model->height); am->maxDrift=1; //info->AddLine("cai dist %f %f %f",owner->pos.distance(wantedPos),owner->pos.distance2D(wantedPos),owner->pos.y-wantedPos.y); if(owner->pos.distance(wantedPos)<4 && abs(owner->heading-unit->heading)<50 && owner->updir.dot(UpVector)>0.995){ am->dontCheckCol=false; am->dontLand=true; std::vector<int> args; args.push_back((int)(unit->model->height*65536)); owner->cob->Call("BeginTransport",args); std::vector<int> args2; args2.push_back(0); args2.push_back((int)(unit->model->height*65536)); owner->cob->Call("QueryTransport",args2); ((CTransportUnit*)owner)->AttachUnit(unit,args2[0]); am->SetWantedAltitude(0); FinishCommand(); return; } } else { inCommand=true; scriptReady=false; StopMove(); std::vector<int> args; args.push_back(unit->id); owner->cob->Call("TransportPickup",args,ScriptCallback,this,0); } } } else { FinishCommand(); } } else if(c.params.size()==4){ //load in radius if(lastCall==gs->frameNum) //avoid infinite loops return; lastCall=gs->frameNum; float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; CUnit* unit=FindUnitToTransport(pos,radius); if(unit && ((CTransportUnit*)owner)->transportCapacityUsed < owner->unitDef->transportCapacity){ Command c2; c2.id=CMD_LOAD_UNITS; c2.params.push_back(unit->id); c2.options=c.options | INTERNAL_ORDER; commandQue.push_front(c2); inCommand=false; SlowUpdate(); return; } else { FinishCommand(); return; } } break; case CMD_UNLOAD_UNITS:{ if(lastCall==gs->frameNum) //avoid infinite loops return; lastCall=gs->frameNum; if(((CTransportUnit*)owner)->transported.empty()){ FinishCommand(); return; } float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; float3 found; bool canUnload=FindEmptySpot(pos,max(16.0f,radius),((CTransportUnit*)owner)->transported.front().unit->radius,found); if(canUnload){ Command c2; c2.id=CMD_UNLOAD_UNIT; c2.params.push_back(found.x); c2.params.push_back(found.y); c2.params.push_back(found.z); c2.options=c.options | INTERNAL_ORDER; commandQue.push_front(c2); SlowUpdate(); return; } else { FinishCommand(); } break;} case CMD_UNLOAD_UNIT: if(inCommand){ if(!owner->cob->busy) // if(scriptReady) FinishCommand(); } else { if(((CTransportUnit*)owner)->transported.empty()){ FinishCommand(); return; } float3 pos(c.params[0],c.params[1],c.params[2]); if(goalPos.distance2D(pos)>20){ SetGoal(pos,owner->pos); } if(pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9){ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){ //handle air transports differently pos.y=ground->GetHeight(pos.x,pos.z); CUnit* unit=((CTransportUnit*)owner)->transported.front().unit; float3 wantedPos=pos+UpVector*unit->model->height; SetGoal(wantedPos,owner->pos); am->SetWantedAltitude(unit->model->height); am->maxDrift=1; if(owner->pos.distance(wantedPos)<8 && owner->updir.dot(UpVector)>0.99){ am->dontLand=false; owner->cob->Call("EndTransport"); ((CTransportUnit*)owner)->DetachUnit(unit); float3 fix = owner->pos+owner->frontdir*20; SetGoal(fix,owner->pos); //move the transport away slightly FinishCommand(); } } else { inCommand=true; scriptReady=false; StopMove(); std::vector<int> args; args.push_back(((CTransportUnit*)owner)->transported.front().unit->id); args.push_back(PACKXZ(pos.x, pos.z)); owner->cob->Call("TransportDrop",args,ScriptCallback,this,0); } } } break; default: CMobileCAI::SlowUpdate(); break; } }
int script_get(int type, int v1, int v2) { switch(type) { case VETERAN_LEVEL: return 0; case MIN_ID: return 0; case MAX_ID: return 254; case MY_ID: return 0; case UNIT_TEAM: // returns team(player ID in TA) of unit given with parameter return 0; case UNIT_BUILD_PERCENT_LEFT: // basically BUILD_PERCENT_LEFT, but comes with a unit parameter return 0; case UNIT_ALLIED: // is unit given with parameter allied to the unit of the current COB script. 0=not allied, not zero allied return 1; case UNIT_IS_ON_THIS_COMP: // indicates if the 1st parameter(a unit ID) is local to this computer return 1; case BUILD_PERCENT_LEFT: return 0; case ACTIVATION: case STANDINGMOVEORDERS: case STANDINGFIREORDERS: case HEALTH: case INBUILDSTANCE: case BUSY: case YARD_OPEN: case BUGGER_OFF: case ARMORED: return 0;//(int)port[type]; case PIECE_XZ: { Vec P = Mesh::instance()->getRelativePosition(v1); return PACKXZ(P.x * 2.0f, P.z * 2.0f); } case PIECE_Y: { Vec P = Mesh::instance()->getRelativePosition(v1); return (int)(P.y * 2.0f) << 16; } case UNIT_XZ: return PACKXZ( 0.0f, 0.0f ); case UNIT_Y: return (int)(0.0f) << 16; case UNIT_HEIGHT: return 0;//(int)(model->top * 2.0f) << 16; case XZ_ATAN: return (int)(atan2f( UNPACKX(v1) , UNPACKZ(v1) ) * RAD2TA) + 32768; case XZ_HYPOT: return (int)hypotf( UNPACKX(v1), UNPACKZ(v1) ) << 16; case ATAN: return (int)(atan2f(v1,v2) * RAD2TA ); case HYPOT: return (int)hypotf(v1,v2); case GROUND_HEIGHT: return 0; default: LOG_DEBUG(LOG_PREFIX_SCRIPT << "GET unknown constant " << type); } return 0; }
int CCobInstance::GetUnitVal(int val, int p1, int p2, int p3, int p4) { #ifndef _CONSOLE switch(val) { case ACTIVATION: if (unit->activated) return 1; else return 0; break; case STANDINGMOVEORDERS: break; case STANDINGFIREORDERS: break; case HEALTH: return (int) ((unit->health/unit->maxHealth)*100.0f); case INBUILDSTANCE: if (unit->inBuildStance) return 1; else return 0; case BUSY: if (busy) return 1; else return 0; break; case PIECE_XZ:{ if (!unit->localmodel->PieceExists(p1)) GCobEngine.ShowScriptError("Invalid piecenumber for get piece_xz"); float3 relPos = unit->localmodel->GetPiecePos(p1); float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; return PACKXZ(pos.x, pos.z);} case PIECE_Y:{ if (!unit->localmodel->PieceExists(p1)) GCobEngine.ShowScriptError("Invalid piecenumber for get piece_y"); float3 relPos = unit->localmodel->GetPiecePos(p1); float3 pos = unit->pos + unit->frontdir * relPos.z + unit->updir * relPos.y + unit->rightdir * relPos.x; return (int)(pos.y * SCALE);} case UNIT_XZ: { if (p1 == 0) return PACKXZ(unit->pos.x, unit->pos.z); CUnit *u = (p1 < MAX_UNITS) ? uh->units[p1] : NULL; if (u == NULL) return PACKXZ(0,0); else return PACKXZ(u->pos.x, u->pos.z);} case UNIT_Y: { //logOutput.Print("Unit-y %d", p1); if (p1 == 0) return (int)(unit->pos.y * SCALE); CUnit *u = (p1 < MAX_UNITS) ? uh->units[p1] : NULL; if (u == NULL) return 0; else return (int)(u->pos.y * SCALE);} case UNIT_HEIGHT:{ if (p1 == 0) return (int)(unit->radius * SCALE); CUnit *u = (p1 < MAX_UNITS) ? uh->units[p1] : NULL; if (u == NULL) return 0; else return (int)(u->radius * SCALE);} case XZ_ATAN: return (int)(TAANG2RAD*atan2((float)UNPACKX(p1), (float)UNPACKZ(p1)) + 32768 - unit->heading); case XZ_HYPOT: return (int)(hypot((float)UNPACKX(p1), (float)UNPACKZ(p1)) * SCALE); case ATAN: return (int)(TAANG2RAD*atan2((float)p1, (float)p2)); case HYPOT: return (int)hypot((float)p1, (float)p2); case GROUND_HEIGHT: return (int)(ground->GetHeight(UNPACKX(p1), UNPACKZ(p1)) * SCALE); case BUILD_PERCENT_LEFT: return (int)((1 - unit->buildProgress) * 100); case YARD_OPEN: if (yardOpen) return 1; else return 0; case BUGGER_OFF: break; case ARMORED: if (unit->armoredState) return 1; else return 0; default: logOutput.Print("CobError: Unknown get constant %d", val); case VETERAN_LEVEL: return (int)(100*unit->experience); case CURRENT_SPEED: if (unit->moveType) return (int)(unit->speed.Length()*SCALE); return 0; case ON_ROAD: return 0; case IN_WATER: return (unit->pos.y < 0.0f) ? 1 : 0; case MAX_ID: return MAX_UNITS-1; case MY_ID: return unit->id; case UNIT_TEAM:{ CUnit *u = (p1 >= 0 && p1 < MAX_UNITS) ? uh->units[p1] : NULL; return u ? unit->team : 0; } case UNIT_ALLIED:{ CUnit *u = (p1 >= 0 && p1 < MAX_UNITS) ? uh->units[p1] : NULL; if (u) return gs->Ally (unit->allyteam, u->allyteam) ? 1 : 0; return 0;} case UNIT_BUILD_PERCENT_LEFT:{ CUnit *u = (p1 >= 0 && p1 < MAX_UNITS) ? uh->units[p1] : NULL; if (u) return (int)((1 - u->buildProgress) * 100); return 0;} case MAX_SPEED: if(unit->moveType){ return int(unit->moveType->maxSpeed*SCALE); } break; } #endif return 0; }
void CTransportCAI::ExecuteUnloadUnit(Command &c) { CTransportUnit* transport = (CTransportUnit*)owner; if (inCommand) { if (!owner->cob->busy) { // if(scriptReady) FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transList = transport->transported; if (transList.empty()) { FinishCommand(); return; } float3 pos(c.params[0], c.params[1], c.params[2]); if(goalPos.distance2D(pos) > 20){ SetGoal(pos, owner->pos); } CUnit* unit = NULL; if (c.params.size() < 4) { unit = transList.front().unit; } else { const int unitID = (int)c.params[3]; std::list<CTransportUnit::TransportedUnit>::const_iterator it; for (it = transList.begin(); it != transList.end(); ++it) { CUnit* carried = it->unit; if (unitID == carried->id) { unit = carried; break; } } if (unit == NULL) { FinishCommand(); return; } } if (pos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) { CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType); if (am != NULL) { // handle air transports differently pos.y = ground->GetHeight(pos.x, pos.z); const float3 wantedPos = pos + UpVector * unit->model->height; SetGoal(wantedPos, owner->pos); am->SetWantedAltitude(unit->model->height); am->maxDrift = 1; if ((owner->pos.distance(wantedPos) < 8) && (owner->updir.dot(UpVector) > 0.99f)) { am->dontLand = false; owner->cob->Call("EndTransport"); transport->DetachUnit(unit); const float3 fix = owner->pos + owner->frontdir * 20; SetGoal(fix, owner->pos); //move the transport away slightly FinishCommand(); } } else { inCommand = true; scriptReady = false; StopMove(); std::vector<int> args; args.push_back(transList.front().unit->id); args.push_back(PACKXZ(pos.x, pos.z)); owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); } } } return; }
void CTransportCAI::UnloadLandFlood(Command& c) { //land, then release all units at once CTransportUnit* transport = (CTransportUnit*)owner; if (inCommand) { if (!owner->cob->busy) { //if(scriptReady) FinishCommand(); } } else { const std::list<CTransportUnit::TransportedUnit>& transList = transport->transported; if (transList.empty()) { FinishCommand(); return; } //check units are all carried CUnit* unit = NULL; if (c.params.size() < 4) { unit = transList.front().unit; } else { const int unitID = (int)c.params[3]; std::list<CTransportUnit::TransportedUnit>::const_iterator it; for (it = transList.begin(); it != transList.end(); ++it) { CUnit* carried = it->unit; if (unitID == carried->id) { unit = carried; break; } } if (unit == NULL) { FinishCommand(); return; } } //move to position float3 pos(c.params[0], c.params[1], c.params[2]); if (isFirstIteration) { if(goalPos.distance2D(pos) > 20) SetGoal(startingDropPos, owner->pos); } if (startingDropPos.distance2D(owner->pos) < (owner->unitDef->loadingRadius * 0.9f)) { //create aircraft movetype instance CTAAirMoveType* am = dynamic_cast<CTAAirMoveType*>(owner->moveType); if (am != NULL) { //lower to ground startingDropPos.y = ground->GetHeight(startingDropPos.x,startingDropPos.z); const float3 wantedPos = startingDropPos + UpVector * unit->model->height; SetGoal(wantedPos, owner->pos); am->SetWantedAltitude(1); am->maxDrift = 1; am->dontLand = false; //when on our way down start animations for unloading gear if (isFirstIteration) { owner->cob->Call("StartUnload"); } isFirstIteration = false; //once at ground if (owner->pos.y - ground->GetHeight(wantedPos.x,wantedPos.z) < 8) { am->SetState(am->AIRCRAFT_LANDED);//nail it to the ground before it tries jumping up, only to land again... std::vector<int> args; args.push_back(transList.front().unit->id); args.push_back(PACKXZ(pos.x, pos.z)); owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); //call this so that other animations such as opening doors may be started transport->DetachUnitFromAir(unit,pos); FinishCommand(); if (transport->transported.empty()) { am->dontLand = false; owner->cob->Call("EndTransport"); am->UpdateLanded(); } } } else { //land transports inCommand = true; scriptReady = false; StopMove(); std::vector<int> args; args.push_back(transList.front().unit->id); args.push_back(PACKXZ(pos.x, pos.z)); owner->cob->Call("TransportDrop", args, ScriptCallback, this, 0); transport->DetachUnitFromAir(unit,pos); isFirstIteration = false; FinishCommand(); if (transport->transported.empty()) owner->cob->Call("EndTransport"); } } } return; }