Skip to main content

codegridfx/
cell.rs

1use theframework::prelude::*;
2
3/// Assignment operators in the AST
4#[derive(Clone, PartialEq, Debug)]
5pub enum AssignmentOp {
6    Assign,
7    AddAssign,
8    SubtractAssign,
9    MultiplyAssign,
10    DivideAssign,
11}
12
13impl AssignmentOp {
14    pub fn describe(&self) -> &str {
15        match self {
16            AssignmentOp::Assign => "=",
17            AssignmentOp::AddAssign => "+=",
18            AssignmentOp::SubtractAssign => "-=",
19            AssignmentOp::MultiplyAssign => "*=",
20            AssignmentOp::DivideAssign => "/=",
21        }
22    }
23
24    pub fn to_index(&self) -> i32 {
25        match self {
26            AssignmentOp::Assign => 0,
27            AssignmentOp::AddAssign => 1,
28            AssignmentOp::SubtractAssign => 2,
29            AssignmentOp::MultiplyAssign => 3,
30            AssignmentOp::DivideAssign => 4,
31        }
32    }
33
34    pub fn from_index(idx: i32) -> Option<Self> {
35        match idx {
36            0 => Some(AssignmentOp::Assign),
37            1 => Some(AssignmentOp::AddAssign),
38            2 => Some(AssignmentOp::SubtractAssign),
39            3 => Some(AssignmentOp::MultiplyAssign),
40            4 => Some(AssignmentOp::DivideAssign),
41            _ => None,
42        }
43    }
44}
45
46#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
47pub enum ArithmeticOp {
48    Add,
49    Subtract,
50    Multiply,
51    Divide,
52}
53
54impl ArithmeticOp {
55    pub fn from_index(idx: usize) -> Option<Self> {
56        match idx {
57            0 => Some(ArithmeticOp::Add),
58            1 => Some(ArithmeticOp::Subtract),
59            2 => Some(ArithmeticOp::Multiply),
60            3 => Some(ArithmeticOp::Divide),
61            _ => None,
62        }
63    }
64
65    pub fn to_index(&self) -> usize {
66        match self {
67            ArithmeticOp::Add => 0,
68            ArithmeticOp::Subtract => 1,
69            ArithmeticOp::Multiply => 2,
70            ArithmeticOp::Divide => 3,
71        }
72    }
73
74    pub fn to_string(&self) -> &'static str {
75        match self {
76            ArithmeticOp::Add => "+",
77            ArithmeticOp::Subtract => "-",
78            ArithmeticOp::Multiply => "*",
79            ArithmeticOp::Divide => "/",
80        }
81    }
82}
83
84#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
85pub enum ComparisonOp {
86    Equal,
87    NotEqual,
88    LessEqual,
89    GreaterEqual,
90    Less,
91    Greater,
92}
93impl ComparisonOp {
94    pub fn from_index(idx: usize) -> Option<Self> {
95        match idx {
96            0 => Some(ComparisonOp::Equal),
97            1 => Some(ComparisonOp::NotEqual),
98            2 => Some(ComparisonOp::LessEqual),
99            3 => Some(ComparisonOp::GreaterEqual),
100            4 => Some(ComparisonOp::Less),
101            5 => Some(ComparisonOp::Greater),
102            _ => None,
103        }
104    }
105
106    pub fn to_index(&self) -> usize {
107        match self {
108            ComparisonOp::Equal => 0,
109            ComparisonOp::NotEqual => 1,
110            ComparisonOp::LessEqual => 2,
111            ComparisonOp::GreaterEqual => 3,
112            ComparisonOp::Less => 4,
113            ComparisonOp::Greater => 5,
114        }
115    }
116    pub fn to_string(&self) -> &'static str {
117        match self {
118            ComparisonOp::Equal => "==",
119            ComparisonOp::NotEqual => "!=",
120            ComparisonOp::LessEqual => "<=",
121            ComparisonOp::GreaterEqual => ">=",
122            ComparisonOp::Less => "<",
123            ComparisonOp::Greater => ">",
124        }
125    }
126}
127
128#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
129pub enum Cell {
130    ConstructAssignBlock,
131    ConstructColorAssignBlock,
132    ConstructIfBlock,
133
134    Empty,
135    Variable(String),
136    Integer(String),
137    Float(String),
138    Str(String),
139    Boolean(bool),
140    Assignment,
141    Comparison(ComparisonOp),
142    Arithmetic(ArithmeticOp),
143    If,
144    Else,
145    PaletteColor(u8),
146    Value(String),
147
148    // Script based
149    Action,
150    AddItem,
151    BlockEvents,
152    CastSpell,
153    ClearAudio,
154    ClearTarget,
155    CloseIn,
156    DealDamage,
157    Drop,
158    DropItems,
159    EntitiesInRadius,
160    Equip,
161    GetAttr,
162    GetAttrOf,
163    GetEntityAttr,
164    Goto,
165    Id,
166    Intent,
167    InventoryItems,
168    InventoryItemsOf,
169    Message,
170    Say,
171    NotifyIn,
172    OfferInventory,
173    Patrol,
174    PlayAudio,
175    Random,
176    RandomWalk,
177    RandomWalkInSector,
178    SetAttr,
179    SetAudioBusVolume,
180    SetEmitLight,
181    SetPlayerCamera,
182    SetProximityTracking,
183    SetTarget,
184    SetTile,
185    Take,
186    Target,
187    HasTarget,
188    Teleport,
189    ToggleAttr,
190    TookDamage,
191
192    // Shader based (sorted)
193    Abs,
194    Atan,
195    Atan2,
196    Ceil,
197    Clamp,
198    Cos,
199    Cross,
200    Degrees,
201    Dot,
202    Exp,
203    Floor,
204    Fract,
205    Length,
206    Log,
207    Max,
208    Min,
209    Mix,
210    Mod,
211    Normalize,
212    Pow,
213    Radians,
214    Rand,
215    Rotate2d,
216    Sign,
217    Sin,
218    Smoothstep,
219    Sample,
220    SampleNormal,
221    Textures(String),
222    Sqrt,
223    Step,
224    Tan,
225
226    LeftParent,
227    RightParent,
228}
229
230#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
231pub enum CellRole {
232    None,
233    Operator,
234    Value,
235    Function,
236    Event,
237}
238
239impl CellRole {
240    pub fn to_color(&self) -> [u8; 4] {
241        match self {
242            CellRole::None => [180, 180, 180, 255],
243            CellRole::Operator => [200, 195, 150, 255],
244            CellRole::Value => [160, 185, 160, 255],
245            CellRole::Function => [160, 175, 190, 255],
246            CellRole::Event => [195, 170, 150, 255],
247        }
248    }
249}
250
251use Cell::*;
252
253impl Cell {
254    pub fn description(&self) -> &'static str {
255        match self {
256            Cell::ConstructAssignBlock => "Var = ..",
257            Cell::ConstructColorAssignBlock => "Color = ..",
258            Cell::ConstructIfBlock => "If .. == ..",
259
260            Cell::Empty => "Empty",
261            Cell::Variable(_) => "Variable",
262            Cell::Integer(_) => "Integer",
263            Cell::Float(_) => "Float",
264            Cell::Str(_) => "String",
265            Cell::Boolean(_) => "Boolean",
266            Cell::Assignment => "Assignment",
267            Cell::Comparison(_) => "Comparison",
268            Cell::Arithmetic(_) => "Arithmetic",
269            Cell::If => "If",
270            Cell::Else => "Else",
271            Cell::PaletteColor(_) => "Palette Color",
272            Cell::Value(_) => "Value",
273
274            Cell::Action => "Action",
275            Cell::AddItem => "Add Item",
276            Cell::BlockEvents => "Block Events",
277            Cell::CastSpell => "Cast Spell",
278            Cell::ClearAudio => "Clear Audio",
279            Cell::ClearTarget => "Clear Target",
280            Cell::CloseIn => "Close In",
281            Cell::DealDamage => "Deal Damage",
282            Cell::Drop => "Drop",
283            Cell::DropItems => "Drop Items",
284            Cell::EntitiesInRadius => "Entities in Radius",
285            Cell::Equip => "Equip",
286            Cell::GetAttr => "Get Attribute",
287            Cell::GetAttrOf => "Get Attribute Of",
288            Cell::GetEntityAttr => "Get Attribute Of",
289            Cell::Goto => "Goto",
290            Cell::Id => "Id",
291            Cell::Intent => "Intent",
292            Cell::InventoryItems => "Inventory Items",
293            Cell::InventoryItemsOf => "Inventory Items Of",
294            Cell::Message => "Message",
295            Cell::Say => "Say",
296            Cell::NotifyIn => "Notify In",
297            Cell::OfferInventory => "Offer Inventory",
298            Cell::Patrol => "Patrol",
299            Cell::PlayAudio => "Play Audio",
300            Cell::Random => "Random Number",
301            Cell::RandomWalk => "Random Walk",
302            Cell::RandomWalkInSector => "Random Walk In Sector",
303            Cell::SetAttr => "Set Attribute",
304            Cell::SetAudioBusVolume => "Set Audio Bus Volume",
305            Cell::SetEmitLight => "Set Emit Light",
306            Cell::SetPlayerCamera => "Set Player Camera",
307            Cell::SetProximityTracking => "Set Proximity Tracking",
308            Cell::SetTarget => "Set Target",
309            Cell::SetTile => "Set Tile",
310            Cell::Take => "Take",
311            Cell::Target => "Target",
312            Cell::HasTarget => "Has Target",
313            Cell::Teleport => "Teleport",
314            Cell::ToggleAttr => "Toggle Attr",
315            Cell::TookDamage => "Took Damage",
316
317            Cell::Abs => "Abs",
318            Cell::Atan => "Atan",
319            Cell::Atan2 => "Atan2",
320            Cell::Ceil => "Ceil",
321            Cell::Clamp => "Clamp",
322            Cell::Cos => "Cos",
323            Cell::Cross => "Cross",
324            Cell::Degrees => "Degrees",
325            Cell::Dot => "Dot",
326            Cell::Exp => "Exp",
327            Cell::Floor => "Floor",
328            Cell::Fract => "Fract",
329            Cell::Length => "Length",
330            Cell::Log => "Log",
331            Cell::Max => "Max",
332            Cell::Min => "Min",
333            Cell::Mix => "Mix",
334            Cell::Mod => "Mod",
335            Cell::Normalize => "Normalize",
336            Cell::Pow => "Pow",
337            Cell::Radians => "Radians",
338            Cell::Rand => "Rand",
339            Cell::Rotate2d => "Rotate2d",
340            Cell::Sign => "Sign",
341            Cell::Sin => "Sin",
342            Cell::Smoothstep => "Smoothstep",
343            Cell::Sample => "Sample",
344            Cell::SampleNormal => "Sample Normal",
345            Cell::Textures(_) => "Texture",
346            Cell::Sqrt => "Sqrt",
347            Cell::Step => "Step",
348            Cell::Tan => "Tan",
349
350            Cell::LeftParent => "Left Parenthesis",
351            Cell::RightParent => "Right Parenthesis",
352        }
353    }
354    pub fn from_str(s: &str) -> Option<Self> {
355        match s {
356            "Var = .." => Some(Cell::ConstructAssignBlock),
357            "Color = .." => Some(Cell::ConstructColorAssignBlock),
358            "If .. == .." => Some(Cell::ConstructIfBlock),
359
360            "Empty" => Some(Cell::Empty),
361            "Variable" => Some(Cell::Variable("Unnamed".into())),
362            "Integer" => Some(Cell::Integer("0".into())),
363            "Float" => Some(Cell::Float("0.0".into())),
364            "String" => Some(Cell::Str("".into())),
365            "Boolean" => Some(Cell::Boolean(true)),
366            "Assignment" => Some(Cell::Assignment),
367            "Comparison" => Some(Cell::Comparison(ComparisonOp::Equal)),
368            "Arithmetic" => Some(Cell::Arithmetic(ArithmeticOp::Add)),
369            "If" => Some(Cell::If),
370            "Else" => Some(Cell::Else),
371            "Palette Color" => Some(Cell::PaletteColor(0)),
372            "Value" => Some(Cell::Value("1".to_string())),
373
374            "action" => Some(Cell::Action),
375            "add_item" => Some(Cell::AddItem),
376            "block_events" => Some(Cell::BlockEvents),
377            "cast_spell" => Some(Cell::CastSpell),
378            "clear_audio" => Some(Cell::ClearAudio),
379            "clear_target" => Some(Cell::ClearTarget),
380            "close_in" => Some(Cell::CloseIn),
381            "deal_damage" => Some(Cell::DealDamage),
382            "drop" => Some(Cell::Drop),
383            "drop_items" => Some(Cell::DropItems),
384            "entities_in_radius" => Some(Cell::EntitiesInRadius),
385            "equip" => Some(Cell::Equip),
386            "get_attr" => Some(Cell::GetAttr),
387            "get_attr_of" => Some(Cell::GetAttrOf),
388            "goto" => Some(Cell::Goto),
389            "id" => Some(Cell::Id),
390            "intent" => Some(Cell::Intent),
391            "inventory_items" => Some(Cell::InventoryItems),
392            "inventory_items_of" => Some(Cell::InventoryItemsOf),
393            "message" => Some(Cell::Message),
394            "say" => Some(Cell::Say),
395            "notify_in" => Some(Cell::NotifyIn),
396            "offer_inventory" => Some(Cell::OfferInventory),
397            "patrol" => Some(Cell::Patrol),
398            "play_audio" => Some(Cell::PlayAudio),
399            "random" => Some(Cell::Random),
400            "random_walk" => Some(Cell::RandomWalk),
401            "random_walk_in_sector" => Some(Cell::RandomWalkInSector),
402            "set_attr" => Some(Cell::SetAttr),
403            "set_audio_bus_volume" => Some(Cell::SetAudioBusVolume),
404            "set_emit_light" => Some(Cell::SetEmitLight),
405            "set_player_camera" => Some(Cell::SetPlayerCamera),
406            "set_proximity_tracking" => Some(Cell::SetProximityTracking),
407            "set_target" => Some(Cell::SetTarget),
408            "set_tile" => Some(Cell::SetTile),
409            "take" => Some(Cell::Take),
410            "target" => Some(Cell::Target),
411            "has_target" => Some(Cell::HasTarget),
412            "teleport" => Some(Cell::Teleport),
413            "toggle_attr" => Some(Cell::ToggleAttr),
414            "took_damage" => Some(Cell::TookDamage),
415
416            "abs" => Some(Cell::Abs),
417            "atan" => Some(Cell::Atan),
418            "atan2" => Some(Cell::Atan2),
419            "ceil" => Some(Cell::Ceil),
420            "clamp" => Some(Cell::Clamp),
421            "cos" => Some(Cell::Cos),
422            "cross" => Some(Cell::Cross),
423            "degrees" => Some(Cell::Degrees),
424            "dot" => Some(Cell::Dot),
425            "exp" => Some(Cell::Exp),
426            "floor" => Some(Cell::Floor),
427            "fract" => Some(Cell::Fract),
428            "length" => Some(Cell::Length),
429            "log" => Some(Cell::Log),
430            "max" => Some(Cell::Max),
431            "min" => Some(Cell::Min),
432            "mix" => Some(Cell::Mix),
433            "mod" => Some(Cell::Mod),
434            "normalize" => Some(Cell::Normalize),
435            "pow" => Some(Cell::Pow),
436            "radians" => Some(Cell::Radians),
437            "rand" => Some(Cell::Rand),
438            "rotate2d" => Some(Cell::Rotate2d),
439            "sample" => Some(Cell::Sample),
440            "sample_normal" => Some(Cell::SampleNormal),
441            "textures" => Some(Cell::Textures("value".into())),
442            "sign" => Some(Cell::Sign),
443            "sin" => Some(Cell::Sin),
444            "smoothstep" => Some(Cell::Smoothstep),
445            "sqrt" => Some(Cell::Sqrt),
446            "step" => Some(Cell::Step),
447            "tan" => Some(Cell::Tan),
448
449            _ => None,
450        }
451    }
452
453    pub fn to_string(&self) -> String {
454        match &self {
455            Variable(var_name) => {
456                if var_name == "myself" {
457                    "id()".to_string()
458                } else {
459                    var_name.clone()
460                }
461            }
462            Integer(value) | Float(value) => value.clone(),
463            Boolean(value) => {
464                if *value {
465                    "true".into()
466                } else {
467                    "false".into()
468                }
469            }
470            Str(value) => {
471                if value.contains("\"") {
472                    value.clone()
473                } else {
474                    format!("\"{}\"", value)
475                }
476            }
477            PaletteColor(idx) => {
478                format!("palette({})", idx)
479            }
480            Value(value) => value.clone(),
481
482            Assignment => "=".into(),
483            Comparison(op) => op.to_string().to_string(),
484            Arithmetic(op) => op.to_string().to_string(),
485            If => "if".into(),
486            Else => "else".into(),
487
488            Action => "action".into(),
489            AddItem => "add_item".into(),
490            BlockEvents => "block_events".into(),
491            CastSpell => "cast_spell".into(),
492            ClearAudio => "clear_audio".into(),
493            ClearTarget => "clear_target".into(),
494            CloseIn => "close_in".into(),
495            DealDamage => "deal_damage".into(),
496            Drop => "drop".into(),
497            DropItems => "drop_items".into(),
498            EntitiesInRadius => "entities_in_radius".into(),
499            Equip => "equip".into(),
500            GetAttr => "get_attr".into(),
501            GetAttrOf => "get_attr_of".into(),
502            Goto => "goto".into(),
503            Id => "id".into(),
504            Intent => "intent".into(),
505            InventoryItems => "inventory_items".into(),
506            InventoryItemsOf => "inventory_items_of".into(),
507            Message => "message".into(),
508            Say => "say".into(),
509            NotifyIn => "notify_in".into(),
510            OfferInventory => "offer_inventory".into(),
511            Patrol => "patrol".into(),
512            PlayAudio => "play_audio".into(),
513            Random => "random".into(),
514            RandomWalk => "random_walk".into(),
515            RandomWalkInSector => "random_walk_in_sector".into(),
516            SetAttr => "set_attr".into(),
517            SetAudioBusVolume => "set_audio_bus_volume".into(),
518            SetEmitLight => "set_emit_light".into(),
519            SetPlayerCamera => "set_player_camera".into(),
520            SetProximityTracking => "set_proximity_tracking".into(),
521            SetTarget => "set_target".into(),
522            SetTile => "set_tile".into(),
523            Take => "take".into(),
524            Target => "target".into(),
525            HasTarget => "has_target".into(),
526            Teleport => "teleport".into(),
527            ToggleAttr => "toggle_attr".into(),
528            TookDamage => "took_damage".into(),
529
530            Abs => "abs".into(),
531            Atan => "atan".into(),
532            Atan2 => "atan2".into(),
533            Ceil => "ceil".into(),
534            Clamp => "clamp".into(),
535            Cos => "cos".into(),
536            Cross => "cross".into(),
537            Degrees => "degrees".into(),
538            Dot => "dot".into(),
539            Exp => "exp".into(),
540            Floor => "floor".into(),
541            Fract => "fract".into(),
542            Length => "length".into(),
543            Log => "log".into(),
544            Max => "max".into(),
545            Min => "min".into(),
546            Mix => "mix".into(),
547            Mod => "mod".into(),
548            Normalize => "normalize".into(),
549            Pow => "pow".into(),
550            Radians => "radians".into(),
551            Rand => "rand".into(),
552            Rotate2d => "rotate2d".into(),
553            Sample => "sample".into(),
554            SampleNormal => "sample_normal".into(),
555            Textures(name) => format!("\"{}\"", name),
556            Sign => "sign".into(),
557            Sin => "sin".into(),
558            Smoothstep => "smoothstep".into(),
559            Sqrt => "sqrt".into(),
560            Step => "step".into(),
561            Tan => "tan".into(),
562
563            LeftParent => "(".into(),
564            RightParent => ")".into(),
565            _ => "".into(),
566        }
567    }
568
569    pub fn status(&self) -> String {
570        match &self {
571            Action => "Player based action.".into(),
572            AddItem => "Add an item to the inventory of the current entity.".into(),
573            BlockEvents => "Block specific events for a period of in-game minutes for the current entity or item.".into(),
574            CastSpell => "Cast a spell template towards a target entity or position: cast_spell(template, target[, success_pct]).".into(),
575            ClearAudio => "Stop currently playing audio on a bus, or all buses if omitted.".into(),
576            ClearTarget => "Clear current target for the current entity or item.".into(),
577            CloseIn => "Close in to the target entities within the given radius and speed.".into(),
578            DealDamage => "Deal damage. Use deal_damage(amount) for current target, or deal_damage(target, amount).".into(),
579            Drop => "Drop the item of the given ID for the current entity.".into(),
580            DropItems => "Drop all or filtered items for the current entity.".into(),
581            EntitiesInRadius => {
582                "Returns a list of entity IDs in the radius of the current entity or item.".into()
583            }
584            GetAttr => "Get an attribute of the current entity or item.".into(),
585            GetAttrOf => "Get an attribute of the given entity or item.".into(),
586            Goto => "Go to a sector using pathfinding.".into(),
587            Id => "Returns the ID of the current entity or item.".into(),
588            Intent=> "Player intent. Only applicable during for user events.".into(),
589            InventoryItems => {
590                "Returns a list of item IDs of the inventory of the current entity.".into()
591            }
592            InventoryItemsOf => "Returns a list of item IDs of the item with the given ID.".into(),
593            Message => "Send a message to an entity.".into(),
594            Say => "Display speech above an entity in the game view (optional category).".into(),
595            NotifyIn => "Send the given event after the given amount of in-game minutes.".into(),
596            OfferInventory => "Offer the inventory for sale to the given entity.".into(),
597            Patrol => "Patrol using attributes.route (patrol(wait, speed)).".into(),
598            PlayAudio => "Play an audio asset: play_audio(name, bus, gain, looping).".into(),
599            Random => "Generate a random number within an open range.".into(),
600            RandomWalk => "Randomly walk.".into(),
601            RandomWalkInSector => "Randomly walk in the entities current sector.".into(),
602            SetAttr => "Set an attribute of the current entity or item.".into(),
603            SetAudioBusVolume => "Set volume for an audio bus.".into(),
604            SetEmitLight => "Set the light emission state of the current entity or item.".into(),
605            SetPlayerCamera => {
606                "Sets the player camera: '2d', 'iso' or 'firstp'.".into()
607            }
608            SetProximityTracking => {
609                "Enable / disable tracking of entities for the current entity or item.".into()
610            }
611            SetTarget => "Set current target entity ID for the current entity or item.".into(),
612            SetTile => "Set the tile ID for the current entity or item.".into(),
613            Take => "Take the item with the given ID.".into(),
614            Target => "Get current target entity ID.".into(),
615            HasTarget => "Returns true if a valid current target is set.".into(),
616            Teleport => "Teleport to a sector. Optionally in another region.".into(),
617            ToggleAttr => "Toggles a boolean attribute of the current entity or item.".into(),
618            TookDamage => "Takes damage.".into(),
619
620            Abs => "Absolute value of x.".into(),
621            Atan => "Arc tangent of y/x (single-arg).".into(),
622            Atan2 => "Arc tangent of y/x using signs of both to determine quadrant.".into(),
623            Ceil => "Ceiling: round x up to the next integer.".into(),
624            Clamp => "Clamp x to the range [min, max].".into(),
625            Cos => "Cosine of angle (radians).".into(),
626            Cross => "3D cross product.".into(),
627            Degrees => "Convert radians to degrees.".into(),
628            Dot => "Dot product.".into(),
629            Exp => "Exponential e^x.".into(),
630            Floor => "Floor: round x down to the previous integer.".into(),
631            Fract => "Fractional part of x.".into(),
632            Length => "Vector length / magnitude.".into(),
633            Log => "Natural logarithm.".into(),
634            Max => "Component-wise maximum of x and y.".into(),
635            Min => "Component-wise minimum of x and y.".into(),
636            Mix => "Linear interpolation: mix(a, b, t).".into(),
637            Mod => "Remainder of x/y with sign of x.".into(),
638            Normalize => "Normalize a vector to unit length.".into(),
639            Pow => "Power: x^y.".into(),
640            Radians => "Convert degrees to radians.".into(),
641            Rand => "Random number in [0,1).".into(),
642            Rotate2d => "Rotate a 2D vector by an angle (in degrees).".into(),
643            Sign => "Sign of x (-1, 0, or 1) component-wise.".into(),
644            Sin => "Sine of angle (radians).".into(),
645            Smoothstep => "Hermite smooth interpolation between edge0 and edge1.".into(),
646            Sqrt => "Square root.".into(),
647            Step => "Step function: 0 if x < edge, else 1.".into(),
648            Tan => "Tangent of angle (radians).".into(),
649            Sample => "Sample a noise or pattern texture.".into(),
650            SampleNormal => "Sample the normal of a noise or pattern texture.".into(),
651
652            _ => "".into(),
653        }
654    }
655
656    pub fn role(&self) -> CellRole {
657        match &self {
658            Variable(_) | Integer(_) | Float(_) | Str(_) | Boolean(_) | Textures(_) | Value(_)
659            | PaletteColor(_) => CellRole::Value,
660            Assignment | Comparison(_) | If | Else | Arithmetic(_) => CellRole::Operator,
661            Empty => CellRole::None,
662
663            _ => CellRole::Function,
664        }
665    }
666}