// Get values from a group bool scrGroupObjGet(UDWORD index) { INTERP_TYPE type; DROID_GROUP *psGroup; DROID *psCurr; if (!stackPopParams(1, ST_GROUP, &psGroup)) { return false; } switch (index) { case GROUPID_POSX: lgX = 0; lgMembers = 0; for(psCurr = psGroup->psList; psCurr; psCurr = psCurr->psGrpNext) { lgMembers += 1; lgX += (SDWORD)psCurr->pos.x; } if (lgMembers > 0) { lgX = lgX / lgMembers; } type = VAL_INT; scrFunctionResult.v.ival = lgX; break; case GROUPID_POSY: lgY = 0; lgMembers = 0; for(psCurr = psGroup->psList; psCurr; psCurr = psCurr->psGrpNext) { lgMembers += 1; lgY += (SDWORD)psCurr->pos.y; } if (lgMembers > 0) { lgY = lgY / lgMembers; } type = VAL_INT; scrFunctionResult.v.ival = lgY; break; case GROUPID_MEMBERS: lgMembers = 0; for(psCurr = psGroup->psList; psCurr; psCurr = psCurr->psGrpNext) { lgMembers += 1; } type = VAL_INT; scrFunctionResult.v.ival = lgMembers; break; case GROUPID_HEALTH: lgHealth = 0; lgMembers = 0; for(psCurr = psGroup->psList; psCurr; psCurr = psCurr->psGrpNext) { lgMembers += 1; lgHealth += (SDWORD)((100 * psCurr->body)/psCurr->originalBody); } if (lgMembers > 0) { lgHealth = lgHealth / lgMembers; } type = VAL_INT; scrFunctionResult.v.ival = lgHealth; break; case GROUPID_TYPE: type = VAL_INT; scrFunctionResult.v.ival = psGroup->type; break; case GROUPID_CMD: type = (INTERP_TYPE)ST_DROID; scrFunctionResult.v.oval = psGroup->psCommander; break; default: ASSERT( false, "scrGroupObjGet: unknown variable index" ); return false; break; } // Return the value if (!stackPushResult(type, &scrFunctionResult)) { return false; } return true; }
// Get values from a base object bool scrBaseObjGet(UDWORD index) { INTERP_TYPE type = VAL_VOID; BASE_OBJECT *psObj; DROID *psDroid; STRUCTURE *psStruct; FEATURE *psFeature; if (!stackPopParams(1, ST_BASEOBJECT, &psObj)) { debug(LOG_ERROR, "scrBaseObjGet: stackPopParams failed"); return false; } // Check this is a valid pointer ASSERT_OR_RETURN(false, psObj, "Passed a NULL pointer to a base object"); ASSERT_OR_RETURN(false, psObj->type == OBJ_DROID || psObj->type == OBJ_STRUCTURE || psObj->type == OBJ_FEATURE, "Invalid object %p of type %d", psObj, psObj->type); // set the type and return value switch (index) { case OBJID_POSX: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->pos.x; break; case OBJID_POSY: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->pos.y; break; case OBJID_POSZ: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->pos.z; break; case OBJID_ID: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->id; break; case OBJID_PLAYER: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->player; break; case OBJID_TYPE: type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)psObj->type; break; case OBJID_ORDER: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid"); return false; } type = VAL_INT; scrFunctionResult.v.ival = ((DROID *)psObj)->order.type; if (scrFunctionResult.v.ival == DORDER_GUARD && ((DROID *)psObj)->order.psObj == NULL) { scrFunctionResult.v.ival = DORDER_NONE; } break; //new member variable case OBJID_ACTION: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: action only valid for a droid"); return false; } type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->action; break; //new member variable - if droid is selected (humans only) case OBJID_SELECTED: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: selected only valid for a droid"); return false; } type = VAL_BOOL; scrFunctionResult.v.bval = (SDWORD)((DROID *)psObj)->selected; break; case OBJID_STRUCTSTATTYPE: if (psObj->type == OBJ_STRUCTURE) { type = VAL_INT; scrFunctionResult.v.ival = ((STRUCTURE *)psObj)->pStructureType->type; } else { debug(LOG_ERROR, ".stattype is only supported by Structures"); return false; } break; case OBJID_ORDERX: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid"); return false; } type = VAL_INT; scrFunctionResult.v.ival = ((DROID *)psObj)->order.pos.x; break; case OBJID_ORDERY: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: order only valid for a droid"); return false; } type = VAL_INT; scrFunctionResult.v.ival = ((DROID *)psObj)->order.pos.y; break; case OBJID_DROIDTYPE: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: droidType only valid for a droid"); return false; } type = VAL_INT; scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->droidType; break; case OBJID_CLUSTERID: if (psObj->type == OBJ_FEATURE) { debug(LOG_ERROR, "scrBaseObjGet: clusterID not valid for features"); return false; } type = VAL_INT; scrFunctionResult.v.ival = clustGetClusterID(psObj); break; case OBJID_HEALTH: switch (psObj->type) { case OBJ_DROID: psDroid = (DROID *)psObj; type = VAL_INT; scrFunctionResult.v.ival = psDroid->body * 100 / psDroid->originalBody; break; case OBJ_FEATURE: psFeature = (FEATURE *)psObj; type = VAL_INT; if (psFeature->psStats->damageable) { scrFunctionResult.v.ival = psFeature->body * 100 / psFeature->psStats->body; } else { scrFunctionResult.v.ival = 100; } break; case OBJ_STRUCTURE: psStruct = (STRUCTURE *)psObj; type = VAL_INT; //val = psStruct->body * 100 / psStruct->baseBodyPoints; scrFunctionResult.v.ival = psStruct->body * 100 / structureBody(psStruct); break; default: break; } break; case OBJID_BODY: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: body only valid for a droid"); return false; } type = (INTERP_TYPE)ST_BODY; scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asBits[COMP_BODY].nStat; break; case OBJID_PROPULSION: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: propulsion only valid for a droid"); return false; } type = (INTERP_TYPE)ST_PROPULSION; scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asBits[COMP_PROPULSION].nStat; break; case OBJID_WEAPON: //TODO: only returns first weapon now type = (INTERP_TYPE)ST_WEAPON; switch (psObj->type) { case OBJ_DROID: if (((DROID *)psObj)->asWeaps[0].nStat == 0) { scrFunctionResult.v.ival = 0; }else{ scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->asWeaps[0].nStat; } break; case OBJ_STRUCTURE: if (((STRUCTURE *)psObj)->numWeaps == 0 || ((STRUCTURE *)psObj)->asWeaps[0].nStat == 0) { scrFunctionResult.v.ival = 0; }else{ scrFunctionResult.v.ival = (SDWORD)((STRUCTURE *)psObj)->asWeaps[0].nStat; } break; default: //only droids and structures can have a weapon debug(LOG_ERROR, "scrBaseObjGet: weapon only valid for droids and structures" ); return false; break; } break; case OBJID_STRUCTSTAT: //droid.stat - now returns the type of structure a truck is building for droids if (psObj->type == OBJ_STRUCTURE) { type = (INTERP_TYPE)ST_STRUCTURESTAT; scrFunctionResult.v.ival = ((STRUCTURE *)psObj)->pStructureType - asStructureStats; } else if (psObj->type == OBJ_DROID) { type = (INTERP_TYPE)ST_STRUCTURESTAT; scrFunctionResult.v.ival = ((DROID *)psObj)->order.psStats - asStructureStats; } else //Nothing else supported { debug(LOG_ERROR, "scrBaseObjGet(): .stat only valid for structures and droids"); return false; } break; case OBJID_TARGET: //added object->psTarget if (psObj->type == OBJ_STRUCTURE) { type = (INTERP_TYPE)ST_BASEOBJECT; scrFunctionResult.v.oval = ((STRUCTURE *)psObj)->psTarget[0]; } else if (psObj->type == OBJ_DROID) { type = (INTERP_TYPE)ST_BASEOBJECT; scrFunctionResult.v.oval = ((DROID *)psObj)->order.psObj; } else //Nothing else supported { debug(LOG_ERROR, "scrBaseObjGet(): .target only valid for structures and droids"); return false; } break; case OBJID_GROUP: if (psObj->type != OBJ_DROID) { debug(LOG_ERROR, "scrBaseObjGet: group only valid for a droid"); return false; } type = (INTERP_TYPE)ST_GROUP; scrFunctionResult.v.oval = ((DROID *)psObj)->psGroup; break; case OBJID_HITPOINTS: type = VAL_INT; switch (psObj->type) { case OBJ_DROID: scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->body; break; case OBJ_STRUCTURE: scrFunctionResult.v.ival = (SDWORD)((STRUCTURE *)psObj)->body; break; case OBJ_FEATURE: scrFunctionResult.v.ival = (SDWORD)((FEATURE *)psObj)->body; break; default: debug(LOG_ERROR, "scrBaseObjGet: unknown object type"); return false; break; } break; case OBJID_ORIG_HITPOINTS: type = VAL_INT; switch (psObj->type) { case OBJ_DROID: scrFunctionResult.v.ival = (SDWORD)((DROID *)psObj)->originalBody; break; case OBJ_STRUCTURE: scrFunctionResult.v.ival = (SDWORD)structureBody((STRUCTURE *)psObj); break; case OBJ_FEATURE: scrFunctionResult.v.ival = ((FEATURE *)psObj)->psStats->body; break; default: debug(LOG_ERROR, "scrBaseObjGet: unknown object type"); return false; break; } break; default: debug(LOG_ERROR, "scrBaseObjGet: unknown variable index"); return false; break; } // Return the value if (!stackPushResult(type, &scrFunctionResult)) { debug(LOG_ERROR, "scrBaseObjGet: stackPushResult() failed"); return false; } return true; }
// General function to get some basic game values BOOL scrGenExternGet(UDWORD index) { INTERP_TYPE type; SDWORD val; switch (index) { case EXTID_TRACKTRANSPORTER: type = VAL_BOOL; val = bTrackTransporter; break; case EXTID_ISPSX: type = VAL_BOOL; val = bIsPSX; break; case EXTID_MAPWIDTH: type = VAL_INT; val = mapWidth; break; case EXTID_MAPHEIGHT: type = VAL_INT; val = mapHeight; break; case EXTID_GAMEINIT: type = VAL_BOOL; val = gameInitialised; break; case EXTID_SELECTEDPLAYER: type = VAL_INT; val = selectedPlayer; break; case EXTID_GAMELEVEL: type = VAL_INT; val = scrGameLevel; break; case EXTID_GAMETIME: type = VAL_INT; val = (SDWORD)(gameTime/SCR_TICKRATE); break; case EXTID_TUTORIAL: type = VAL_BOOL; val = bInTutorial; break; case EXTID_CURSOR: type = VAL_INT; val = iV_GetMouseFrame(); // from rendfunc.c // DBPRINTF(("CURSOR = %d val\n",val)); break; case EXTID_INTMODE: type=VAL_INT; val=intMode; break; case EXTID_TARGETTYPE: type=VAL_INT; val=getTargetType(); break; case EXTID_EXTRAVICTORYFLAG: type=VAL_BOOL; val=bExtraVictoryFlag; break; case EXTID_EXTRAFAILFLAG: type=VAL_BOOL; val=bExtraFailFlag; break; case EXTID_MULTIGAMETYPE: // multiplayer variable.. type = VAL_INT; val = game.type; break; case EXTID_MULTIGAMEHUMANMAX: // multiplayer variable.. type = VAL_INT; val = game.maxPlayers; break; case EXTID_MULTIGAMEBASETYPE: type = VAL_INT; val = game.base; break; default: ASSERT((FALSE, "scrGenExternGet: unknown variable index")); return FALSE; break; } if (!stackPushResult(type, val)) { return FALSE; } return TRUE; }
BOOL scrSkDefenseLocation(void) { SDWORD *pX,*pY,statIndex,statIndex2; UDWORD x,y,gX,gY,dist,player,nearestSoFar,count; GATEWAY *psGate,*psChosenGate; DROID *psDroid; BASE_STATS *psStats,*psWStats; UDWORD x1,x2,x3,x4,y1,y2,y3,y4; BOOL noWater; if (!stackPopParams(6, VAL_REF|VAL_INT, &pX, VAL_REF|VAL_INT, &pY, ST_STRUCTURESTAT, &statIndex, ST_STRUCTURESTAT, &statIndex2, ST_DROID, &psDroid, VAL_INT, &player) ) { return FALSE; } if (player >= MAX_PLAYERS) { ASSERT((FALSE, "scrSkDefenseLocation:player number is too high")); return FALSE; } psStats = (BASE_STATS *)(asStructureStats + statIndex); psWStats = (BASE_STATS *)(asStructureStats + statIndex2); // check for wacky coords. if( *pX < 0 || *pX > (SDWORD)(mapWidth<<TILE_SHIFT) || *pY < 0 || *pY > (SDWORD)(mapHeight<<TILE_SHIFT) ) { goto failed; } x = *pX >> TILE_SHIFT; // change to tile coords. y = *pY >> TILE_SHIFT; // go down the gateways, find the nearest gateway with >1 empty tiles nearestSoFar = UDWORD_MAX; psChosenGate = NULL; for(psGate= psGateways; psGate; psGate= psGate->psNext) { count = 0; noWater = TRUE; // does it have >1 tile unoccupied. if(psGate->x1 == psGate->x2) {// vert gX = psGate->x1; for(gY=psGate->y1;gY <= psGate->y2; gY++) { if(! TILE_OCCUPIED(mapTile(gX,gY) )) { count++; } if(TERRAIN_TYPE(mapTile(gX,gY)) == TER_WATER) { noWater = FALSE; } } } else {// horiz gY = psGate->y1; for(gX=psGate->x1;gX <= psGate->x2; gX++) { if(! TILE_OCCUPIED(mapTile(gX,gY) )) { count++; } if(TERRAIN_TYPE(mapTile(gX,gY)) == TER_WATER) { noWater = FALSE; } } } if(count > 1 && noWater) { // ok it's free. Is it the nearest one yet? /* Get gateway midpoint */ gX = (psGate->x1 + psGate->x2)/2; gY = (psGate->y1 + psGate->y2)/2; /* Estimate the distance to it */ dist = dirtySqrt(x,y,gX,gY); /* Is it best we've found? */ if(dist<nearestSoFar && dist<30) { /* Yes, then keep a record of it */ nearestSoFar = dist; psChosenGate = psGate; } } } if(!psChosenGate) // we have a gateway. { goto failed; } // find an unnocupied tile on that gateway. if(psChosenGate->x1 == psChosenGate->x2) {// vert gX = psChosenGate->x1; for(gY=psChosenGate->y1;gY <= psChosenGate->y2; gY++) { if(! TILE_OCCUPIED(mapTile(gX,gY) )) { y = gY; x = gX; break; } } } else {// horiz gY = psChosenGate->y1; for(gX=psChosenGate->x1;gX <= psChosenGate->x2; gX++) { if(! TILE_OCCUPIED(mapTile(gX,gY) )) { y = gY; x = gX; break; } } } // back to world coords and store result. *pX = (x << TILE_SHIFT) + (TILE_UNITS/2); // return centre of tile. *pY = (y << TILE_SHIFT) + (TILE_UNITS/2); if (!stackPushResult(VAL_BOOL,TRUE)) // success { return FALSE; } // order the droid to build two walls, one either side of the gateway. // or one in the case of a 2 size gateway. x = (psChosenGate->x1 + psChosenGate->x2)/2; y = (psChosenGate->y1 + psChosenGate->y2)/2; x1 = (psChosenGate->x1 << TILE_SHIFT) + (TILE_UNITS/2); y1 = (psChosenGate->y1 << TILE_SHIFT) + (TILE_UNITS/2); if(psChosenGate->x1 == psChosenGate->x2) { x2 = x1; y2 = ((y-1) << TILE_SHIFT) + (TILE_UNITS/2); x3 = x1; y3 = ((y+1) << TILE_SHIFT) + (TILE_UNITS/2); } else { x2 = ((x-1) << TILE_SHIFT) + (TILE_UNITS/2); y2 = y1; x3 = ((x+1) << TILE_SHIFT) + (TILE_UNITS/2); y3 = y1; } x4 = (psChosenGate->x2 << TILE_SHIFT) + (TILE_UNITS/2); y4 = (psChosenGate->y2 << TILE_SHIFT) + (TILE_UNITS/2); // first section. if(x1 == x2 && y1 == y2) { orderDroidStatsLoc(psDroid, DORDER_BUILD, psWStats, x1, y1); } else { orderDroidStatsTwoLoc(psDroid, DORDER_LINEBUILD, psWStats, x1, y1,x2,y2); } // second section if(x3 == x4 && y3 == y4) { orderDroidStatsLocAdd(psDroid, DORDER_BUILD, psWStats, x3, y3); } else { orderDroidStatsTwoLocAdd(psDroid, DORDER_LINEBUILD, psWStats, x3, y3,x4,y4); } return TRUE; failed: if (!stackPushResult(VAL_BOOL,FALSE)) // failed! { return FALSE; } return TRUE; }
BOOL scrSkCanBuildTemplate(void) { STRUCTURE *psStructure; DROID_TEMPLATE *psTempl; SDWORD player, structure, templ; if (!stackPopParams(3,VAL_INT, &player,ST_STRUCTURE, &structure, ST_TEMPLATE, &templ)) { return FALSE; } psTempl = (DROID_TEMPLATE*) templ; psStructure = (STRUCTURE *) structure; // is factory big enough? if(!validTemplateForFactory(psTempl, psStructure) ) { goto failTempl; } if ((asBodyStats + psTempl->asParts[COMP_BODY])->size > ((FACTORY*)psStructure->pFunctionality)->capacity ) { goto failTempl; } // is every component from template available? // body available. if( apCompLists[player][COMP_BODY][psTempl->asParts[COMP_BODY]] != AVAILABLE ) { goto failTempl; } // propulsion method available. if( apCompLists[player][COMP_PROPULSION][psTempl->asParts[COMP_PROPULSION]] != AVAILABLE ) { goto failTempl; } // weapon/sensor switch (droidTemplateType(psTempl)) { case DROID_CYBORG: // cyborg-type thang.. no need to check weapon. case DROID_CYBORG_SUPER: // super cyborg-type thang break; case DROID_WEAPON: if( apCompLists[player][COMP_WEAPON][ psTempl->asWeaps[0] ] != AVAILABLE ) { goto failTempl; } break; case DROID_SENSOR: if( apCompLists[player][COMP_SENSOR][psTempl->asParts[COMP_SENSOR]] != AVAILABLE ) { goto failTempl; } break; case DROID_ECM: if( apCompLists[player][COMP_ECM][psTempl->asParts[COMP_ECM]] != AVAILABLE ) { goto failTempl; } break; case DROID_REPAIR: if( apCompLists[player][COMP_REPAIRUNIT][psTempl->asParts[COMP_REPAIRUNIT]] != AVAILABLE ) { goto failTempl; } break; case DROID_COMMAND: case DROID_CONSTRUCT: // Constructor droid case DROID_PERSON: // person case DROID_CYBORG_CONSTRUCT: // cyborg-construct thang case DROID_CYBORG_REPAIR: // cyborg-repair thang case DROID_TRANSPORTER: // guess what this is! case DROID_DEFAULT: // Default droid case DROID_ANY: default: DBERROR(("scrSkCanBuildTemplate: Unhandled template type")); break; } if (!stackPushResult(VAL_BOOL, TRUE)) // yes { return FALSE; } return TRUE; failTempl: if (!stackPushResult(VAL_BOOL, FALSE)) // no { return FALSE; } return TRUE; }
// Get values from a weapon bool scrWeaponObjGet(UDWORD index) { INTERP_TYPE type; SDWORD weapIndex; if (!stackPopParams(1, ST_WEAPON, &weapIndex)) { return false; } switch (index) { case WEAPID_SHORT_RANGE: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].shortRange; break; case WEAPID_LONG_RANGE: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].longRange; break; case WEAPID_SHORT_HIT: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].shortHit; break; case WEAPID_LONG_HIT: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].longHit; break; case WEAPID_DAMAGE: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].damage; break; case WEAPID_FIRE_PAUSE: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].firePause; break; case WEAPID_RELOAD_TIME: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].reloadTime; break; case WEAPID_NUM_ROUNDS: type = VAL_INT; scrFunctionResult.v.ival = asWeaponStats[weapIndex].numRounds; break; default: ASSERT( false, "unknown variable index" ); return false; break; } // Return the value if (!stackPushResult(type, &scrFunctionResult)) { return false; } return true; }
//multiplayer beacon //--------------------------- bool scrCallBeacon(void) { SDWORD *playerFrom, playerTo; char **BeaconText = NULL; SDWORD *locX, *locY; if (!stackPopParams(5, VAL_INT, &playerTo, VAL_REF | VAL_INT, &playerFrom, VAL_REF | VAL_INT, &locX, VAL_REF | VAL_INT, &locY, VAL_REF | VAL_STRING, &BeaconText)) { debug(LOG_ERROR, "scrCallBeacon() - failed to pop parameters."); return false; } debug(LOG_SCRIPT, "scrCallBeacon: to: %d (%d), text: %s ", playerTo, MultiMsgPlayerTo, *BeaconText); if (*BeaconText == NULL) { debug(LOG_ERROR, "scrCallBeacon(): passed string was not initialized"); return false; } if (MultiMsgPlayerTo >= 0 && MultiMsgPlayerFrom >= 0 && MultiMsgPlayerTo < MAX_PLAYERS && MultiMsgPlayerFrom < MAX_PLAYERS) { if (MultiMsgPlayerTo == playerTo) { strcpy(*BeaconText, MultiplayMsg); *playerFrom = MultiMsgPlayerFrom; *locX = beaconX; *locY = beaconY; scrFunctionResult.v.bval = true; if (!stackPushResult(VAL_BOOL, &scrFunctionResult)) //triggered { debug(LOG_ERROR, "scrCallBeacon - failed to push"); return false; } return true; } } else { debug(LOG_ERROR, "scrCallBeacon() - player indexes failed: %d - %d", MultiMsgPlayerFrom, MultiMsgPlayerTo); scrFunctionResult.v.bval = false; if (!stackPushResult(VAL_BOOL, &scrFunctionResult)) //not triggered { return false; } return true; } //return "not triggered" scrFunctionResult.v.bval = false; if (!stackPushResult(VAL_BOOL, &scrFunctionResult)) { return false; } return true; }