void C4Landscape::UpdatePixMaps() // Copied from C4Landscape.cpp { int32_t i; for (i = 0; i < C4M_MaxTexIndex; i++) Pix2Mat[i] = PixCol2Mat(i); for (i = 0; i < C4M_MaxTexIndex; i++) Pix2Dens[i] = MatDensity(Pix2Mat[i]); for (i = 0; i < C4M_MaxTexIndex; i++) Pix2Place[i] = MatValid(Pix2Mat[i]) ? ::MaterialMap.Map[Pix2Mat[i]].Placement : 0; for (i = 0; i < C4M_MaxTexIndex; i++) Pix2Light[i] = MatValid(Pix2Mat[i]) && (::MaterialMap.Map[Pix2Mat[i]].Light>0); Pix2Place[0] = 0; // clear bridge mat conversion buffers for (int32_t i = 0; i < C4M_MaxTexIndex; ++i) { delete [] BridgeMatConversion[i]; BridgeMatConversion[i] = NULL; } }
int32_t C4TextureMap::GetIndexMatTex(const char *szMaterialTexture, const char *szDefaultTexture, BOOL fAddIfNotExist, const char *szErrorIfFailed) { // split material/texture pair StdStrBuf Material, Texture; Material.CopyUntil(szMaterialTexture, '-'); Texture.Copy(SSearch(szMaterialTexture, "-")); // texture not given or invalid? int32_t iMatTex = 0; if (Texture.getData()) if (iMatTex = GetIndex(Material.getData(), Texture.getData(), fAddIfNotExist)) return iMatTex; if (szDefaultTexture) if (iMatTex = GetIndex(Material.getData(), szDefaultTexture, fAddIfNotExist)) return iMatTex; #ifdef C4ENGINE // search material long iMaterial = Game.Material.Get(szMaterialTexture); if (!MatValid(iMaterial)) { if (szErrorIfFailed) DebugLogF("Error getting MatTex for %s: Invalid material", szErrorIfFailed); return 0; } // return default map entry return Game.Material.Map[iMaterial].DefaultMatTex; #else return 0; #endif }
bool C4TexMapEntry::Init() { // Find material iMaterialIndex = ::MaterialMap.Get(Material.getData()); if (!MatValid(iMaterialIndex)) { DebugLogF("Error initializing material %s-%s: Invalid material!", Material.getData(), Texture.getData()); return false; } pMaterial = &::MaterialMap.Map[iMaterialIndex]; // Find texture StdStrBuf FirstTexture; FirstTexture.CopyUntil(Texture.getData(), '-'); C4Texture * sfcTexture = ::TextureMap.GetTexture(FirstTexture.getData()); if (!sfcTexture) { DebugLogF("Error initializing material %s-%s: Invalid texture!", Material.getData(), FirstTexture.getData()); Clear(); return false; } // Get overlay properties int32_t iOverlayType=pMaterial->OverlayType; int32_t iZoom=0; if (iOverlayType & C4MatOv_Exact) iZoom=1; if (iOverlayType & C4MatOv_HugeZoom) iZoom=4; // Create pattern MatPattern.Set(sfcTexture->Surface32, iZoom); return true; }
void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj) { // Splash only if there is free space above if (GBackSemiSolid(tx, ty - 15)) return; // get back mat int32_t iMat = GBackMat(tx, ty); // check liquid if (MatValid(iMat)) if (DensityLiquid(Game.Material.Map[iMat].Density) && Game.Material.Map[iMat].Instable) { int32_t sy = ty; while (GBackLiquid(tx, sy) && sy > ty - 20 && sy >= 0) sy--; // Splash bubbles and liquid for (int32_t cnt = 0; cnt < amt; cnt++) { BubbleOut(tx + Random(16) - 8, ty + Random(16) - 6); if (GBackLiquid(tx, ty) && !GBackSemiSolid(tx, sy)) Game.PXS.Create(Game.Landscape.ExtractMaterial(tx, ty), itofix(tx), itofix(sy), FIXED100(Random(151) - 75), FIXED100(-Random(200))); } } // Splash sound if (amt >= 20) StartSoundEffect("Splash2", false, 100, pByObj); else if (amt > 1) StartSoundEffect("Splash1", false, 100, pByObj); }
void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj) { // Splash only if there is free space above if (GBackSemiSolid(tx, ty - 15)) return; // get back mat int32_t iMat = GBackMat(tx, ty); // check liquid if (MatValid(iMat)) if (DensityLiquid(::MaterialMap.Map[iMat].Density) && ::MaterialMap.Map[iMat].Instable) { int32_t sy = ty; while (GBackLiquid(tx, sy) && sy > ty - 20 && sy >= 0) sy--; // Splash bubbles and liquid for (int32_t cnt=0; cnt<amt; cnt++) { int32_t bubble_x = tx+Random(16)-8; int32_t bubble_y = ty+Random(16)-6; BubbleOut(bubble_x,bubble_y); if (GBackLiquid(tx,ty) && !GBackSemiSolid(tx, sy)) { C4Real xdir = C4REAL100(Random(151)-75); C4Real ydir = C4REAL100(-Random(200)); ::PXS.Create(::Landscape.ExtractMaterial(tx,ty,false), itofix(tx),itofix(sy), xdir, ydir); } } } // Splash sound if (amt>=20) StartSoundEffect("Splash2",false,100,pByObj); else if (amt>1) StartSoundEffect("Splash1",false,100,pByObj); }
bool C4PXSSystem::Create(int32_t mat, C4Real ix, C4Real iy, C4Real ixdir, C4Real iydir) { C4PXS *pxp; if (!MatValid(mat)) return false; if (!(pxp=New())) return false; pxp->Mat=mat; pxp->x=ix; pxp->y=iy; pxp->xdir=ixdir; pxp->ydir=iydir; return true; }
void C4EditCursor::UpdateStatusBar() { int32_t X=this->X, Y=this->Y; StdStrBuf str; switch (Mode) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4CNS_ModePlay: if (::MouseControl.GetCaption()) str.CopyUntil(::MouseControl.GetCaption(),'|'); break; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4CNS_ModeEdit: str.Format("%i/%i (%s)",X,Y,Target ? (Target->GetName()) : LoadResStr("IDS_CNS_NOTHING") ); break; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - case C4CNS_ModeDraw: str.Format("%i/%i (%s)",X,Y,MatValid(GBackMat(X,Y)) ? ::MaterialMap.Map[GBackMat(X,Y)].Name : LoadResStr("IDS_CNS_NOTHING") ); break; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } Console.DisplayInfoText(C4ConsoleGUI::CONSOLE_Cursor, str); }
bool C4TexMapEntry::Init() { #ifdef C4ENGINE // Find material iMaterialIndex = Game.Material.Get(Material.getData()); if(!MatValid(iMaterialIndex)) { DebugLogF("Error initializing material %s-%s: Invalid material!", Material.getData(), Texture.getData()); return false; } pMaterial = &Game.Material.Map[iMaterialIndex]; // Special, hardcoded crap: change <liquid>-Smooth to <liquid>-Liquid const char *szTexture = Texture.getData(); if (DensityLiquid(pMaterial->Density)) if (SEqualNoCase(szTexture, "Smooth")) szTexture = "Liquid"; // Find texture C4Texture * sfcTexture = Game.TextureMap.GetTexture(szTexture); if(!sfcTexture) { DebugLogF("Error initializing material %s-%s: Invalid texture!", Material.getData(), Texture.getData()); Clear(); return false; } // Get overlay properties int32_t iOverlayType=pMaterial->OverlayType; bool fMono = !!(iOverlayType & C4MatOv_Monochrome); int32_t iZoom=0; if (iOverlayType & C4MatOv_Exact) iZoom=1; if (iOverlayType & C4MatOv_HugeZoom) iZoom=4; // Create pattern if (sfcTexture->Surface32) MatPattern.Set(sfcTexture->Surface32, iZoom, fMono); else MatPattern.Set(sfcTexture->Surface8, iZoom, fMono); MatPattern.SetColors(pMaterial->Color, pMaterial->Alpha); #endif return true; }
void C4EditCursor::ApplyToolPicker() { int32_t iMaterial; BYTE byIndex; switch (::Landscape.Mode) { case C4LSC_Static: { bool material_set = false; // Material-texture from map if ((byIndex=::Landscape.GetMapIndex(X/::Landscape.MapZoom,Y/::Landscape.MapZoom))) { const C4TexMapEntry *pTex = ::TextureMap.GetEntry(byIndex & (IFT-1)); if (pTex && pTex->GetMaterialName() && *pTex->GetMaterialName()) { Console.ToolsDlg.SelectMaterial(pTex->GetMaterialName()); Console.ToolsDlg.SelectTexture(pTex->GetTextureName()); Console.ToolsDlg.SetIFT(!!(byIndex & ~(IFT-1))); material_set = true; } } // default to sky, because invalid materials are always rendered as sky if (!material_set) Console.ToolsDlg.SelectMaterial(C4TLS_MatSky); break; } case C4LSC_Exact: // Material only from landscape if (MatValid(iMaterial=GBackMat(X,Y))) { Console.ToolsDlg.SelectMaterial(::MaterialMap.Map[iMaterial].Name); Console.ToolsDlg.SetIFT(!!GBackIFT(X,Y)); } else Console.ToolsDlg.SelectMaterial(C4TLS_MatSky); break; } Hold=false; }
bool C4MaterialMap::mrfConvert(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged) { if (pReaction->fUserDefined) if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged)) return false; switch (evEvent) { case meePXSMove: // PXS movement // for hardcoded stuff: only InMatConvert is Snow in Water, which does not have any collision proc if (!pReaction->fUserDefined) break; // user-defined conversions may also convert upon hitting materials case meePXSPos: // PXS check before movement { // Check depth int32_t iDepth = pReaction->fUserDefined ? pReaction->iDepth : ::MaterialMap.Map[iPxsMat].InMatConvertDepth; if (!iDepth || GBackMat(iX, iY - iDepth) == iLsMat) { // Convert iPxsMat = pReaction->fUserDefined ? pReaction->iConvertMat : ::MaterialMap.Map[iPxsMat].InMatConvertTo; if (!MatValid(iPxsMat)) // Convert failure (target mat not be loaded, or target may be C4TLS_MatSky): Kill Pix return true; // stop movement after conversion fXDir = fYDir = 0; if (pfPosChanged) *pfPosChanged = true; } } break; case meeMassMove: // MassMover-movement // Conversion-transfer to PXS ::PXS.Create(iPxsMat,itofix(iX),itofix(iY)); return true; } // not handled return false; }
bool C4MaterialMap::CrossMapMaterials(const char* szEarthMaterial) // Called after load { // Check material number if (::MaterialMap.Num>C4MaxMaterial) { LogFatal(LoadResStr("IDS_PRC_TOOMANYMATS")); return false; } // build reaction function map delete [] ppReactionMap; typedef C4MaterialReaction * C4MaterialReactionPtr; ppReactionMap = new C4MaterialReactionPtr[(Num+1)*(Num+1)]; for (int32_t iMatPXS=-1; iMatPXS<Num; iMatPXS++) { C4Material *pMatPXS = (iMatPXS+1) ? Map+iMatPXS : NULL; for (int32_t iMatLS=-1; iMatLS<Num; iMatLS++) { C4MaterialReaction *pReaction = NULL; C4Material *pMatLS = ( iMatLS+1) ? Map+ iMatLS : NULL; // natural stuff: material conversion here? if (pMatPXS && pMatPXS->sInMatConvert.getLength() && SEqualNoCase(pMatPXS->sInMatConvert.getData(), pMatLS ? pMatLS->Name : C4TLS_MatSky)) pReaction = &DefReactConvert; // non-sky reactions else if (pMatPXS && pMatLS) { // incindiary vs extinguisher if ((pMatPXS->Incendiary && pMatLS->Extinguisher) || (pMatPXS->Extinguisher && pMatLS->Incendiary)) pReaction = &DefReactPoof; // incindiary vs inflammable else if ((pMatPXS->Incendiary && pMatLS->Inflammable) || (pMatPXS->Inflammable && pMatLS->Incendiary)) pReaction = &DefReactIncinerate; // corrosive vs corrode else if (pMatPXS->Corrosive && pMatLS->Corrode) pReaction = &DefReactCorrode; // liquid hitting liquid or solid: Material insertion else if (DensityLiquid(MatDensity(iMatPXS)) && DensitySemiSolid(MatDensity(iMatLS))) pReaction = &DefReactInsert; // solid hitting solid: Material insertion else if (DensitySolid(MatDensity(iMatPXS)) && DensitySolid(MatDensity(iMatLS))) pReaction = &DefReactInsert; } // assign the function; or NULL for no reaction SetMatReaction(iMatPXS, iMatLS, pReaction); } } // reset max shape size max_shape_width=max_shape_height=0; // material-specific initialization int32_t cnt; for (cnt=0; cnt<Num; cnt++) { C4Material *pMat = Map+cnt; const char *szTextureOverlay = NULL; // newgfx: init pattern if (Map[cnt].sTextureOverlay.getLength()) if (::TextureMap.GetTexture(Map[cnt].sTextureOverlay.getLength())) { szTextureOverlay = Map[cnt].sTextureOverlay.getData(); // backwards compatibility: if a pattern was specified although the no-pattern flag was set, overwrite that flag if (Map[cnt].OverlayType & C4MatOv_None) { DebugLogF("Error in overlay of material %s: Flag C4MatOv_None ignored because a custom overlay (%s) was specified!", Map[cnt].Name, szTextureOverlay); Map[cnt].OverlayType &= ~C4MatOv_None; } } // default to first texture in texture map int iTexMapIx; if (!szTextureOverlay && (iTexMapIx = ::TextureMap.GetIndex(Map[cnt].Name, NULL, false))) szTextureOverlay = TextureMap.GetEntry(iTexMapIx)->GetTextureName(); // default to smooth if (!szTextureOverlay) szTextureOverlay = "none"; // search/create entry in texmap Map[cnt].DefaultMatTex = ::TextureMap.GetIndex(Map[cnt].Name, szTextureOverlay, true, FormatString("DefaultMatTex of mat %s", Map[cnt].Name).getData()); // init PXS facet C4Surface * sfcTexture; C4Texture * Texture; if (Map[cnt].sPXSGfx.getLength()) if ((Texture=::TextureMap.GetTexture(Map[cnt].sPXSGfx.getData()))) if ((sfcTexture=Texture->Surface32)) Map[cnt].PXSFace.Set(sfcTexture, Map[cnt].PXSGfxRt.x, Map[cnt].PXSGfxRt.y, Map[cnt].PXSGfxRt.Wdt, Map[cnt].PXSGfxRt.Hgt); // evaluate reactions for that material for (unsigned int iRCnt = 0; iRCnt < pMat->CustomReactionList.size(); ++iRCnt) { C4MaterialReaction *pReact = &(pMat->CustomReactionList[iRCnt]); if (pReact->sConvertMat.getLength()) pReact->iConvertMat = Get(pReact->sConvertMat.getData()); else pReact->iConvertMat = -1; // evaluate target spec int32_t tmat; if (MatValid(tmat=Get(pReact->TargetSpec.getData()))) { // single material target if (pReact->fInverseSpec) for (int32_t cnt2=-1; cnt2<Num; cnt2++) { if (cnt2!=tmat) SetMatReaction(cnt, cnt2, pReact); else SetMatReaction(cnt, tmat, pReact); } } else if (SEqualNoCase(pReact->TargetSpec.getData(), "All")) { // add to all materials, including sky if (!pReact->fInverseSpec) for (int32_t cnt2=-1; cnt2<Num; cnt2++) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Solid")) { // add to all solid materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (DensitySolid(Map[cnt2].Density) != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "SemiSolid")) { // add to all semisolid materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (DensitySemiSolid(Map[cnt2].Density) != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Background")) { // add to all BG materials, including sky if (!pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Density != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Sky")) { // add to sky if (!pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); else for (int32_t cnt2=0; cnt2<Num; cnt2++) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Incendiary") || SEqualNoCase(pReact->TargetSpec.getData(), "Incindiary")) { // add to all incendiary materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Incendiary == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Extinguisher")) { // add to all incendiary materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Extinguisher == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Inflammable")) { // add to all incendiary materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Inflammable == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Corrosive")) { // add to all incendiary materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Corrosive == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } else if (SEqualNoCase(pReact->TargetSpec.getData(), "Corrode")) { // add to all incendiary materials if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact); for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Corrode == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact); } } } // second loop (DefaultMatTex is needed by GetIndexMatTex) for (cnt=0; cnt<Num; cnt++) { if (Map[cnt].sBlastShiftTo.getLength()) Map[cnt].BlastShiftTo=::TextureMap.GetIndexMatTex(Map[cnt].sBlastShiftTo.getData(), NULL, true, FormatString("BlastShiftTo of mat %s", Map[cnt].Name).getData()); if (Map[cnt].sInMatConvertTo.getLength()) Map[cnt].InMatConvertTo=Get(Map[cnt].sInMatConvertTo.getData()); if (Map[cnt].sBelowTempConvertTo.getLength()) Map[cnt].BelowTempConvertTo=::TextureMap.GetIndexMatTex(Map[cnt].sBelowTempConvertTo.getData(), NULL, true, FormatString("BelowTempConvertTo of mat %s", Map[cnt].Name).getData()); if (Map[cnt].sAboveTempConvertTo.getLength()) Map[cnt].AboveTempConvertTo=::TextureMap.GetIndexMatTex(Map[cnt].sAboveTempConvertTo.getData(), NULL, true, FormatString("AboveTempConvertTo of mat %s", Map[cnt].Name).getData()); } // Get hardcoded system material indices const C4TexMapEntry* earth_entry = ::TextureMap.GetEntry(::TextureMap.GetIndexMatTex(szEarthMaterial)); if(!earth_entry) { LogFatal(FormatString("Earth material \"%s\" not found!", szEarthMaterial).getData()); return false; } MVehic = Get("Vehicle"); MCVehic = Mat2PixColDefault(MVehic); MHalfVehic = Get("HalfVehicle"); MCHalfVehic = Mat2PixColDefault(MHalfVehic); MTunnel = Get("Tunnel"); MWater = Get("Water"); MEarth = Get(earth_entry->GetMaterialName()); if ((MVehic==MNone) || (MTunnel==MNone)) { LogFatal(LoadResStr("IDS_PRC_NOSYSMATS")); return false; } return true; }
void C4PXS::Execute() { #ifdef DEBUGREC_PXS if (Config.General.DebugRec) { C4RCExecPXS rc; rc.x=x; rc.y=y; rc.iMat=Mat; rc.pos = 0; AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc)); } #endif int32_t inmat; // Safety if (!MatValid(Mat)) { Deactivate(); return; } // Out of bounds if ((x<0) || (x>=::Landscape.GetWidth()) || (y<-10) || (y>=::Landscape.GetHeight())) { Deactivate(); return; } // Material conversion int32_t iX = fixtoi(x), iY = fixtoi(y); inmat=GBackMat(iX,iY); C4MaterialReaction *pReact = ::MaterialMap.GetReactionUnsafe(Mat, inmat); if (pReact && (*pReact->pFunc)(pReact, iX,iY, iX,iY, xdir,ydir, Mat,inmat, meePXSPos, NULL)) { Deactivate(); return; } // Gravity ydir+=GravAccel; if (GBackDensity(iX, iY + 1) < ::MaterialMap.Map[Mat].Density) { // Air speed: Wind plus some random int32_t iWind = Weather.GetWind(iX, iY); C4Real txdir = itofix(iWind, 15) + C4REAL256(Random(1200) - 600); C4Real tydir = C4REAL256(Random(1200) - 600); // Air friction, based on WindDrift. MaxSpeed is ignored. int32_t iWindDrift = std::max(::MaterialMap.Map[Mat].WindDrift - 20, 0); xdir += ((txdir - xdir) * iWindDrift) * WindDrift_Factor; ydir += ((tydir - ydir) * iWindDrift) * WindDrift_Factor; } C4Real ctcox = x + xdir; C4Real ctcoy = y + ydir; int32_t iToX = fixtoi(ctcox), iToY = fixtoi(ctcoy); // In bounds? if (Inside<int32_t>(iToX, 0, ::Landscape.GetWidth()-1) && Inside<int32_t>(iToY, 0, ::Landscape.GetHeight()-1)) // Check path if (::Landscape._PathFree(iX, iY, iToX, iToY)) { x=ctcox; y=ctcoy; return; } // Test path to target position int32_t iX0 = iX, iY0 = iY; bool fStopMovement = false; do { // Step int32_t inX = iX + Sign(iToX - iX), inY = iY + Sign(iToY - iY); // Contact? inmat = GBackMat(inX, inY); C4MaterialReaction *pReact = ::MaterialMap.GetReactionUnsafe(Mat, inmat); if (pReact) { if ((*pReact->pFunc)(pReact, iX,iY, inX,inY, xdir,ydir, Mat,inmat, meePXSMove, &fStopMovement)) { // destructive contact Deactivate(); return; } else { // no destructive contact, but speed or position changed: Stop moving for now if (fStopMovement) { // But keep fractional positions to allow proper movement on moving ground if (iX != iX0) x = itofix(iX); if (iY != iY0) y = itofix(iY); return; } // there was a reaction func, but it didn't do anything - continue movement } } iX = inX; iY = inY; } while (iX != iToX || iY != iToY); // No contact? Free movement x=ctcox; y=ctcoy; #ifdef DEBUGREC_PXS if (Config.General.DebugRec) { C4RCExecPXS rc; rc.x=x; rc.y=y; rc.iMat=Mat; rc.pos = 1; AddDbgRec(RCT_ExecPXS, &rc, sizeof(rc)); } #endif return; }
int32_t FnFxFireStart(C4AulContext *ctx, C4Object *pObj, int32_t iNumber, int32_t iTemp, int32_t iCausedBy, bool fBlasted, C4Object *pIncineratingObject) { // safety if (!pObj) return -1; // temp readd if (iTemp) { pObj->SetOnFire(true); return 1; } // fail if already on fire if (pObj->GetOnFire()) return -1; // get associated effect C4Effect *pEffect; if (!(pEffect = pObj->pEffects)) return -1; if (!(pEffect = pEffect->Get(iNumber, true))) return -1; // structures must eject contents now, because DoCon is not guaranteed to be // executed! // In extinguishing material BOOL fFireCaused = TRUE; int32_t iMat; if (MatValid(iMat = GBackMat(pObj->x, pObj->y))) if (Game.Material.Map[iMat].Extinguisher) { // blasts should changedef in water, too! if (fBlasted) if (pObj->Def->BurnTurnTo != C4ID_None) pObj->ChangeDef(pObj->Def->BurnTurnTo); // no fire caused fFireCaused = FALSE; } // BurnTurnTo if (fFireCaused) if (pObj->Def->BurnTurnTo != C4ID_None) pObj->ChangeDef(pObj->Def->BurnTurnTo); // eject contents C4Object *cobj; if (!pObj->Def->IncompleteActivity && !pObj->Def->NoBurnDecay) while (cobj = pObj->Contents.GetObject()) { cobj->Controller = iCausedBy; // update controller, so incinerating a hut // full of flints attributes the damage to // the incinerator if (pObj->Contained) cobj->Enter(pObj->Contained); else cobj->Exit(cobj->x, cobj->y); } // Detach attached objects cobj = 0; if (!pObj->Def->IncompleteActivity && !pObj->Def->NoBurnDecay) while (cobj = Game.FindObject(0, 0, 0, 0, 0, OCF_All, 0, pObj, 0, 0, ANY_OWNER, cobj)) if ((cobj->Action.Act > ActIdle) && (cobj->Def->ActMap[cobj->Action.Act].Procedure == DFA_ATTACH)) cobj->SetAction(ActIdle); // fire caused? if (!fFireCaused) { // if object was blasted but not incinerated (i.e., inside extinguisher) // do a script callback if (fBlasted) pObj->Call(PSF_IncinerationEx, &C4AulParSet(C4VInt(iCausedBy))); return -1; } // determine fire appearance int32_t iFireMode; if (!(iFireMode = pObj->Call(PSF_FireMode).getInt())) { // set default fire modes DWORD dwCat = pObj->Category; if (dwCat & (C4D_Living | C4D_StaticBack)) // Tiere, Bäume iFireMode = C4Fx_FireMode_LivingVeg; else if (dwCat & (C4D_Structure | C4D_Vehicle)) // Gebäude und Fahrzeuge // sind unten meist kantig iFireMode = C4Fx_FireMode_StructVeh; else iFireMode = C4Fx_FireMode_Object; } else if (!Inside<int32_t>(iFireMode, 1, C4Fx_FireMode_Last)) { DebugLogF("Warning: FireMode %d of object %s (%s) is invalid!", iFireMode, pObj->GetName(), pObj->Def->GetName()); iFireMode = C4Fx_FireMode_Object; } // store causes in effect vars FxFireVarMode(pEffect).SetInt(iFireMode); FxFireVarCausedBy(pEffect) .SetInt(iCausedBy); // used in C4Object::GetFireCause and timer! FxFireVarBlasted(pEffect).SetBool(fBlasted); FxFireVarIncineratingObj(pEffect).SetObject(pIncineratingObject); // Set values pObj->SetOnFire(true); pObj->FirePhase = Random(MaxFirePhase); if (pObj->Shape.Wdt * pObj->Shape.Hgt > 500) StartSoundEffect("Inflame", false, 100, pObj); if (pObj->Def->Mass >= 100) StartSoundEffect("Fire", true, 100, pObj); // Engine script call pObj->Call(PSF_Incineration, &C4AulParSet(C4VInt(iCausedBy))); // Done, success return C4Fx_OK; }