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 SimFlightHitsLiquid(C4Real fcx, C4Real fcy, C4Real xdir, C4Real ydir) { // Start in water? int temp; if (DensityLiquid(GBackDensity(fixtoi(fcx), fixtoi(fcy)))) if (!SimFlight(fcx, fcy, xdir, ydir, 0, C4M_Liquid - 1, temp=10)) return false; // Hits liquid? if (!SimFlight(fcx, fcy, xdir, ydir, C4M_Liquid, 100, temp=-1)) return false; // liquid & deep enough? return GBackLiquid(fixtoi(fcx), fixtoi(fcy)) && GBackLiquid(fixtoi(fcx), fixtoi(fcy) + 9); }
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; }
bool C4MaterialCore::Load(C4Group &hGroup, const char *szEntryName) { StdStrBuf Source; if (!hGroup.LoadEntryString(szEntryName,&Source)) return false; StdStrBuf Name = hGroup.GetFullName() + DirSep + szEntryName; if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, Source, Name.getData())) return false; // adjust placement, if not specified if (!Placement) { if (DensitySolid(Density)) { Placement=30; if (!DigFree) Placement+=20; if (!BlastFree) Placement+=10; } else if (DensityLiquid(Density)) Placement=10; else Placement=5; } return true; }
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 C4MapScriptMatTexMask::UnmaskSpec(C4String *spec) { // Mask all indices of material-texture definitions // Possible definitions: // Material-Texture - Given material-texture combination (both sky and tunnel background) // Material - All defined default textures of given material // * - All materials including sky // Sky - Index C4M_MaxTexIndex // Transparent - Index 0 // Background - All tunnel materials plus sky // Liquid - All liquid materials // Solid - All solid materials // Possible modifiers: // ^Material - Given material only with sky background // &Material - Given material only with tunnel background // ~Material - Inverse of given definition; i.e. everything except Material if (!spec || !spec->GetCStr()) return; const char *cspec = spec->GetCStr(); bool invert=false, bgsky=false, bgtunnel=false, prefix_done=false; while (*cspec) { switch (*cspec) { case '~': invert=!invert; break; case '^': bgsky=true; break; case '&': bgtunnel=true; break; default: prefix_done=true; break; } if (prefix_done) break; ++cspec; } std::vector<bool> mat_mask(C4M_MaxTexIndex+1, false); if (SEqual(cspec, DrawFn_Transparent_Name)) { // "Transparent" is zero index. Force to non-IFT mat_mask[0] = true; } else if (SEqual(cspec, DrawFn_Sky_Name)) { // Sky material mat_mask[C4M_MaxTexIndex] = true; } else if (SEqual(cspec, DrawFn_Background_Name)) { // All background materials for (int32_t i=1; i<C4M_MaxTexIndex; ++i) if (!DensitySemiSolid(Landscape.GetPixDensity(i))) mat_mask[i] = true; // Background includes sky mat_mask[C4M_MaxTexIndex] = true; } else if (SEqual(cspec, DrawFn_Liquid_Name)) { // All liquid materials for (int32_t i=1; i<C4M_MaxTexIndex; ++i) if (DensityLiquid(Landscape.GetPixDensity(i))) mat_mask[i] = true; } else if (SEqual(cspec, DrawFn_Solid_Name)) { // All solid materials for (int32_t i=1; i<C4M_MaxTexIndex; ++i) if (DensitySolid(Landscape.GetPixDensity(i))) mat_mask[i] = true; } else if (SEqual(cspec, "*")) { // All materials for (int32_t i=1; i<C4M_MaxTexIndex; ++i) mat_mask[i] = true; // Including sky mat_mask[C4M_MaxTexIndex] = true; } else { // Specified material if (SCharCount('-', cspec)) { // Material+Texture int32_t col = ::MapScript.pTexMap->GetIndexMatTex(cspec, NULL, false); if (col) mat_mask[col] = true; } else { // Only material: Mask all textures of this material int32_t mat = ::MapScript.pMatMap->Get(cspec); if (mat!=MNone) { const char *tex_name; int32_t col; for (int32_t itex=0; (tex_name=::MapScript.pTexMap->GetTexture(itex)); itex++) if ((col = ::MapScript.pTexMap->GetIndex(cspec,tex_name,false))) mat_mask[col] = true; } } } // 'OR' spec onto this->sky_mask and this->tunnel_mask. Apply bgsky, bgtunnel and invert. for (int32_t i=0; i<C4M_MaxTexIndex + 1; ++i) { if ((mat_mask[i] && (bgsky || !bgtunnel)) != invert) sky_mask[i] = true; if ((mat_mask[i] && (!bgsky || bgtunnel)) != invert) tunnel_mask[i] = true; } }