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; } }