/** * Shake the screen. * @param e The Explosion. * @param parameter Unused parameter. */ static void Explosion_Func_ScreenShake(Explosion *e, uint16 parameter) { int i; #ifdef _DEBUG Debug("Explosion_Func_ScreenShake(%p, %d)\n", e, parameter); #else VARIABLE_NOT_USED(e); VARIABLE_NOT_USED(parameter); #endif for(i = 0; i < 2; i++) { #if defined(_WIN32) msleep(30); #else sleepIdle(); sleepIdle(); #endif Video_SetOffset(320); #if defined(_WIN32) msleep(30); #else sleepIdle(); sleepIdle(); #endif Video_SetOffset(0); } }
/** * Shake the screen. * @param e The Explosion. * @param parameter Unused parameter. */ static void Explosion_Func_ScreenShake(Explosion *e, uint16 parameter) { VARIABLE_NOT_USED(e); VARIABLE_NOT_USED(parameter); /* TODO -- Implement this function */ }
int main(int argc, char **argv) #endif /* __APPLE__ */ { bool commit_dune_cfg = false; #if defined(_WIN32) #if defined(__MINGW32__) && defined(__STRICT_ANSI__) int __cdecl __MINGW_NOTHROW _fileno (FILE*); #endif FILE *err = fopen("error.log", "w"); FILE *out = fopen("output.log", "w"); #if defined(_MSC_VER) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif if (err != NULL) _dup2(_fileno(err), _fileno(stderr)); if (out != NULL) _dup2(_fileno(out), _fileno(stdout)); FreeConsole(); #endif CrashLog_Init(); VARIABLE_NOT_USED(argc); VARIABLE_NOT_USED(argv); if (!File_Init()) { Error("Cannot initialise files. Does %s directory exist ?\n", DATA_DIR); exit(1); } /* Loading / writing config from/to dune.cfg */ if (!Config_Read("dune.cfg", &g_config)) { Config_Default(&g_config); commit_dune_cfg = true; } if (commit_dune_cfg && !Config_Write("dune.cfg", &g_config)) { Error("Error writing to dune.cfg file.\n"); exit(1); } Input_Init(); Drivers_All_Init(); if (!Unknown_25C4_000E()) exit(1); g_var_7097 = 0; GameLoop_Main(); printf("%s\n", String_Get_ByIndex(STR_THANK_YOU_FOR_PLAYING_DUNE_II)); PrepareEnd(); exit(0); }
/** * Handle clicks on the Mentat widget. * @return True, always. */ bool GUI_Widget_Mentat_Click(Widget *w) { VARIABLE_NOT_USED(w); g_cursorSpriteID = 0; Sprites_SetMouseSprite(0, 0, g_sprites[0]); Sound_Output_Feedback(0xFFFE); Driver_Voice_Play(NULL, 0xFF); Music_Play(g_table_houseInfo[g_playerHouseID].musicBriefing); Sprites_UnloadTiles(); Timer_SetTimer(TIMER_GAME, false); GUI_Mentat_ShowHelpList(false); Timer_SetTimer(TIMER_GAME, true); Driver_Sound_Play(1, 0xFF); Sprites_LoadTiles(); g_textDisplayNeedsUpdate = true; GUI_DrawInterfaceAndRadar(SCREEN_0); Music_Play(Tools_RandomLCG_Range(0, 5) + 8); return true; }
/** * Gets the best target for the current team. * * Stack: *none*. * * @param script The script engine to operate on. * @return The encoded index of the best target or 0 if none found. */ uint16 Script_Team_FindBestTarget(ScriptEngine *script) { Team *t; PoolFindStruct find; VARIABLE_NOT_USED(script); t = g_scriptCurrentTeam; find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; uint16 target; u = Unit_Find(&find); if (u == NULL) break; if (u->team - 1 != t->index) continue; target = Unit_FindBestTargetEncoded(u, t->action == TEAM_ACTION_KAMIKAZE ? 4 : 0); if (target == 0) continue; if (t->target == target) return target; t->target = target; t->targetTile = Tile_GetTileInDirectionOf(Tile_PackTile(u->o.position), Tools_Index_GetPackedTile(target)); return target; } return 0; }
/** * Stop with this Animation. * @param animation The Animation to stop. * @param parameter Not used. */ static void Animation_Func_Stop(Animation *animation, int16 parameter) { const uint16 *layout = g_table_structure_layoutTiles[animation->tileLayout]; uint16 packed = Tile_PackTile(animation->tile); Tile *t = &g_map[packed]; int i; VARIABLE_NOT_USED(parameter); t->hasAnimation = false; animation->commands = NULL; for (i = 0; i < g_table_structure_layoutTileCount[animation->tileLayout]; i++) { uint16 position = packed + (*layout++); if (animation->tileLayout != 0) { g_map[position].groundSpriteID = g_mapSpriteID[position]; } if (Map_IsPositionUnveiled(position)) { g_map[position].overlaySpriteID = 0; } Map_Update(position, 0, false); } }
/** * Rotate the unit to aim at the enemy. * * Stack: *none*. * * @param script The script engine to operate on. * @return 0 if the enemy is no longer there or if we are looking at him, 1 otherwise. */ uint16 Script_Unit_Rotate(ScriptEngine *script) { const UnitInfo *ui; Unit *u; uint16 index; int8 current; tile32 tile; int8 orientation; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; ui = &g_table_unitInfo[u->o.type]; if (ui->movementType != MOVEMENT_WINGER && u->currentDestination.tile != 0) return 1; index = ui->o.flags.hasTurret ? 1 : 0; /* Check if we are already rotating */ if (u->orientation[index].speed != 0) return 1; current = u->orientation[index].current; if (!Tools_Index_IsValid(u->targetAttack)) return 0; /* Check where we should rotate to */ tile = Tools_Index_GetTile(u->targetAttack); orientation = Tile_GetDirection(u->o.position, tile); /* If we aren't already looking at it, rotate */ if (orientation == current) return 0; Unit_SetOrientation(u, orientation, false, index); return 1; }
/** * 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; }
/** * Unknown function 2BD5. * * Stack: *none*. * * @param script The script engine to operate on. * @return ??. */ uint16 Script_Unit_Unknown2BD5(ScriptEngine *script) { Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; switch (Tools_Index_GetType(u->o.script.variables[4])) { case IT_UNIT: { Unit *u2; u2 = Tools_Index_GetUnit(u->o.script.variables[4]); if (Tools_Index_Encode(u->o.index, IT_UNIT) == u2->o.script.variables[4] && u2->o.houseID == u->o.houseID) return 1; u2->targetMove = 0; } break; case IT_STRUCTURE: { Structure *s; s = Tools_Index_GetStructure(u->o.script.variables[4]); if (Tools_Index_Encode(u->o.index, IT_UNIT) == s->o.script.variables[4] && s->o.houseID == u->o.houseID) return 1; } break; default: break; } Object_Script_Variable4_Clear(&u->o); return 0; }
/** * Transform an MCV into Construction Yard. * * Stack: *none*. * * @param script The script engine to operate on. * @return 1 if and only if the transformation succeeded. */ uint16 Script_Unit_MCVDeploy(ScriptEngine *script) { Unit *u; Structure *s = NULL; uint16 i; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; Unit_UpdateMap(0, u); uint houseID = Unit_GetHouseID(u); uint tile = Tile_PackTile(u->o.position); for (i = 0; i < 4; i++) { static int8 offsets[4] = { 0, -1, -64, -65 }; s = Structure_Create(STRUCTURE_INDEX_INVALID, STRUCTURE_CONSTRUCTION_YARD, houseID, tile + offsets[i]); if (s != NULL) { Unit_Remove(u); return 1; } } if (houseID == g_playerHouseID) { GUI_DisplayText(String_Get_ByIndex(STR_UNIT_IS_UNABLE_TO_DEPLOY_HERE), 0); } Unit_UpdateMap(1, u); return 0; }
/** * Perform a random action when we are sitting idle, like rotating around. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_IdleAction(ScriptEngine *script) { Unit *u; uint16 random; uint16 movementType; uint16 i; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; random = Tools_RandomLCG_Range(0, 10); movementType = g_table_unitInfo[u->o.type].movementType; if (movementType != MOVEMENT_FOOT && movementType != MOVEMENT_TRACKED && movementType != MOVEMENT_WHEELED) return 0; if (movementType == MOVEMENT_FOOT && random > 8) { u->spriteOffset = Tools_Random_256() & 0x3F; Unit_UpdateMap(2, u); } if (random > 2) return 0; /* Ensure the order of Tools_Random_256() calls. */ i = (Tools_Random_256() & 1) == 0 ? 1 : 0; Unit_SetOrientation(u, Tools_Random_256(), false, i); return 0; }
/** * Make the current unit harvest spice. * * Stack: *none*. * * @param script The script engine to operate on. * @return ??. */ uint16 Script_Unit_Harvest(ScriptEngine *script) { Unit *u; uint16 packed; uint16 type; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; if (u->o.type != UNIT_HARVESTER) return 0; if (u->amount >= 100) return 0; packed = Tile_PackTile(u->o.position); type = Map_GetLandscapeType(packed); if (type != LST_SPICE && type != LST_THICK_SPICE) return 0; u->amount += Tools_Random_256() & 1; u->o.flags.s.inTransport = true; Unit_UpdateMap(2, u); if (u->amount > 100) u->amount = 100; if ((Tools_Random_256() & 0x1F) != 0) return 1; Map_ChangeSpiceAmount(packed, -1); return 0; }
/** * Start the animation on the current tile. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 1. Always. */ uint16 Script_Unit_StartAnimation(ScriptEngine *script) { Unit *u; uint16 animationUnitID; uint16 position; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; position = Tile_PackTile(Tile_Center(u->o.position)); Animation_Stop_ByTile(position); animationUnitID = g_table_landscapeInfo[Map_GetLandscapeType(Tile_PackTile(u->o.position))].isSand ? 0 : 1; if (u->o.script.variables[1] == 1) animationUnitID += 2; g_map[position].houseID = Unit_GetHouseID(u); assert(animationUnitID < 4); if (g_table_unitInfo[u->o.type].displayMode == 3) { Animation_Start(g_table_animation_unitScript1[animationUnitID], u->o.position, 0, Unit_GetHouseID(u), 4); } else { Animation_Start(g_table_animation_unitScript2[animationUnitID], u->o.position, 0, Unit_GetHouseID(u), 4); } return 1; }
/** * Handle damage to a tile, removing spice, removing concrete, stuff like that. * @param e The Explosion to handle damage on. * @param parameter Unused parameter. */ static void Explosion_Func_TileDamage(Explosion *e, uint16 parameter) { static const int16 craterIconMapIndex[] = { -1, 2, 1 }; uint16 packed; uint16 type; Tile *t; int16 iconMapIndex; uint16 overlaySpriteID; uint16 *iconMap; VARIABLE_NOT_USED(parameter); packed = Tile_PackTile(e->position); if (!Map_IsPositionUnveiled(packed)) return; type = Map_GetLandscapeType(packed); if (type == LST_STRUCTURE || type == LST_DESTROYED_WALL) return; t = &g_map[packed]; if (type == LST_CONCRETE_SLAB) { t->groundSpriteID = g_mapSpriteID[packed]; Map_Update(packed, 0, false); } if (g_table_landscapeInfo[type].craterType == 0) return; /* You cannot damage veiled tiles */ overlaySpriteID = t->overlaySpriteID; if (!Sprite_IsUnveiled(overlaySpriteID)) return; iconMapIndex = craterIconMapIndex[g_table_landscapeInfo[type].craterType]; iconMap = &g_iconMap[g_iconMap[iconMapIndex]]; if (iconMap[0] <= overlaySpriteID && overlaySpriteID <= iconMap[10]) { /* There already is a crater; make it bigger */ overlaySpriteID -= iconMap[0]; if (overlaySpriteID < 4) overlaySpriteID += 2; } else { /* Randomly pick 1 of the 2 possible craters */ overlaySpriteID = Tools_Random_256() & 1; } /* Reduce spice if there is any */ Map_ChangeSpiceAmount(packed, -1); /* Boom a bloom if there is one */ if (t->groundSpriteID == g_bloomSpriteID) { Map_Bloom_ExplodeSpice(packed, g_playerHouseID); return; } /* Update the tile with the crater */ t->overlaySpriteID = overlaySpriteID + iconMap[0]; Map_Update(packed, 0, false); }
/** * Load all kinds of important info from a file. * @param fp The file to load from. * @param length The length of the data chunk. * @return True if and only if all bytes were read successful. */ bool Info_LoadOld(FILE *fp, uint32 length) { VARIABLE_NOT_USED(length); if (!SaveLoad_Load(s_saveInfoOld, fp, NULL)) return false; return true; }
/** * Handles Click event for "Resume Game" button. * * @return True, always. */ bool GUI_Widget_HOF_Resume_Click(Widget *w) { VARIABLE_NOT_USED(w); g_doQuitHOF = true; return true; }
/** * Handles Click event for "Resume Game" button. * * @return True, always. */ bool GUI_Widget_HOF_Resume_Click(Widget *w) { VARIABLE_NOT_USED(w); g_var_81E6 = true; return true; }
/** * Remove fog around the current structure. * Radius to uncover is taken from the current structure info. * * Stack: *none* * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Structure_RemoveFogAroundTile(ScriptEngine *script) { VARIABLE_NOT_USED(script); Structure_RemoveFog(g_scriptCurrentStructure); return 0; }
static void Scenario_Load_Team(const char *key, char *settings) { uint8 houseType, teamActionType, movementType; uint16 minMembers, maxMembers; char *split; VARIABLE_NOT_USED(key); /* The value should have 5 values separated by a ',' */ split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* First value is the House type */ houseType = House_StringToType(settings); if (houseType == HOUSE_INVALID) return; /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Second value is the teamAction type */ teamActionType = Team_ActionStringToType(settings); if (teamActionType == TEAM_ACTION_INVALID) return; /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Third value is the movement type */ movementType = Unit_MovementStringToType(settings); if (movementType == MOVEMENT_INVALID) return; /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Fourth value is minimum amount of members in team */ minMembers = atoi(settings); /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Fifth value is maximum amount of members in team */ maxMembers = atoi(settings); Team_Create(houseType, teamActionType, movementType, minMembers, maxMembers); }
/** * Get the state of the current structure. * * Stack: *none* * * @param script The script engine to operate on. * @return State of current structure. */ uint16 Script_Structure_GetState(ScriptEngine *script) { Structure *s; VARIABLE_NOT_USED(script); s = g_scriptCurrentStructure; return s->state; }
/** * Unknown function 0C5A. * * Stack: *none* * * @param script The script engine to operate on. * @return unknown. */ uint16 Script_Structure_Unknown0C5A(ScriptEngine *script) { tile32 tile; Structure *s; Unit *u; uint16 position; VARIABLE_NOT_USED(script); s = g_scriptCurrentStructure; if (s->o.linkedID == 0xFF) return 0; u = Unit_Get_ByIndex(s->o.linkedID); if (g_table_unitInfo[u->o.type].movementType == MOVEMENT_WINGER && Unit_SetPosition(u, s->o.position)) { s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; if (s->o.linkedID == 0xFF) Structure_SetState(s, STRUCTURE_STATE_IDLE); Object_Script_Variable4_Clear(&s->o); if (s->o.houseID == g_playerHouseID) Sound_Output_Feedback(g_playerHouseID + 49); return 1; } position = Structure_FindFreePosition(s, u->o.type == UNIT_HARVESTER); if (position == 0) return 0; u->o.seenByHouses |= s->o.seenByHouses; tile = Tile_Center(Tile_UnpackTile(position)); if (!Unit_SetPosition(u, tile)) return 0; s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; Unit_SetOrientation(u, Tile_GetDirection(s->o.position, u->o.position) & 0xE0, true, 0); Unit_SetOrientation(u, u->orientation[0].current, true, 1); if (u->o.houseID == g_playerHouseID && u->o.type == UNIT_HARVESTER) { GUI_DisplayHint(STR_SEARCH_FOR_SPICE_FIELDS_TO_HARVEST, 0x6A); } if (s->o.linkedID == 0xFF) Structure_SetState(s, STRUCTURE_STATE_IDLE); Object_Script_Variable4_Clear(&s->o); if (s->o.houseID != g_playerHouseID) return 1; if (s->o.type == STRUCTURE_REPAIR) return 1; Sound_Output_Feedback(g_playerHouseID + ((u->o.type == UNIT_HARVESTER) ? 68 : 30)); return 1; }
/** * Checks if the current unit is in transport. * * Stack: *none*. * * @param script The script engine to operate on. * @return True if the current unit is in transport. */ uint16 Script_Unit_IsInTransport(ScriptEngine *script) { Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; return u->o.flags.s.inTransport ? 1 : 0; }
/** * Removes fog around the current unit. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_RemoveFog(ScriptEngine *script) { Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; Unit_RemoveFog(u); return 0; }
/** * Blink the unit for 32 ticks. * * Stack: *none*. * * @param script The script engine to operate on. * @return The value 0. Always. */ uint16 Script_Unit_Blink(ScriptEngine *script) { Unit *u; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; u->blinkCounter = 32; return 0; }
/** * Stop performing an explosion. * @param e The Explosion to end. * @param parameter Unused parameter. */ static void Explosion_Func_Stop(Explosion *e, uint16 parameter) { VARIABLE_NOT_USED(parameter); g_map[Tile_PackTile(e->position)].hasExplosion = false; Explosion_Update(0, e); e->commands = NULL; }
/** * 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; }
/** * Gets the average distance between current team members, and set the * position of the team to the average position. * * Stack: *none*. * * @param script The script engine to operate on. * @return The average distance. */ uint16 Script_Team_GetAverageDistance(ScriptEngine *script) { uint16 averageX = 0; uint16 averageY = 0; uint16 count = 0; uint16 distance = 0; Team *t; PoolFindStruct find; VARIABLE_NOT_USED(script); t = g_scriptCurrentTeam; find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; u = Unit_Find(&find); if (u == NULL) break; if (t->index != u->team - 1) continue; count++; averageX += (u->o.position.x >> 8) & 0x3f; averageY += (u->o.position.y >> 8) & 0x3f; } if (count == 0) return 0; averageX /= count; averageY /= count; t->position = Tile_MakeXY(averageX, averageY); find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; u = Unit_Find(&find); if (u == NULL) break; if (t->index != u->team - 1) continue; distance += Tile_GetDistanceRoundedUp(u->o.position, t->position); } distance /= count; if (t->target == 0 || t->targetTile == 0) return distance; if (Tile_GetDistancePacked(Tile_PackXY(averageX, averageY), Tools_Index_GetPackedTile(t->target)) <= 10) t->targetTile = 2; return distance; }
static uint32 SaveLoad_SelectionType(void *object, uint32 value, bool loading) { VARIABLE_NOT_USED(object); if (loading) { g_selectionTypeNew = (uint16)value; return 0; } return g_selectionType; }
static uint32 SaveLoad_TickScenarioStart(void *object, uint32 value, bool loading) { VARIABLE_NOT_USED(object); if (loading) { g_tickScenarioStart = g_timerGame - value; return 0; } return g_timerGame - g_tickScenarioStart; }
/** * Check if there is a bloom at the location, and make it explode if needed. * @param e The Explosion to perform the explosion on. * @param parameter Unused parameter. */ static void Explosion_Func_BloomExplosion(Explosion *e, uint16 parameter) { uint16 packed; VARIABLE_NOT_USED(parameter); packed = Tile_PackTile(e->position); if (g_map[packed].groundSpriteID != g_bloomSpriteID) return; Map_Bloom_ExplodeSpice(packed, g_playerHouseID); }