• 0

    posted a message on [Data] The Uberlisk

    @DrSuperEvil: Go

    Pretty sure I did the supporter stuff right. Wasn't sure if the :: was necessary but tried with and without and it didn't make a difference.

    The sphere doesn't move along the ground, it moves the same way the tip of the spine crawler would.. it launches itself directly at the target then follows an upward curve back into position.

    Posted in: Tutorials
  • 0

    posted a message on [Data] The Uberlisk

    @DrSuperEvil: Go

    The beam was set to SpineL1Beam. I set them to blank for all the spines. Still no luck.

    I double checked on the effect I have the ammo unit set to my Missile - Impaler Tentacle X unit (L1, L2, etc) and those units do exist.
    In the Spine X Missile actors, I have the token - unit name set to Missile - Impaler Tentacle X, I checked that the model is set to invisible, and I have the refset event defined as such:

    MotionPhaseStart
    - Term: MotionPhase, Index: 0
    - Msg Type: Reference Set
    - - Target = ::Supporter
    - - Reference Name = Custom (SpineL1Tentacle)
    - - Reference Source = System (Self)

    In the Spine Attack X I have Launch effect set to Impaler Tentacle X Missile and I set the beam to blank as you said. Launch site is my Spine X Site, which has the ActorCreation.SpineX - Create and ActorDestruction.SpineX - Destroy events and has Host+ set to SpineX and HostSiteOps+ set to SOpAttachHardPoint.

    Can't think of anything else too relevant. Still getting the same unable to create unit actor errors and seeing spheres being tossed.

    Posted in: Tutorials
  • 0

    posted a message on [Data] The Uberlisk

    Tried looking over my missiles.. effects.. units.. tokens. My tentacles are just throwing the default model sphere at things rather than stretching out. There's an error:

    Scope[ImpalerTentacleL1, Unit] Unable to create unit actor. Creating fallback sphere unit.

    If I change the ammo to something else, like the peanut, then it throws peanuts. No more error. Can't get them to stretch though. Any idea?

    Posted in: Tutorials
  • 0

    posted a message on Piercing Line AOE - Need Help With Splat and Visuals/Audio

    @DrSuperEvil: Go

    So I got rid of my local offset SOp and made a Site SOp like the Hellion's and I made my beam's events like the hellions using the same effects and the effectexecuteindex term (which I set to 32 since mine has 32 periods max), and I made my search, damage, and persistent effects use the same location fields as those that the hellion effects use (no idea what the location field does but it seemed like it'd matter).

    At this point everything still worked but now my beam wasn't visible at all.

    Then I copied the hellion's action and changed the beam to my beam and changed the events to use my effects and reset the impact and damage maps to default.. which I'm guessing would make them do nothing since I didn't have anything with the default IDs set.

    After that my beam was moving from my weapon to the first target.. which seemed right at first, but as Raynor moved his weapon to stand, the beam moved with it instead of staying in place. And it's really only moving to the first target it's not moving to the full length of the shot. If the target is in the air, it shoots up into the air rather than straight. If there's no target, the beam doesn't shoot at all.

    So I'm back to having no clue what I'm doing. :)

    Still fiddling with it. I imagine that for the source I need to use the point the attachment is at when it's created, not actually the attachment point. And for the target I imagine I need the final point .. somehow

    Posted in: Data
  • 0

    posted a message on (solved)Sound of ability must play from point where effect applyed

    @Form01: Go

    I believe in the sound actor's events you just need to add the term At Target

    For instance I have a sound actor (Piercing Round Impact Sound) for when my ability hits a target. It has these events:

    SoundDone
    - Destroy

    Effect.PiercingRoundDamage.Start
    -> At Target
    - Create

    Posted in: Data
  • 0

    posted a message on Piercing Line AOE - Need Help With Splat and Visuals/Audio

    Still fiddling with this. I got the blood splatter working by doing:

    Effect.PiercingRoundDamage.Start
    -> At Target
    -> ValidateUnit UnitIsBiological
    - Create

    ActorCreation
    -> ValidateUnit NotMassive
    - SetScale 0.5

    I also removed the global Raynor SOp... so it looks like the blood splatter squirts up instead of towards Raynor but it's hardly noticeable anyhow. And with the scale I get bigger ones on massive units so that part works pretty well.

    Only thing left is that as the ability's range increases from 1 to 32, its guide and projectile beam also need to increase.

    Since I couldn't modify the guide's scale or the beam's offset via triggers, I thought I'd try through upgrades, but those seem to have the same restrictions. Technically both methods seem to let me modify the beam actor's scale, but the modification has no effect. Even setting the scale in the properties has no effect. I can only change its size via the model's scale. When I try to modify the beam's offset via triggers, I get an error. And there's simply no option for it when doing the upgrade.

    I also tried modifying the beam's scale via the upgrade. That doesn't appear to have any effect.

    My last thought was perhaps I could do it via the actor events.. if I could check the upgrade level then maybe I could set the stuff. I found the upgrade finalized event, but I don't see anything in terms to check the actual level of it. And in the local offset SOp for the beam, I don't see a Set Local Offset or anything similar that I could use anyhow.

    For reference, my upgrade is currently defined as such:

    Name: Piercing Round Range
    Max Level: 32
    Effects +
    - Ability - Piercing Round: Range - Add 1
    - Effect - Piercing Round Persistent: Period Count - Add 1

    So in essence, I set the level of the upgrade to the range that I want my piercing round to have, up to a max of 32 (as determined by the 32 period limit on the persistent). I set the starting range and period counts to 0 to compensate.

    @DrSuperEvil: Go

    Been pouring over the Hellion Attack Beam for days. It does get wider via changing the x-scale. I can't seem to replicate any scaling on my end. I noticed it uses a Site whereas I'm currently using a Local Offset. Maybe I need a Site in order to be able to scale it? I don't understand how the sites work. I expected Hellion Attack Beam to have Hellion Attack Beam Impact Site listed in its Site Ops but it's not.. there's nothing listed.

    Been trying to find tutorials on this stuff without any luck.. the few ability tutorials which use lots of effects and such don't really discuss actors or get into any of this detail of site ops and query regions and bears (oh my).

    Posted in: Data
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?

    @Truun: Go

    Ha! We got off on a bit of a tangent. :)

    Posted in: Triggers
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?

    @Mille25: Go

    Very good to know thanks :)

    Posted in: Triggers
  • 0

    posted a message on How do I recolor these textures?

    @JacktheArcher: Go

    I have almost 0 experience with modeling.. still I was able to remove Raynor's spotlight with the Blender tools. So it's possible. However I couldn't figure out how to see the spotlight.. much like it's not visible when previewing the unit.. so how I did it was I believe I found a "bone" that was sort of floating in front of his chest and I deleted it, saved and imported, and voila. Not sure if that's the right way but it seemed to work.

    Posted in: Artist Tavern
  • 0

    posted a message on Build Order Practice arcade game.

    @iSunMonkey: Go

    As hobbidude mentioned, it's impossible to make a single map that has every 1v1 melee map in it. You might be able to fit a few of the smaller ones in one map but there's a max size.

    What you should do is create a mod with all these features (reset the map, pick race, build orders). The mod could even have a map picker much like what Hero Attack uses, but that's limited to 4 terrains per map and you'd be similarly limited. Then you can create or re-create whatever maps you want to play on and apply the mod to them drawing out the boundaries for each inner map.

    Of course keep in mind a few things..
    - it's very difficult to properly re-theme the UI for your chosen race. I haven't seen it done successfully. So while you might be able to change your race in-game your UI will likely stay as whichever race you chose in the lobby.
    - I haven't seen a way to change mineral or vespene count in-game. Maybe you could remove the mineral patches and vespene geysers and re-create them. I'm just not exactly sure.
    - The final game score at the end is going to be completely useless to you if there's a reset option so might want to incorporate something similar before each reset.
    - everybody's editor is pretty slow

    Honestly sounds like a pretty limited project only including 1v1 maps and lots of this has been done. You might find better success trying to join an existing project rather than re-invent the wheel, so to speak. :)

    Posted in: Map Suggestions/Requests
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?
    Quote from GlornII: Go

    Here is a map init question I have; with smart people in the area... Does picking units/players during map init slow the loading down? In wc3, this was a thing. A big thing. You should never pick units or players during map init; due to the way things were loaded into the game. It would attempt to pick a player that didnt exist yet; and freeze up until said player got far enough into the loading process that it recognized them. It could also cause server splits. Not to steal the topic or anything; but do either of you know if this has any affect in sc2?

    I'm not sure. I would hope they'd fix such a thing.

    But that said.. since loading screens are such an awful experience (they don't even support chat).. I would suggest to anyone that they take the same route as Aeon of Storms and a couple other maps I've seen recently.. do as little as possible in the map init.. then have a secondary loading phase in-game. This at least gets people off that frozen screen and into an interactive experience as quickly as possible.

    Posted in: Triggers
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?

    @Mille25: Go

    Man am I ever disillusioned...

    I tried googling it.. couldn't really find anything discussing if galaxy is compiled or interpreted. I finally buckled down and got an mpq editor and grabbed a map and copy/pasted a trigger a bunch of times and compared the before and after in the mpq. Not as many files as I expected. And true enough.. the only changed files were the string file holding the names of the triggers and such.. the trigger file that holds the xml that describes the trigger editor data.. and the galaxy file with the code in it.

    I'm just flabbergasted.

    And the more I think about it... it would be difficult for sc2 to run compiled code for a game, especially given it would need the same code to work on both mac and pc. They'd have to go interpreted... but.. why would they create their own butchered version of a language.

    To your concerns as to why they couldn't use LUA.. WoW would've had the same issues... they found a way (and this was many years ago that WoW started) to restrict lua's native lib to a smaller subset of functions.. and they also added a couple of their own in addition to the robust wow api. You couldn't write an addon that could write to files or connect to anything external because all those functions were removed. They limited so that the addon couldn't affect anything outside of the game's UI. It worked great and has obviously stood the test of time.

    Since the Trigger Editor simply writes galaxy behind-the-scenes.. I don't see any reason it couldn't simply write lua. It's just a different syntax.

    The only thing I can think of is that perhaps they needed a typed language for performance reasons.. there are a crap ton of variable types in galaxy. Maybe they needed something that could be "parsed" and have a reasonable certainty that it wouldn't explode mid-game. I dunno. I'm just fishing. WoW used lua just fine amidst all the inventory and unit frame and other things it had which could've been types but weren't. And it handled errors without blowing up.. SC2 maps still get errors with all of its string functions and what-not. I have to imagine it was a performance concern but given SC2's performance hiccups and relatively large times on even barren maps it's hard to argue that using LUA would've been any worse.

    It's also possible that they went the jvm route and they have a just-in-time compiler. That could explain why it takes a map so long to load.. if it's during that stage that they convert the galaxy script into compiled code for the current platform. That is a possibility.. and it makes code optimization even more important if it affects load time.


    On a side note.. the xml trigger file is HUGE. In my very tiny demo map, the galaxy script is 5.49 KB. The trigger file is 41.01 KB (7.47 times bigger than galaxy). When I made 12 copies of one of my triggers (of moderate size, 25 lines), it jumped to 32.98 KB galaxy and 420.41 KB triggers (12.75 times bigger than galaxy). In addition the string file jumped from 512 bytes to 4.52 KB. When the galaxy file grew 6 times its size, the trigger file grew over 10 times its size and the strings grew 9 times their size. Even the map file itself (which is compressed) nearly doubled in size from 43 KB to 83 KB.

    For further comparison, I took the total 13 copies of that trigger, pasted them into a new custom script "node" in the trigger editor, and saved it. I must've not copied exactly because my resulting galaxy file ended up being 33.19 KB.. a little bigger than the 32.98 of the trigger editor version. But regardless.. my triggers file dropped from over 400 KB back down to just 48.18 (it contains a complete copy of the code wrapped in xml - kind of annoying). And my string file is now 235 bytes.. a little smaller since I removed the original trigger as well and put it into galaxy. Total map size dropped back down to 44 KB.

    To take things even further.. I took that custom script node and moved its contents into an external .galaxy file, which I then imported into the map. My trigger file dropped to 9.39 KB since it no longer has the copy of all the code. My string dropped a little to 180 bytes without the node. The compined size of my new imported file and the map script file are about the same as the map script file used to be. My .SC2Map file overall dropped another 3 KB.

    I already write most of my stuff in galaxy.. anything complex or using math, at least.. I think I may switch to doing it all in there. The savings on an imported file vs a custom script node aren't huge, but could easily be worthwhile on larger maps. The savings moving from trigger to galaxy seems like just a no-brainer for me after seeing these numbers.

    Now I just need a less painful way to write the code in my editor and transfer it into the map. :)

    Posted in: Triggers
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?

    @Mille25: Go

    Great points :)

    I wanted to clarify one thing.. compiled code is machine-level code. I don't know for certain if SC2 compiles to machine-level code, but I'm pretty sure it compiles the galaxy script into something closer to machine-level code so I'll call it machine-level for the sake of simplicity.. it creates some kind of low-level instruction that it can execute much more quickly than it could parse the galaxy script in real-time. In all honesty it's not even fair to call it script. Ctrl+F11 is the "View Script" command but scripts are parsed and executed at run-time which gives them the distinct advantage of being able to do things like having functions as variables and dynamically executing code on-the-fly. Due to how limited galaxy is and due to its similarity to C and its use of references and strongly-typed variables, I'm pretty certain it's not script. Blizzard used Lua script in WoW for the addon interface, and it was extremely powerful and flexible, so I can only imagine the reason they didn't use that here was for performance.. and to get better performance, that means using a language that's compiled.. not a scripting language. But I digress. :)

    When you're using the trigger editor, everything you do is converted to galaxy script (or code.. or whatever). You can see it by hitting Ctrl+F11. I believe this is the step you're thinking of as being faster using actions vs triggers? This step doesn't affect game performance at all and is virtually immediate within the editor.

    When you save the map, hit Ctrl+F12, or seemingly at random other moments as well, the game will try to compile your code. It's a bigger deal when writing galaxy script manually then when doing trigger stuff... and the editor actually won't save your map if there's any compilation errors. This is the step though that converts all of the galaxy script.. the human-readable code.. into machine-level code. This step could take a little while on really, really large projects and if you get down into it the less galaxy script the faster it would be, but again it's negligible. I've compiled large java projects that take 10-15 minutes to finish. I can't imagine anything in SC2 taking more than a few seconds. I'd be curious to know how long SCU takes. :) There's no indication of when it finishes though.. if there's an error it'll ding and show the error, but if it all works, I think the window just flashes or something.

    The comparison of i = i + 1 and i += 1 was to demonstrate that regardless of how you type it, that'll compile into the same machine code. It'll run the same. We can't see that code.. I assume it's in the mpq somewhere but it's binary and we wouldn't understand it.

    The parameters, yeah, I have no idea why they don't let you edit them. If you look at the galaxy script, they're simply functions with regular parameters. If you wrote that same function manually, you could edit them. It's not a limiting feature of the language, it's of the GUI. But to your point, while you could do a custom action to modify them, I feel that defeats the purpose of using the GUI. If you're doing work with the Trigger Editor you're able to rename and move things around and it'll update all references and write function declarations for you. Once you start doing custom code, you break that. If you really want to be as performant as possible though, you would write everything in galaxy script manually. Many of the actions in the Trigger Editor are purely wrappers around native functions that add a little more logic (like getting "default" facing) or simply change the order of the parameters. Every time you use these actions, you're suffering the performance penalty of one more function call. So getting into that discussion is a whole other beast. :)

    Posted in: Triggers
  • 0

    posted a message on [Solved] Using action functions or triggers for initialization actions?

    @Ahli634: Go

    I always wondered how the threading worked. I just ran some tests and you're right, it looks like it doesn't actually have threading it just moves things around the stack much like javascript does. Makes a lot more sense this way now.

    Ordering seems a little weird. I created three triggers: A, B, and C. All iterate 1 through 3 printing out their letter and then waiting on each iteration.

    I ran a few tests to see the order of execution.

    A and B execute on map init, C has no event. A calls C with Don't Wait as its first action.

    I expected to get CAB CAB CAB .. because A and B would go on the stack from the event, A would execute first, which would call C immediately. C would print then wait (move to end of stack). A would print and wait. Then B would print and wait. C was first moved on to stack so keep iterating in that order...

    I did get CAB, but then I got BCA BCA.

    If I remove C, I get AB BA BA.

    If I do C on map init, I get ABC CBA CBA

    If I do C as first action of A with Wait, I get CB BC BC AAA

    If I do A and C on init and A calls B with Don't Wait, I get BAC CBA CBA

    If I do B and C on init, and C calls A with Don't Wait, I get BAC ACB ACB .. which is the first time that the last thing in the first set wasn't called first in the second set.

    Been staring at this awhile now.. what's happening is that things are going onto the stack in reverse order and then maintaining reverse order. The first set is always different because that's executing in operational order.. after that, it executes in function order.
    So if you look at the last one, B gets called from map init and prints B, then C gets called from map init and executes A which prints A then C finishes executing to print C .. BAC. BUT the function order was BCA.. which is ACB reversed. If you follow that logic for all of them, it works out. It's almost like it's executing functions from the bottom up, but executing events from top down. Or in other words, event triggers are executing from the top of the stack while everything else executes from the bottom.

    TLDR: Don't rely on any set order of execution. If B shouldn't execute until after A, then make A execute B when it's done. Don't rely on events or waits or which function is above the other in the list.

    @Mille25: Go You are starting to sway me towards using actions for this scenario.. primarily because I agree that if a trigger doesn't have an event then there's no reason to incur the overhead (whatever it's size) of creating a trigger.. you can simply have your one map init trigger call a few functions. However if I may play devil's advocate to your points... and also perhaps lend a little more information to the topic because I think this has been a really great discussion and I've already learned quite a bit from it...

    Quote:

    - TriggerExecute() is way slower than just calling a function
    - They can check conditions faster than triggers, because the unnecessary negation is missing (Which is used by trigger conditions)

    The speed difference here is likely negligible. I don't know how TriggerExecute() works.. it's probably doing a dictionary lookup and calling the associated function, but with proper optimizing, we could be talking nanoseconds. And the difference on a bit-wise operator is even less than that.

    Quote:

    - The action calls itself contain way less galaxy code than triggers, because the trigger initialisation and registration is missing
    - Bloated generated code segment such as condition validation or return true/false is not necessary.

    I know this isn't the meaning of your argument, but I want to clarify for anyone else that might read it this way, just because you have less source code doesn't necessarily mean you'll have less or quicker compiled code (and as far as I know, Starcraft 2 does compile the galaxy code). For instance, compare: a += 1; vs a = a + 1; First one is shorter, but these are going to compile to exactly the same thing (or they certainly should if the compiler is any good).

    To the meaning of your argument... if we're talking we already have a single map init trigger, that's a given, and the difference between it then executing 5 triggers or calling 5 actions.. we're talking about the triggers adding 5 functions and 5 function calls one time only on map init to set themselves up.. and then on execution, it's 5 more if statements to check if it should run. Then there's 5 trigger objects in memory and TriggerExecute runs 5 times. So given all that.. yeah, that sounds like a good bit more... which is why I said that for this scenario I'm seeing the advantage of using actions over triggers.. even if they do get added to the action list (I saw the comment about hiding them afterwards, but that just seems like a pain if you do ever need to move them to unhide and re-create and re-hide - I would just keep them visible and live with it).

    Quote:

    - Event properties just need to be read out once, stored in a variable and then passed by parameter, such as "Triggering Unit". All of those event responses are actually functions which are slower to call than reading variables/parameters, so the more often you need to access event properties the more actions will pull ahead.

    I thought this was an interesting argument... and one that's very subjective. So I'd like to lay out a bunch of scenarios and discuss the approaches:

    If you're using an event property only once, it's actually quicker to just make the single function call then it would be to store the function result to a variable and pass that variable to a function. As you said, the more you use it, the more performance favors the action.. but it goes the other way too - the less you use it, the more performance favors the initial trigger. I could strengthen your argument further as well by removing the middle step, don't store it to a variable, just pass it.
    For instance, choose one (pseud-code):

    UIDisplayMessage(UnitName(TriggeringUnit());
    vs
    unit myUnit; myUnit = TriggeringUnit(); PrintUnitName(myUnit);
    vs
    PrintUnitName(myUnit);

    Last example is least code, first is going to be the quickest if that's really all you need to do.
    HOWEVER, if you do need to do more with the triggering unit, you can still store it to a local variable in the trigger and then use that rather than calling the function again and again.. this would be a very good practice. One should never call the same function twice (whether it be a blizz function or one you make yourself) unless you're reasonably certain the outcome will be different.

    In addition, Actions in the Trigger Editor do not allow you to modify params. So if you had a trigger like On Unit Takes Damage and passed that TriggerUnit() to your Action as a param, and then wanted to modify the unit param, you can't. Think of a chain lightning ability done in a trigger where you pass the first target and then the action does the bouncing. Your target will keep changing on each bounce.. but you can't change your target param so you end up having to create a local variable for your target and setting its initial value to your param and then modifying that from there (I actually did this a couple weeks ago). This creates more source code and is (negligibly) worse for performance then if you just had a local variable to work with.

    Also consider the case where your action is used multiple times but it's only ever called by a single trigger. Say on unit death you want to award bounty. You wire up the events to your trigger, you grab the dead unit and the killing player and send those over to an action to determine the amount of bounty and award it. Now for that, you've created 3 functions (2 for the trigger + 1 for the action) when you really only needed the single trigger (2 functions)... all other things being equal.





    I do like the idea of having a localized place for event handling. I'm not arguing against that. If we take the last example but let's say in addition to awarding bounty on unit death, maybe it's a gladiator type of game so when a unit dies the crowd cheers and maybe a banner enters the screen proclaiming the victor and loser and.. I dunno.. the killing unit does a little dance. So now we have 4 "things" that take place. For organization purposes, I'd make those 4 separate actions all calling from a single trigger.. I really like that idea. The banner and the bounty actions might both need to know the defeated unit so you could put that in a variable and then pass the var rather than call the DyingUnit() function twice. The banner also needs to know the victor so maybe you pass KillingUnit() directly.. maybe you still assign it to a variable for readability and consistency.

    If you are worried about performance though, it would still be best to keep the code for them in the trigger since none of those things will happen outside of a unit death event.

    So what I'm saying is that whether or not a trigger or action is "best" depends on the circumstances in which it's being used.
    Also, I'm trying to point out that the war between performance vs organization is exactly that.. almost anytime you do something to better organize your code, you're going to hurt performance. Function calls have overhead associated with them (if you've ever seen assembly code, functions don't actually take params the way we think of it.. you have to first push all the params onto a stack and then the function takes them down off the stack in a consistent order so the more params you have the more expensive your function call is both in terms of memory and performance).

    Technology is reaching a point where I think performance is becoming less and less of a concern. Processors are getting faster. GPUs are taking on some of the work. That's why I say that until I see benchmarks, most of these concerns are negligible. We're not building nuclear reactors here. :) Everything is a case-by-case.

    I mentioned that I like the idea of a single place for event handling, but that depends on the situation as well.
    Let's imagine a game where some abilities are created using triggers rather than the data editor. So.. we have a game where bounty is awarded on unit death.. but somebody also has a passive ability that each time he kills a unit a small explosion occurs at the location of the corpse to damage nearby enemies.. Corpse Explosion. Now.. do I have a single On Unit Death trigger.. that calls the bounty action and the corpse explosion action (letting the corpse explosion action check the killing unit to see if he has the passive or not) .. or does my On Unit Death trigger call the bounty action and then check to see if it should call the corpse explosion action (segmenting the logic). Or do I have two triggers... one for the bounty action (and any other simple actions that always occur on unit death - ie things generic to the game)... and a seperate trigger grouped with anything else (variables, actions, etc) pertinent to my Corpse Explosion ability.

    Personally, I think I like the last scenario here.. I think I like the idea of having every last bit related to my corpse explosion in a single folder that I can then copy/paste into another map if need be. And then if I want to change the eventing for corpse explosion, I look at my corpse explosion ability folder rather than looking through my eventing to see what calls the corpse explosion.


    Whew that was alot. Brevity is not my strong suit. I think I hurt my own head writing all of that. :D

    Posted in: Triggers
  • 0

    posted a message on [Showcase] NanaKey&Delphinium's Models

    Been watching this thread for a couple months now, your stuff is amazing. I wish maps had stuff that looked this awesome.

    Just wanted to second that I'd love to see some tutorials as I haven't the first clue how you do all the animations and particles and data. This stuff is all so visual, a video tut would probably suit it best. :)

    Keep up the awesome work!

    Posted in: Artist Tavern
  • To post a comment, please or register a new account.