Smart Contract

FixesTraits

A.d2abb5dbf5e08666.FixesTraits

Valid From

86,128,615

Deployed

3d ago
Feb 24, 2026, 11:54:28 PM UTC

Dependents

0 imports
1/**
2> Author: Fixes Lab <https://github.com/fixes-world/>
3
4# FixesTraits
5
6This contract mainly includes commonly used Structs related to Asset Traits.
7
8*/
9// Thirdparty Imports
10import MetadataViews from 0x1d7e57aa55817448
11import ViewResolver from 0x1d7e57aa55817448
12
13/// The `FixesTraits` contract
14///
15access(all) contract FixesTraits {
16
17    access(all) entitlement Write;
18
19    /// =============  Trait: Fungible Token =============
20
21    /// The mergeable data interface
22    ///
23    access(all) struct interface MergeableData {
24        /// Get the id of the data
25        access(all)
26        view fun getId(): String
27        /// Get the string value of the data
28        access(all)
29        view fun toString(): String
30        /// Get the data keys
31        access(all)
32        view fun getKeys(): [String]
33        /// Get the value of the data
34        access(all)
35        view fun getValue(_ key: String): AnyStruct?
36        /// Get the writable keys
37        access(all)
38        view fun getWritableKeys(): [String] {
39            return []
40        }
41        /// Set the value of the data
42        access(Write)
43        fun setValue(_ key: String, _ value: AnyStruct) {
44            pre {
45                self.getWritableKeys().contains(key): "The key is not writable"
46            }
47            let writableKeys = self.getWritableKeys()
48            if writableKeys.length == 0 {
49                panic("The gene data cannot be modified by set method")
50            }
51        }
52        /// Split the data into another instance
53        access(Write)
54        fun split(_ perc: UFix64): {MergeableData} {
55            pre {
56                perc > 0.0 && perc <= 1.0: "The percentage should be between 0 and 1"
57            }
58            post {
59                self.getType().identifier == result.getType().identifier: "The data type must be the same"
60            }
61        }
62        /// Merge the data from another instance
63        access(Write)
64        fun merge(_ from: {MergeableData}): Void {
65            pre {
66                self.getType().identifier == from.getType().identifier: "The data type must be the same"
67            }
68        }
69    }
70
71    /// =============  Trait: Season 0 - Secret Garden =============
72
73    /// The Definition of the Marketplace Season 0
74    access(all) enum Season0SecretPlaces: UInt8 {
75        access(all) case HeartOfTheAzureOcean // 蔚蓝海洋之心
76        access(all) case HeartOfTheDarkForest // 黑暗森林之心
77        access(all) case GardenofVenus // 维纳斯的花园
78        access(all) case CityOfTheDead // 亡者之城
79        access(all) case DragonboneWasteland // 龙骨荒原
80        access(all) case MysticForest // 神秘森林
81        access(all) case SoulWaterfall // 灵魂瀑布
82        access(all) case AbyssalHollow // 深渊之穴
83        access(all) case SilentGlacier // 静寂冰川
84        access(all) case FrostWasteland // 霜冻荒原
85        access(all) case DesolateGround // 荒芜之地
86        access(all) case MirageCity // 海市蜃楼
87        access(all) case ScorpionGorge // 蛇蝎峡谷
88        access(all) case MysteriousIceLake // 神秘冰湖
89        access(all) case NightShadowForest // 夜影密林
90        access(all) case SpiritualValley // 灵犀山谷
91        access(all) case RavensPerch // 乌鸦栖息地
92        access(all) case RainbowFalls // 彩虹瀑布
93        access(all) case TwilightValley // 暮色谷地
94        access(all) case RuggedHill // 乱石山岗
95    }
96
97    access(all)
98    view fun getSeason0SecretPlacesDefs(): [Definition] {
99        return [
100            Definition(5, 100), // 1% chance, rarity 2
101            Definition(12, 1900), // 19% chance, rarity 1
102            Definition(20, 8000) // 80% chance, rarity 0
103        ]
104    }
105
106    /// =============  Trait: Season 0 - Ability =============
107
108    /// The Definition of the Marketplace Season 0
109    ///
110    access(all) enum Season0Ability: UInt8 {
111        access(all) case Omniscience // 全知全能
112        access(all) case ElementalMastery // 全元素掌控
113        access(all) case TimeStand // 时间静止
114        access(all) case MillenniumFreeze // 千年冰封
115        access(all) case FossilResurgence // 化石重生
116        access(all) case MysticVision // 神秘视界
117        access(all) case PhoenixRebirth // 凤凰复生
118        access(all) case SoulBind // 灵魂束缚
119        access(all) case PrayerOfLight // 光明祈祷
120        access(all) case Starfall // 星辰坠落
121        access(all) case DragonsBreath // 龙焰吐息
122        access(all) case PsychicSense // 心灵感应
123        access(all) case MindControl // 心灵控制
124        access(all) case EndlessTorment // 无尽痛苦
125        access(all) case MeditationInDespair // 绝境冥思
126        access(all) case SilenceFear // 沉默恐惧
127        access(all) case GloryChallenge // 荣耀挑战
128        access(all) case ShieldWall // 防御罩墙
129        access(all) case TidalCall // 海潮呼唤
130        access(all) case FountainOfLife // 生命之泉
131        access(all) case PsychicInteraction // 精神互动
132        access(all) case PlagueTransmission // 疫病传染
133        access(all) case NinjaStealth // 忍者潜行
134        access(all) case BattleRoar // 战斗吼叫
135        access(all) case CongestiveStrike // 充血打击
136        access(all) case HolyGuidance // 圣光指引
137        access(all) case EmpoweredBarrier // 强化结界
138        access(all) case PerpetualLife // 生生不息
139        access(all) case CombatEvade // 战斗闪避
140        access(all) case AbyssArrow // 深渊之箭
141        access(all) case SoulEcho // 灵魂回响
142        access(all) case ArcaneBlink // 魔力闪现
143        access(all) case ArcaneExplosion // 魔力爆炸
144        access(all) case ShadowStep // 暗黑影步
145        access(all) case JadeStoneSpell // 玉石咒语
146        access(all) case PhantomDodge // 鬼魅闪避
147        access(all) case KissOfDeath // 死亡之吻
148        access(all) case PhantomSummoning // 幻影召唤
149        access(all) case EyeOfTheRaven // 乌鸦之眼
150        access(all) case RatSwarmSurge // 鼠群涌动
151        access(all) case FlameShock // 烈焰冲击
152        access(all) case GaleSpeedBlade // 疾风快剑
153        access(all) case InterstellarFlight // 星界飞行
154        access(all) case WraithSeal // 怨灵封印
155        access(all) case DivineRestoration // 神力恢复
156        access(all) case LifePull // 生命拉扯
157        access(all) case RapidFire // 快速射击
158        access(all) case MightyBlow // 强力打击
159        access(all) case PhysicalTraining // 锻炼体魄
160    }
161
162    access(all)
163    view fun getSeason0AbilityDefs(): [Definition] {
164        return [
165            Definition(5, 20), // 0.2% chance, rarity 3
166            Definition(12, 100), // 1% chance, rarity 2
167            Definition(25, 1880), // 18.8% chance, rarity 1
168            Definition(49, 8000) // 80% chance, rarity 0
169        ]
170    }
171
172    /// =============  Trait: Season 0 - Weapons =============
173
174    access(all) enum Season0Weapons: UInt8 {
175        access(all) case Starstaff // 星辰法杖
176        access(all) case BowOfTheMysteriousBird // 九天玄鸟之弓
177        access(all) case VoidSpiritWand // 虚空灵杖
178        access(all) case GodlyWand // 神祇法杖
179        access(all) case SunriseHolySword // 旭日圣剑
180        access(all) case DeepSeaTrident // 深海三叉戟
181        access(all) case DragonboneBow // 龙骨弓
182        access(all) case RainbowHolySword // 虹光圣剑
183        access(all) case MysticalGrimoire // 神秘法书
184        access(all) case SaintsStaff // 圣者圣杖
185        access(all) case FirePhoenixWhip // 火凤长鞭
186        access(all) case SoulOrb // 灵魂法球
187        access(all) case LightningSpear // 闪电长矛
188        access(all) case DarkScepter // 黑暗权杖
189        access(all) case DawnLance // 破晓长枪
190        access(all) case RedLotusRocket // 红莲火箭
191        access(all) case DemonBoneSpike // 恶魔骨刺
192        access(all) case EvilStarCatapult // 魔星投石器
193        access(all) case SwordOfTenderness // 温柔之剑
194        access(all) case WindWarriorLongbow // 风战者长弓
195        access(all) case NightDagger // 黑夜匕首
196        access(all) case GalaxyHalberd // 银河双戟
197        access(all) case MoonshadowScimitar // 影月弯刀
198        access(all) case IceCrownDagger // 冰冠短剑
199        access(all) case StormBattleAxe // 风暴战斧
200        access(all) case ArcaneStaff // 奥术长杖
201        access(all) case AxeOfInferno // 烈火之斧
202        access(all) case SkybreakerDualBlade // 破空双刃
203        access(all) case IceGiantSword // 寒冰巨剑
204        access(all) case TrollsHammer // 巨魔之锤
205    }
206
207    access(all)
208    view fun getSeason0WeaponsDefs(): [Definition] {
209        return [
210            Definition(5, 20), // 0.2% chance, rarity 3
211            Definition(12, 100), // 1% chance, rarity 2
212            Definition(20, 1880), // 18.8% chance, rarity 1
213            Definition(30, 8000) // 80% chance, rarity 0
214        ]
215    }
216
217    access(account)
218    fun attemptToGenerateRandomEntryForSeason0(): @Entry? {
219        // 5% for secret places, 10% for ability, 15% for weapons, 70% for nothing
220        let randForTypePercent = revertibleRandom<UInt8>(modulo: 100)
221        if randForTypePercent >= 30 {
222            return nil
223        }
224        var type: Type? = nil
225        if randForTypePercent < 5 {
226            type = Type<Season0SecretPlaces>()
227        } else if randForTypePercent < 15 {
228            type = Type<Season0Ability>()
229        } else {
230            type = Type<Season0Weapons>()
231        }
232        return <- self.generateRandomEntry(type!)
233    }
234
235    /**
236        ------------------------ Public Methods ------------------------
237    */
238
239    /// Get the rarity definition array for a given series
240    /// The higher the rarity in front.
241    ///
242    access(all)
243    view fun getRarityDefinition(_ series: Type): [Definition]? {
244        switch series {
245        case Type<Season0SecretPlaces>():
246            return self.getSeason0SecretPlacesDefs()
247        case Type<Season0Ability>():
248            return self.getSeason0AbilityDefs()
249        case Type<Season0Weapons>():
250            return self.getSeason0WeaponsDefs()
251        }
252        return nil
253    }
254
255    /// Get the maximum rarity for a given series
256    ///
257    access(all)
258    view fun getMaxRarity(_ series: Type): UInt8 {
259        if let arr = self.getRarityDefinition(series) {
260            return UInt8(arr.length - 1)
261        }
262        return UInt8.max
263    }
264
265    /**
266        ------------------------ Genreal Interfaces & Resources ------------------------
267    */
268
269    /// The Entry Definition
270    ///
271    access(all) struct Definition {
272        access(all)
273        let threshold: UInt8 // max value for this rarity, not included
274        access(all)
275        let weight: UInt64 // weight of this rarity
276
277        view init (
278            _ threshold: UInt8,
279            _ weight: UInt64
280        ) {
281            self.threshold = threshold
282            self.weight = weight
283        }
284    }
285
286    /// The TraitWithOffset Definition
287    ///
288    access(all) struct TraitWithOffset {
289        // Series is the identifier of the series enum
290        access(all)
291        let series: Type
292        // Value is the value of the trait, as the rawValue of the enum
293        access(all)
294        let value: UInt8
295        // Rarity is the rarity of the trait, from 0 to maxRarity
296        access(all)
297        let rarity: UInt8
298        // Offset is random between -20 and 20, to be used for rarity extension
299        access(all)
300        let offset: Int8
301
302        init(
303            series: Type,
304            value: UInt8,
305            rarity: UInt8
306        ) {
307            self.series = series
308            self.value = value
309            self.rarity = rarity
310            // Offset is random between -20 and 20
311            let rand = revertibleRandom<UInt8>(modulo: 40)
312            self.offset = Int8(rand) - 20
313        }
314    }
315
316    /// The `Entry` resource
317    ///
318    access(all) resource Entry: ViewResolver.Resolver {
319        access(self)
320        let trait: TraitWithOffset
321
322        init (
323            series: Type,
324            value: UInt8,
325            rarity: UInt8
326        ) {
327            self.trait = TraitWithOffset(
328                series: series,
329                value: value,
330                rarity: rarity
331            )
332        }
333
334        /// Get the trait
335        ///
336        access(all)
337        view fun getTrait(): TraitWithOffset {
338            return self.trait
339        }
340
341        // ---- implement Resolver ----
342
343        /// Function that returns all the Metadata Views available for this profile
344        ///
345        access(all)
346        view fun getViews(): [Type] {
347            return [
348                Type<TraitWithOffset>(),
349                Type<MetadataViews.Trait>()
350            ]
351        }
352
353        /// Function that resolves a metadata view for this profile
354        ///
355        access(all)
356        fun resolveView(_ view: Type): AnyStruct? {
357            switch view {
358            case Type<TraitWithOffset>():
359                return self.trait
360            case Type<MetadataViews.Trait>():
361                return MetadataViews.Trait(
362                    name: self.trait.series.identifier,
363                    value: self.trait.value,
364                    displayType: "number",
365                    rarity: MetadataViews.Rarity(
366                        score: UFix64(self.trait.rarity),
367                        max: UFix64(FixesTraits.getMaxRarity(self.trait.series)),
368                        description: nil
369                    )
370                )
371            }
372            return nil
373        }
374    }
375
376    /// Create a new entry
377    ///
378    access(account)
379    fun createEntry(_ series: Type, _ value: UInt8, _ rarity: UInt8): @Entry {
380        return <- create Entry(
381            series: series,
382            value: value,
383            rarity: rarity
384        )
385    }
386
387    /// Generate a random entry
388    ///
389    access(account)
390    fun generateRandomEntry(_ series: Type): @Entry? {
391        let defs = self.getRarityDefinition(series)
392        if defs == nil {
393            return nil // DO NOT PANIC
394        }
395
396        // generate a random number for the entry
397        let randForEntry = revertibleRandom<UInt64>(modulo: 10000)
398
399        // calculate the rarity
400        var totalWeight: UInt64 = 0
401        var lastThreshold: UInt8 = 0
402        var currentThreshold: UInt8 = 0
403        let maxRarity = UInt8(defs!.length - 1)
404        var currentRarity: UInt8 = 0
405        // find the right rarity
406        for i, def in defs! {
407            totalWeight = totalWeight + def.weight
408            if randForEntry < totalWeight {
409                currentThreshold = def.threshold
410                currentRarity = maxRarity - UInt8(i)
411                break
412            }
413            lastThreshold = def.threshold
414        }
415        // create the entry
416        return <- self.createEntry(
417            series,
418            // calculate the value
419            lastThreshold + (UInt8(randForEntry % 255) % (currentThreshold - lastThreshold)),
420            currentRarity
421        )
422    }
423}
424