@@ -164,6 +164,104 @@ auto fact_soft_penalty( const proc::part_fact &fact ) -> int
164164 } );
165165}
166166
167+ struct candidate_sort_entry {
168+ proc::part_ix ix = proc::invalid_part_ix;
169+ int score = 0 ;
170+ int uses = 0 ;
171+ int mass_g = 0 ;
172+ int volume_ml = 0 ;
173+ std::string id;
174+ };
175+
176+ auto weapon_role_score ( const std::string &role, const proc::part_fact &fact ) -> int
177+ {
178+ const auto density = fact_density ( fact );
179+ const auto bash_resist = fact_bash_resist ( fact );
180+ const auto cut_resist = fact_cut_resist ( fact );
181+ const auto chip_resist = fact_chip_resist ( fact );
182+ const auto bullet_resist = fact_bullet_resist ( fact );
183+ const auto reinforce_bonus = fact_reinforce_bonus ( fact );
184+ const auto soft_penalty = fact_soft_penalty ( fact );
185+
186+ if ( role == " blade" ) {
187+ return density / 8 + cut_resist * 6 + chip_resist * 3 + bullet_resist * 2 +
188+ reinforce_bonus * 5 - soft_penalty * 4 + fact.mass_g / 120 ;
189+ }
190+ if ( role == " guard" ) {
191+ return bash_resist * 5 + chip_resist * 3 + cut_resist * 2 + density / 10 +
192+ reinforce_bonus * 4 - soft_penalty * 3 + fact.mass_g / 180 ;
193+ }
194+ if ( role == " handle" ) {
195+ return bash_resist * 3 + chip_resist * 2 + density / 14 + reinforce_bonus * 2 -
196+ soft_penalty * 2 + fact.mass_g / 220 ;
197+ }
198+ if ( role == " grip" ) {
199+ return bash_resist * 3 + cut_resist * 2 + chip_resist * 2 + density / 12 +
200+ reinforce_bonus * 2 - soft_penalty * 3 + fact.mass_g / 260 ;
201+ }
202+ if ( role == " reinforcement" ) {
203+ return reinforce_bonus * 8 + cut_resist * 3 + chip_resist * 3 + bash_resist * 2 +
204+ density / 10 - soft_penalty * 2 + fact.mass_g / 140 ;
205+ }
206+ return bash_resist * 2 + cut_resist * 2 + chip_resist * 2 + density / 16 +
207+ reinforce_bonus * 2 - soft_penalty * 2 + fact.mass_g / 200 ;
208+ }
209+
210+ auto build_candidate_sort_entry ( const proc::slot_data &slot,
211+ const proc::part_fact &fact ) -> candidate_sort_entry
212+ {
213+ return candidate_sort_entry{
214+ .ix = fact.ix ,
215+ .score = weapon_role_score ( slot.role , fact ),
216+ .uses = fact.uses ,
217+ .mass_g = fact.mass_g ,
218+ .volume_ml = fact.volume_ml ,
219+ .id = fact.id .str (),
220+ };
221+ }
222+
223+ auto sort_weapon_slot_candidates ( const proc::slot_data &slot,
224+ const std::vector<proc::part_fact> &facts,
225+ std::vector<proc::part_ix> &slot_facts ) -> void
226+ {
227+ auto ranked = std::vector<candidate_sort_entry> {};
228+ ranked.reserve ( slot_facts.size () );
229+ std::ranges::for_each ( slot_facts, [&]( const proc::part_ix ix ) {
230+ const auto *fact = find_fact ( facts, ix );
231+ if ( fact == nullptr ) {
232+ return ;
233+ }
234+ ranked.push_back ( build_candidate_sort_entry ( slot, *fact ) );
235+ } );
236+
237+ std::ranges::sort ( ranked, []( const candidate_sort_entry & lhs,
238+ const candidate_sort_entry & rhs ) {
239+ if ( lhs.score != rhs.score ) {
240+ return lhs.score > rhs.score ;
241+ }
242+ if ( lhs.uses != rhs.uses ) {
243+ return lhs.uses > rhs.uses ;
244+ }
245+ if ( lhs.mass_g != rhs.mass_g ) {
246+ return lhs.mass_g > rhs.mass_g ;
247+ }
248+ if ( lhs.volume_ml != rhs.volume_ml ) {
249+ return lhs.volume_ml > rhs.volume_ml ;
250+ }
251+ if ( lhs.id != rhs.id ) {
252+ return lhs.id < rhs.id ;
253+ }
254+ return lhs.ix < rhs.ix ;
255+ } );
256+
257+ slot_facts.clear ();
258+ slot_facts.reserve ( ranked.size () );
259+ std::ranges::transform ( ranked, std::back_inserter ( slot_facts ),
260+ []( const candidate_sort_entry & entry ) {
261+ return entry.ix ;
262+ } );
263+ }
264+
167265auto role_count ( const std::vector<proc::craft_pick> &picks, const proc::slot_id &slot ) -> int
168266{
169267 return static_cast <int >( std::ranges::count_if ( picks, [&]( const proc::craft_pick & pick ) {
@@ -556,6 +654,9 @@ auto proc::build_candidates( const schema &sch,
556654 slot_facts.push_back ( fact.ix );
557655 }
558656 } );
657+ if ( sch.id == proc::schema_id ( " sword" ) || sch.cat == " weapon" ) {
658+ sort_weapon_slot_candidates ( slot, facts, slot_facts );
659+ }
559660 ret.emplace ( slot.id , std::move ( slot_facts ) );
560661 } );
561662 return ret;
0 commit comments