diff --git a/docs/codeblocks/action.md b/docs/codeblocks/action.md new file mode 100644 index 0000000..65c97bf --- /dev/null +++ b/docs/codeblocks/action.md @@ -0,0 +1,103 @@ +## Syntax +Action syntax is as follows: +```tc +target:Action(arguments){tags}; +``` + +### Arguments + +Arguments are values seperated by commas. Arguments with no value are converted to empty slots. +```tc +default:SendMessage("Hello","world!"); +default:SendMessage( ,"Slot 2 string", , ,"Slot 5 string"); +``` + +### Tags + +Tag syntax can be thought of as a dictionary: +```tc +default:SendMessage("Tags!"){"Alignment Mode" = "Centered", "Inherit Styles" = "True"}; +``` +To use a variable as the tag value, a default must be provided immediately after: +```tc +default:SendMessage("Tags!"){"Alignment Mode" = global messageMode ? "Centered"}; +``` +If you are using the vscode extension, you can use the autocomplete shortcut (`ctrl+space` by default) to quickly insert tag names and values. + +Arguments and tags are both optional and can be left out, making all of these valid action calls: +```tc +default:StopSounds(snd["Pling"]); +default:StopSounds{"Sound Source" = "Jukebox/Note Blocks"}; +default:StopSounds; +``` + +## Player Actions + +Player actions use the following targets: + +- `default` +- `killer` +- `damager` +- `shooter` +- `victim` +- `allPlayers` +- `selection` + +```tc title="Examples" +default:GivePotionEffect(pot["Saturation"]){"Effect Particles" = "None", "Overwrite Effect" = "False"}; + +default:SetVisualShoulderParrot{"Shoulder" = "Left", "Type" = "Cyan"}; + +allPlayers:SendMessage(s"%defaulthas joined!"); + +selection:SetToCreativeMode; + +victim:Heal(game.EventDamage/2); + +shooter:GiveItems(item["Arrow"]); +``` + + +## Entity Actions + +Entity actions use the following targets: + +- `selectionEntity` +- `defaultEntity` +- `killerEntity` +- `damagerEntity` +- `shooterEntity` +- `victimEntity` +- `allEntities` +- `allMobs` +- `projectile` +- `lastEntity` + +```tc title="Examples" +defaultEntity:Teleport(default.Location + vec[0,10,0]); + +defaultEntity:EatGrass; + +selectionEntity:Damage(5); + +projectile:SetArrowNoClip{"Has NoClip" = "Enable"}; + +allMobs:FaceLocation(default.Location) + +lastEntity:SetTag("owner","%default"); +``` + +## Game Actions + +Game actions use the `game` target. + +```tc title="Examples" +game:SpawnMob(item["zombie_spawn_egg"],game.EventBlockLocation); + +game:CancelEvent; + +game:SummonLightning(victim.Location); + +game:SetBlock(loc[10,50,10],item["beacon"]); +``` + diff --git a/docs/codeblocks/set_var.md b/docs/codeblocks/set_var.md new file mode 100644 index 0000000..9f3fa12 --- /dev/null +++ b/docs/codeblocks/set_var.md @@ -0,0 +1 @@ +Math operations can be done much easier by using [Expressions](../language_features/expressions.md). You should only do math via setvar actions when you want absolute control over the template's codeblocks, otherwise its easier to let the compilier handle it for you. \ No newline at end of file diff --git a/docs/dingus.md b/docs/dingus.md new file mode 100644 index 0000000..d2010c1 --- /dev/null +++ b/docs/dingus.md @@ -0,0 +1,3 @@ +# Dignus + +## oh great heavens \ No newline at end of file diff --git a/docs/getting_started/installation.md b/docs/getting_started/installation.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/getting_started/plot_setup.md b/docs/getting_started/plot_setup.md new file mode 100644 index 0000000..35dfa84 --- /dev/null +++ b/docs/getting_started/plot_setup.md @@ -0,0 +1,44 @@ +# Plot Setup + +If you haven't already installed the VSCode extension and CodeUtils, see [Installation](/getting_started/installation.md) + +!!! warning "Don't delete your code!" + Always make sure to start with an empty plot. Never run terracotta on plots made using normal DiamondFire coding because there is no way to recover code terracotta may overwrite. + +## Creating a Project +First, create a project folder to hold all your plot's code and open it in VSCode. Then from the Run and Debug menu, click `create a launch.json file` and select `Terracotta` from the list of langauges. In the newly created `launch.json` file, make sure to set `plotSize` appropriately for the plot you will be compiling to. + +Plot Type | Plot Size +- | - +Basic | `50` +Large | `100` +Massive | `300` +Mega | `300` + +??? info "All `launch.json` parameter explanations" + - `folder`: The folder to compile. Pretty self-explanatory. + - `exportMode`: Can be either `"sendToCodeClient"` or `"saveToFiles"` + - `"sendToCodeClient"`: When running, automatically place compiled templates via CodeClient + - `"saveToFiles"`: (CURRENTLY UNIMPLEMENTED!) When running, save all compiled templates to files + - `autoSwitchToDev`: If in play or build mode upon compiling, automatically enter dev mode. If left disabled, trying to compile while in build or play mode will fail. Only applies if `exportMode` is `"sendToCodeClient"`. + - `autoSwitchToPlay`: Automatically enter play mode after all compiled templates have been placed. + - `plotSize`: Used by the codeline splitter to know what length templates should be limited to. If you want to "disable" the codeline splitter, just set this to a very high number. + +## Compiling a Project +Terracotta script files have the extension `.tc`. Create a script in your project folder to test with: + +``` tc title="test.tc" +PLAYER_EVENT Join; + +default:SendMessage("Hello world!"); +``` + +In your Minecraft client, run the command `/auth`. This gives Terracotta permission to manipulate your plot using CodeClient. You will need to do this every time you restart either Minecraft or VSCode, but not every time you compile. + +Once all that's complete, press f5 or click the green play symbol at the top of Run and Debug to compile your plot. + +!!! warning + Sometimes CodeClient will give up while trying to place code. If this happens, run `/abort` in your Minecraft client and try recompiling. + + If you find yourself getting stuck in a plot border, run `/worldplot `. + diff --git a/docs/getting_started/syntax_guide.md b/docs/getting_started/syntax_guide.md new file mode 100644 index 0000000..af34398 --- /dev/null +++ b/docs/getting_started/syntax_guide.md @@ -0,0 +1,5 @@ +TODO + +semicolons + +non whitespace signifigant \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index 147745d..3e19dc6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,152 +1,26 @@ -this is obviously heavily work in progress +# Terracotta -# very good and awesome documentation +[DiamondFire](https://www.mcdiamondfire.com) is a Minecraft server where you can make your own minigames using block code. -# THIS CHANGE IS DEPLOYED VIA GITHUB ACTIONS! +I do not like block code. -```tc -FUNCTION numbergame; +Terracotta is a text-based programming language that compiles to DiamondFire templates with the goal of *actually* making plot development easier. Unlike previous text-to-df languages, Terracotta makes no compromises when it comes to functionality or convenience. Everything you can do with DiamondFire blocks is just as easy or easier in Terracotta. -"\u{13487137887} dingus \n akjshdg" +To get started, visit [Installation Guide]() and [Plot Setup](getting_started/plot_setup.md) -dict:Get:num; +## Why Terracotta is awesome -line i: num = saved ["%default number"]; +- Expressions. Almost anywhere you can put a value in Terracotta, you can write an expression. You never have to think about %math again! -default:SendMessage("The number game!! compiled with terracotta"); +- Automatic codeline splitting. Codelines that are too long for your plot will be automatically split into +multiple functions. -repeat Forever { - line i += 1; - line rainbowIndex += 1; +- Human-compatable syntax. Terracotta looks and feels like an actual programming language, not like bytecode. - line timeUnit = "Seconds"; - default:SendActionBar(s"The number: " + line i); +- Intellisense/autocomplete support. Remembering specific names of actions sucks, so you can get autocomplete to do it for you. Also supports completion of variable names, function names, action tags, potion effect ids, etc. - if (default ? IsSprinting) { - line rngResult = num:Random(1, 20); +- Compiled code templates are placed automatically. Going from Terracotta code to a playable plot is as easy as pressing `f5`. (thanks CodeClient!) - #fish mode - if (default ? IsSwimming) { - #increase the number EVEN FASTER! - line i += 12345678912345; +- Only code templates that actually changed will be re-placed, making Terracotta usable for large plots. - default:SetRemainingAir(line rngResult * 30); - - line msg = txt:ParseExpression("" + "!"*line rngResult + " FISHMODE!!!!!! " + line i + " " + "!"*line rngResult); - } - #normal sprint mode - else { - line msg = txt:ParseExpression("" + "!"*line rngResult + " The number: " + line i + " " + "!"*line rngResult); - } - - default:SendActionBar(line msg: txt); - - line timeUnit = "Ticks"; #FAST - } - - if (default ? IsSneaking) { - default:PlaySound(snd["Anvil Land"]); - default:SendActionBar(s"You have killed the loop!!! How dare you"); - break; - } - - if (line i < 0) { - line rngResult = num:Random(1, 200); - line msg = txt:ParseExpression("" + "!"*line rngResult + " what have you done... <#FF0000>" + line i + " " + "!"*line rngResult); - default:SendActionBar(line msg: txt); - } - - saved ["%default number"] = line i; - - #reset code - if (default ? IsStandingOnBlock("nether_wart_block")) { - #launching code - default:LaunchTowardLocation(loc:Align(default.Location - vec[0,1,0]), -100); - default:GivePotionEffect(pot["Slow Falling",1,2 * 20]); - - if (line i < 0) { - default:SendActionBar("&c&lFIRST, FIX YOUR MISTAKES"); - line timeUnit = "Seconds"; - } else { - line i = 0; - default:SendMessage("You have been reset"); - default:SendActionBar; #clear action bar - } - } - - wait(1){"Time Unit" = line timeUnit ? "Seconds"}; -} -``` - -```tc -#100% accurate nether gen open sourced???? -LAGSLAYER_CANCEL; PLAYER_EVENT Join; - -default:SetToCreativeMode; - -#var declarations -saved netherSpawnLoc: loc; -call setupVars; - - -# fake loading screen -local loadTime = 3*20; - -default:SendTitle("&aGenerating...","real not clickbait",local loadTime); -default:GivePotionEffect(pot["Mining Fatigue",255,4*20]){"Show Icon" = "False","Effect Particles" = "None"}; -default:GivePotionEffect(pot["Invisibility",255,4*20]){"Show Icon" = "False","Effect Particles" = "None"}; -default:GivePotionEffect(pot["Blindness",1,4*20]){"Show Icon" = "False","Effect Particles" = "None"}; -start loadLoop; - -#teleport to nether -wait(0.5*20); -default:Teleport(global overworldPortalLoc); - -wait(5); - -#teleport to spawn -wait(2*20); #wait until player has been shoved back into plot bounds to avoid messing with getNetherLoc() -call getNetherLoc(line shiftedLoc, global netherSpawnLoc); -default:Teleport(line shiftedLoc); -default:SendTitle("",""); - -default:SetToAdventureMode; -default:SetAllowFlight{"Allow Flight" = "Enable"}; -default:GivePotionEffect(pot["Fire Resistance"]){"Effect Particles" = "None","Show Icon" = "False"}; - -wait(5); - -start interactionEntity; - -line poweredByLoc: loc; -call getNetherLoc(line poweredByLoc, loc[345,84,338]); -global hasSpawnedEntities = 1; -game:SpawnTextDisplay(line poweredByLoc,"POWERED BY:"); -lastEntity:SetDisplayScale(5,5,5); -lastEntity:SetDisplayBillboard{"Billboard Type" = "Fixed"}; -lastEntity:SetTextDisplayBackground("#000000",0); -lastEntity:SetTextDisplayTextShadow{"Text Shadow" = "Disable"}; -lastEntity:SetDisplayRotationFromEulerAngles(0,180,0); -lastEntity:SetDisplayBrightness(15,15); -``` - - -```tc -FUNCTION DispText; -PARAM text: txt; -PARAM spawnAt: loc; -PARAM size: optional plural any = vec[1,1,1];; - -if (var?IsType(line size){"Variable Type" = "Number"}) { - line size = vec[line size,line size,line size]; -} - - -game:SpawnTextDisplay(line spawnAt,line text); -lastEntity:SetDisplayScale(line size); -lastEntity:SetDisplayRotationFromEulerAngles(loc:GetCoordinate(line spawnAt){"Coordinate" = "Pitch"},loc:GetCoordinate(line spawnAt){"Coordinate" = "Yaw"},0); -lastEntity:SetTextDisplayBackground("#000000",0); -lastEntity:SetTextDisplayTextShadow{"Text Shadow" = "Disable"}; -lastEntity:SetDisplayBillboard{"Billboard Type" = "Fixed"}; -lastEntity:SetTextDisplayLineWidth(3785); -``` \ No newline at end of file +And of course, being a text based programming language, you get all sorts of nice things you don't get through normal DiamondFire like comments, copy+paste, easily readable code, etc. \ No newline at end of file diff --git a/docs/language_features/expressions.md b/docs/language_features/expressions.md new file mode 100644 index 0000000..c67e37e --- /dev/null +++ b/docs/language_features/expressions.md @@ -0,0 +1,169 @@ +# Expressions + +For uses of the Set Variable block not covered by the operators listed below, see [Set Variable](../codeblocks/set_var.md) + +You can write an expression *almost* anywhere you can put a value. + +```tc title="Examples" +line reward = num:Round(game.PlayerCount * global coinBonus * (global ["%default killstreak"] + 10)); + +default:Teleport(default.Location + (default.Direction * global ["%default teleportRange"])); + +default:GivePotionEffect(pot["Speed", 1, (10*20) + num:Random(0,global maxPotionBonus)]); +``` + +## Value Operators + +!!! info + Many operators work on more types of code items than just numbers. For more info on which operators work with which code items, check out the code items' respecitve pages under the Code Items category. + +Terracotta supports the following operators: + + - `+` - Addition + - `-` - Subtraction + - `*` - Multiplication + - `/` - Division + - `^` - Exponentiation + - `%` - Modulo + +Operations between constants are evaluated at compile-time, meaning you can use them safely for convenience without having to worry about using CPU. In the below example, `5 * 20` is directly added to the template as the number `100` and never creates any codeblocks. This applies to all code items, not just numbers. + +```tc +wait(5 * 20){"Time Unit" = "Ticks"}; +``` + +## Inlined Functions +Any function that returns a value can be used in expressions. Some actions like Set Location Coordinate don't have a return value listed in their description, still return a value anyway. Generally, if an action has `Variable - Variable to set` as its first parameter, it can be inlined. + +Custom functions cannot be inlined yet as they cannot specify return types, however this functionality will be added in a future update. + +```tc title="Examples" +default:SendMessage("You rolled a " + num:Random(1,6) + "!"); + +default:GiveItems(item[var:SetToRandom("cooked_porkchop","cooked_beef","golden_carrot"),16]); +``` + +## Incrementors +Incrementors do an operation to a variable without having to write out `variablename = variablename `. + +```tc title="Incremetors" +global added += 10; +global subtracted -= 2389; +global multiplied *= 100; +global divided /= 10; +global exponented ^= 3; +global moduloed %= 2; +``` + +## Type Overrides +Terracotta has some type inference built in, so for many situations (especially those involving numbers or variables that are declared inside the file you're working in) you won't have to worry about types. Sometimes though, the type of a value is unknown and must be specified manually in order to use it with operations. This can be done by adding `: ` after the value. + +In the below case, `spawnLocation`'s type is unknown. For the compilier to know what to do when adding the vector to it, you have to manually specify that it's a location. +```tc +default:Teleport(global spawnLocation: loc + vec[1,10,1]); +``` + + +Specifying the type of a variable every time you use it would suck, so you can also assign a type to variables outside of expressions +```tc +global spawnLocation: loc; + +# compilier now knows for both of these lines that `spawnLocation` is a location +default:Teleport(global spawnLocation + vec[0,10,0]); +wait(1){"Time Unit" = "Seconds"}; +default:Teleport(global spawnLocation + vec[0,20,0]); +``` + + +Type overrides can also be applied to indexing operations and actions/functions that return multiple types. + +```tc +default:Teleport(global spawnLocationDict["main"]: loc + vec[0,10,0]); + +line newTag = item:GetTag(global item,"cooltagname"): num + 10; +``` + + +## Indexing Operation + +Values in lists and dicts can be accessed via square bracket syntax from within expressions. + +```tc +line dict = { + "very awesome key" = "even more awesome value" +}; +default:SendMessage(line dict["very awesome key"]); + +line list = [1,2,"buckle my shoe"]; +default:SendMessage(line list[3]); +``` + +!!! warning + Even though you *can* easily do the same index operation in multiple places, it's not recommended. Every index operation creates more codeblocks, which uses more CPU. For this reason, if you know a value is not going to change, it's best to only index once and store the result in a variable. + + ```tc title="Bad" + global locations = { + "spawn" = loc[10,50,10] + }; + + default:SendMessage("Teleporting to location", global locations["spawn"]); + default:Teleport(global locations["spawn"]); + ``` + + ```tc title="Good" + global locations = { + "spawn" = loc[10,50,10] + }; + + line selectedLocation = global locations["spawn"] + + default:SendMessage("Teleporting to location", line selectedLocation); + default:Teleport(line selectedLocation); + ``` + + It's true that the above example is a bit unnecessary, but in loops or when using indexing operations that treverse multiple levels the saved CPU can really add up. + +Indexes can themselves be expressions +```tc +line scores = [23,925,78,873]; +default:SendMessage(line teamScores[num:Random(1,4)]); + +line teams = { + "red" = { + "points" = 12 + }, + "blue" = { + "points" = 15 + } +}; +line teamData = line teams[var:SetToRandom("red","blue")]; +``` + +If the type of a value is unknown, it must be manually specified in order to index into it. The indexing operation can appear directly after the type override; no extra parentheses are needed. +```tc +default:SendMessage(global dict_declared_elsewhere: dict["cool_key"]); +default:SendMessage(global list_declared_elsewhere: list[5]); +``` + +Multiple levels can be traversed, however you will have to manually specify the type of each level. +```tc +line gameState = { + "redTeam" = { + "unlocks" = ["damageBoost","healthBoost"] + } +}; + +line firstUnlock = line gameState["redTeam"]:dict["unlocks"]:list[1]; +``` + +## Order of Operations + +Unlike a certain expression system used by DiamondFire that **shall not be named**, Terracotta expressions follow a sane order of operations. + +Things closer to the top of the list are evaluated before things closer to the bottom. Things on the same line are evaluated left-to-right with the same priority. + +- Nested expressions (parentheses), indexing into dicts/lists, and function calls (actions, constructors) +- Exponentiation (`^`) +- Multiplication, division, and modulo (`*`, `/`, `^`) +- Addition and subtraction (`+`, `-`) +- Comparisons (`==`, `!=`, `<`, `>`, `<=`, `>=`) \ No newline at end of file diff --git a/docs/style.css b/docs/style.css index e0aa184..0506f84 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,61 +1,61 @@ -.nn { +.highlight .nn { color: #B1D7E0; } -.nf { +.highlight .nf { color: #FDFBAC; } -.o { +.highlight .o { color: #4CFFFF; } -.pp { +.highlight .pp { color: #8888FF; } -.s { +.highlight .s { color: #ADF195; } -.k { +.highlight .k { color: #F86D7C; font-weight: bold; } -.kd { +.highlight .kd { color: #F86DA7; font-weight: bold; } -.ks { +.highlight .ks { color: #CCAAFF; } -.nv { +.highlight .nv { color: #CCCCCC; } -.err { +.highlight .err { color: #CCCCCC; } -.nc { +.highlight .nc { color: #84D6FF; } -.m { +.highlight .m { color: #FFC600 } -.c { +.highlight .c { color: #777777; } -.py { +.highlight .py { color: #61A2F1; } -.se { +.highlight .se { color: #89DDFF } \ No newline at end of file diff --git a/docs/test.md b/docs/test.md new file mode 100644 index 0000000..7c83b8e --- /dev/null +++ b/docs/test.md @@ -0,0 +1,5 @@ +## dingus +yes + +## dongus +YERS \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index d30fd91..665fd6a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,33 +1,54 @@ site_name: Terracotta +site_url: https://mrawesomeowl.github.io/terracotta-docs/ docs_dir: docs theme: name: material features: - - navigation.tabs - - navigation.sections - - toc.integrate - - navigation.top + # - navigation.sections + - navigation.path - search.suggest - search.highlight - content.tabs.link - content.code.annotation - content.code.copy + - navigation.instant + - navigation.instant.prefetch + - navigation.instant.progress + - navigation.indexes + - navigation.expand + - content.code.annotate language: en palette: - scheme: slate primary: teal accent: deep-orange markdown_extensions: - - codehilite + # - codehilite - toc: permalink: true + title: Table of Contents - pymdownx.highlight: anchor_linenums: true line_spans: __span pygments_lang_class: true - pymdownx.inlinehilite - pymdownx.snippets + - admonition + - pymdownx.details + - pymdownx.superfences + - tables + - attr_list + - md_in_html nav: - - Home: index.md + - About: index.md + - Getting Started: + - Installation: getting_started/installation.md + - Plot Setup: getting_started/plot_setup.md + - Syntax Guide: getting_started/syntax_guide.md + - Language Features: + - Expressions (math): language_features/expressions.md + - Code Blocks: + - Action: codeblocks/action.md + - Set Variable: codeblocks/set_var.md extra_css: - style.css \ No newline at end of file diff --git a/terracotta_lexer/terracotta.py b/terracotta_lexer/terracotta.py index 03e3b86..ef51e1e 100644 --- a/terracotta_lexer/terracotta.py +++ b/terracotta_lexer/terracotta.py @@ -75,7 +75,7 @@ class TerracottaLexer(RegexLexer): (r'(:\s*)(\w+)',byGroup(Operator,Name.Class)), #operators - (r'[=*+-/:?<>%]|!=',Operator), + (r'[=*+-/:?<>%^]|!=',Operator), #color types names as type names on their own if nothing else has claimed them already (r'(?:(?<=\W)|^)(str|num|vec|loc|pot|snd|txt|item|list|dict|par|any)(?![\\w])',Name.Class),