1+ using UnityEngine ;
2+
3+ namespace ScavShrapnelMod . Helpers
4+ {
5+ /// <summary>
6+ /// Material category for blocks.
7+ /// Classified from internal game data (hitsound, stepsound, metallic flag).
8+ /// Never from block name (localized, unreliable).
9+ /// </summary>
10+ public enum MaterialCategory
11+ {
12+ Unknown ,
13+ Sand , // hitsound=sand, stepsound=Sand
14+ Snow , // hitsound=sand, stepsound=Snow
15+ Dirt , // hitsound=dirt
16+ Rock , // hitsound=rock
17+ Concrete , // hitsound=concrete
18+ Metal , // metallic=true OR hitsound=steel/scrapmetal
19+ Wood , // hitsound=wood
20+ Glass , // hitsound=glass, stepsound=Glass
21+ Ice , // hitsound=glass, stepsound=Ice
22+ Rubber , // hitsound=rubber, stepsound=Rubber
23+ Plastic , // hitsound=rubber, stepsound=Plastic
24+ Organic , // hitsound=rustle or gore2
25+ Trash , // hitsound=trash
26+ Ore // hitsound=crystal
27+ }
28+
29+ /// <summary>
30+ /// Centralized block material classification system.
31+ /// Uses internal game data only — never localized block names.
32+ ///
33+ /// Shared by:
34+ /// - GroundDebrisLogic (ground surface particles)
35+ /// - ShrapnelSpawnLogic (block debris from destroyed blocks)
36+ /// - Any future systems needing material-aware logic
37+ ///
38+ /// Based on GetBlockInfo() switch statement (35 block types).
39+ /// 100% coverage via hitsound/stepsound mapping.
40+ /// </summary>
41+ public static class BlockClassifier
42+ {
43+ /// <summary>
44+ /// Classifies a block into a material category.
45+ /// Priority: metallic flag → hitsound → stepsound refinement.
46+ /// </summary>
47+ /// <param name="info">BlockInfo from WorldGeneration.GetBlockInfo(). Null-safe.</param>
48+ /// <returns>MaterialCategory enum value.</returns>
49+ public static MaterialCategory Classify ( BlockInfo info )
50+ {
51+ if ( info == null ) return MaterialCategory . Unknown ;
52+ if ( info . metallic ) return MaterialCategory . Metal ;
53+
54+ string hit = info . hitsound ?? string . Empty ;
55+ string step = info . stepsound ?? string . Empty ;
56+
57+ // WHY: hitsound is the primary material indicator.
58+ // stepsound refines ambiguous cases (sand vs snow, glass vs ice).
59+
60+ if ( hit == "steel" || hit == "scrapmetal" ) return MaterialCategory . Metal ;
61+ if ( hit == "rock" ) return MaterialCategory . Rock ;
62+ if ( hit == "sand" ) return ( step == "Snow" ) ? MaterialCategory . Snow : MaterialCategory . Sand ;
63+ if ( hit == "dirt" ) return MaterialCategory . Dirt ;
64+ if ( hit == "wood" ) return MaterialCategory . Wood ;
65+ if ( hit == "concrete" ) return MaterialCategory . Concrete ;
66+ if ( hit == "glass" ) return ( step == "Ice" ) ? MaterialCategory . Ice : MaterialCategory . Glass ;
67+ if ( hit == "rubber" ) return ( step == "Plastic" ) ? MaterialCategory . Plastic : MaterialCategory . Rubber ;
68+ if ( hit == "rustle" ) return MaterialCategory . Organic ;
69+ if ( hit == "gore2" ) return MaterialCategory . Organic ;
70+ if ( hit == "trash" ) return MaterialCategory . Trash ;
71+ if ( hit == "crystal" ) return MaterialCategory . Ore ;
72+
73+ return MaterialCategory . Unknown ;
74+ }
75+
76+ /// <summary>
77+ /// Returns dust count multiplier for a material category.
78+ /// Soft/loose materials produce more fine dust.
79+ /// Hard/dense materials produce fewer, larger chunks.
80+ /// Range: 0.8 – 1.3 (max 1.6× difference).
81+ /// </summary>
82+ public static float GetDustMultiplier ( MaterialCategory cat )
83+ {
84+ switch ( cat )
85+ {
86+ case MaterialCategory . Sand : return 1.3f ;
87+ case MaterialCategory . Snow : return 1.25f ;
88+ case MaterialCategory . Dirt : return 1.2f ;
89+ case MaterialCategory . Organic : return 1.15f ;
90+ case MaterialCategory . Trash : return 1.1f ;
91+ case MaterialCategory . Glass : return 1.1f ;
92+ case MaterialCategory . Ice : return 1.1f ;
93+ case MaterialCategory . Wood : return 1.05f ;
94+ case MaterialCategory . Plastic : return 1.0f ;
95+ case MaterialCategory . Rubber : return 0.95f ;
96+ case MaterialCategory . Rock : return 0.9f ;
97+ case MaterialCategory . Concrete : return 0.9f ;
98+ case MaterialCategory . Ore : return 0.85f ;
99+ case MaterialCategory . Metal : return 0.8f ;
100+ default : return 1.0f ;
101+ }
102+ }
103+
104+ /// <summary>
105+ /// Returns base color for a material category.
106+ /// Randomized within each category's palette.
107+ /// Used for ground debris and block destruction particles.
108+ /// </summary>
109+ public static Color GetColor ( MaterialCategory cat , System . Random rng )
110+ {
111+ switch ( cat )
112+ {
113+ case MaterialCategory . Sand :
114+ // Warm yellow-tan
115+ return new Color (
116+ rng . Range ( 0.72f , 0.86f ) ,
117+ rng . Range ( 0.62f , 0.76f ) ,
118+ rng . Range ( 0.32f , 0.46f ) ) ;
119+
120+ case MaterialCategory . Snow :
121+ // White with slight blue tint
122+ {
123+ float w = rng . Range ( 0.85f , 0.97f ) ;
124+ return new Color ( w * 0.98f , w , w * 1.02f ) ;
125+ }
126+
127+ case MaterialCategory . Dirt :
128+ // Dark earthy brown
129+ return new Color (
130+ rng . Range ( 0.38f , 0.52f ) ,
131+ rng . Range ( 0.25f , 0.38f ) ,
132+ rng . Range ( 0.12f , 0.22f ) ) ;
133+
134+ case MaterialCategory . Rock :
135+ // Neutral gray with slight warm tint
136+ {
137+ float g = rng . Range ( 0.38f , 0.56f ) ;
138+ return new Color ( g , g * 0.97f , g * 0.93f ) ;
139+ }
140+
141+ case MaterialCategory . Concrete :
142+ // Light gray, slightly warmer than rock
143+ {
144+ float g = rng . Range ( 0.45f , 0.6f ) ;
145+ return new Color ( g * 1.02f , g , g * 0.96f ) ;
146+ }
147+
148+ case MaterialCategory . Metal :
149+ // Cool blue-gray (steel/alloy tint)
150+ {
151+ float g = rng . Range ( 0.28f , 0.44f ) ;
152+ return new Color ( g * 0.92f , g * 0.96f , g * 1.1f ) ;
153+ }
154+
155+ case MaterialCategory . Wood :
156+ // Warm medium brown
157+ return new Color (
158+ rng . Range ( 0.42f , 0.56f ) ,
159+ rng . Range ( 0.26f , 0.38f ) ,
160+ rng . Range ( 0.12f , 0.2f ) ) ;
161+
162+ case MaterialCategory . Glass :
163+ // Light blue-white (transparent debris)
164+ {
165+ float g = rng . Range ( 0.6f , 0.78f ) ;
166+ return new Color ( g * 0.92f , g * 0.97f , g * 1.05f ) ;
167+ }
168+
169+ case MaterialCategory . Ice :
170+ // Pale blue (colder than glass)
171+ {
172+ float g = rng . Range ( 0.65f , 0.82f ) ;
173+ return new Color ( g * 0.88f , g * 0.95f , g * 1.08f ) ;
174+ }
175+
176+ case MaterialCategory . Rubber :
177+ // Very dark gray (tire-black)
178+ {
179+ float g = rng . Range ( 0.12f , 0.22f ) ;
180+ return new Color ( g , g , g ) ;
181+ }
182+
183+ case MaterialCategory . Plastic :
184+ // Light off-white gray
185+ {
186+ float g = rng . Range ( 0.55f , 0.72f ) ;
187+ return new Color ( g * 1.01f , g , g * 0.97f ) ;
188+ }
189+
190+ case MaterialCategory . Organic :
191+ // Green-brown (plant/fungal)
192+ return new Color (
193+ rng . Range ( 0.22f , 0.38f ) ,
194+ rng . Range ( 0.32f , 0.48f ) ,
195+ rng . Range ( 0.12f , 0.25f ) ) ;
196+
197+ case MaterialCategory . Trash :
198+ // Dark mixed gray-brown
199+ {
200+ float g = rng . Range ( 0.2f , 0.35f ) ;
201+ return new Color ( g * 1.1f , g * 0.95f , g * 0.85f ) ;
202+ }
203+
204+ case MaterialCategory . Ore :
205+ // Copper-tinted (warm metallic)
206+ {
207+ float g = rng . Range ( 0.35f , 0.5f ) ;
208+ return new Color ( g * 1.25f , g * 0.85f , g * 0.55f ) ;
209+ }
210+
211+ default :
212+ // Unknown: safe neutral gray
213+ {
214+ float g = rng . Range ( 0.35f , 0.5f ) ;
215+ return new Color ( g , g * 0.98f , g * 0.95f ) ;
216+ }
217+ }
218+ }
219+
220+ /// <summary>
221+ /// Returns color with specified alpha.
222+ /// Convenience wrapper for debris particles.
223+ /// </summary>
224+ public static Color GetColorWithAlpha ( MaterialCategory cat , System . Random rng , float alpha )
225+ {
226+ Color c = GetColor ( cat , rng ) ;
227+ c . a = alpha ;
228+ return c ;
229+ }
230+ }
231+ }
0 commit comments