System Damage

Jesus4Lyf

Good Idea™
Reaction score
397
Damage​
Version 1.0.5​

Requirements:
- Jass NewGen
- AIDS
- Event

JASS:
//  
//      ___   _     __  __   _   ___  ____    _______________________________
//     |   \ /_\   /  |/  | /_\ /  _\|  __|   ||      D E A L   I T ,      ||
//     | |) / _ \ / / | / |/ _ \| |/||  __|   ||    D E T E C T   I T ,    ||
//     |___/_/ \_/_/|__/|_|_/ \_\___/|____|   ||     B L O C K   I T .     ||
//                            By Jesus4Lyf    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//                                                                    v 1.0.5
//      What is Damage?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Damage is a damage dealing, detection and blocking system. It implements
//          all such functionality. It also provides a means to detect what type
//          of damage was dealt, so long as all damage in your map is dealt using
//          this system's deal damage functions (except for basic attacks).
//
//          It is completely recursively defined, meaning if you deal damage on
//          taking damage, the type detection and other features like blocking
//          will not malfunction.
//          
//      How to implement?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Create a new trigger object called Damage, go to 'Edit -> Convert to
//          Custom Text', and replace everything that's there with this script.
//
//          At the top of the script, there is a '//! external ObjectMerger' line.
//          Save your map, close your map, reopen your map, and then comment out this
//          line. Damage is now implemented. This line creates a dummy ability used
//          in the system in some circumstances with damage blocking.
//
//      Functions:
//     ¯¯¯¯¯¯¯¯¯¯¯¯
//          function Damage_RegisterEvent takes trigger whichTrigger returns nothing
//              - This registers a special "any unit takes damage" event.
//              - This event supports dynamic trigger use.
//              - Only triggers registered on this event may block damage.
//              - Only fires when the damage dealt is not 0.
//
//          function Damage_RegisterZeroEvent takes trigger whichTrigger returns nothing
//              - The same as Damage_RegisterEvent, but for only zero damage events
//                (which are excluded from Damage_RegisterEvent).
//              - Note that getting the damage type may be unreliable, since spells
//                like faerie fire trigger 0 damage, but it will count as an attack.
//
//          function Damage_GetType takes nothing returns damagetype
//              - This will get the type of damage dealt, like an event response,
//                for when using a unit takes damage event (or the special event above).
//
//          function Damage_IsPhysical takes nothing returns boolean
//          function Damage_IsSpell takes nothing returns boolean
//          function Damage_IsPure takes nothing returns boolean
//              - Wrappers to simply check if Damage_GetType is certain types.
//
//          function Damage_IsAttack takes nothing returns boolean
//              - Checks if the damage is from a physical attack (so you can deal
//                physical damage without it being registered as an actual attack).
//
//          function Damage_Block takes real amount returns nothing
//          function Damage_BlockAll takes nothing returns nothing
//              - For use only with Damage_RegisterEvent.
//              - Blocks 'amount' of the damage dealt.
//              - Multiple blocks at once work correctly.
//              - Blocking more than 100% of the damage will block 100% instead.
//              - Damage_BlockAll blocks 100% of the damage being dealt.
//
//          function Damage_EnableEvent takes boolean enable returns nothing
//              - For disabling and re-enabling the special event.
//              - Use it to deal damage which you do not want to be detected by
//                the special event.
//
//          function UnitDamageTargetEx takes lots of things returns boolean
//              - Replaces UnitDamageTarget in your map, with the same arguments.
//
//          function Damage_Physical takes unit source, unit target, real amount,
//            attacktype whichType, boolean attack, boolean ranged returns boolean
//              - A clean wrapper for physical damage.
//              - 'attack' determines if this is to be treated as a real physical
//                attack or just physical type damage.
//              - 'ranged' determines if this is to be treated as a ranged or melee
//                attack.
//
//          function Damage_Spell takes unit source, unit target, real amount returns boolean
//              - A clean wrapper for spell damage.
//
//          function Damage_Pure takes unit source, unit target, real amount returns boolean
//              - A clean wrapper for pure type damage (universal type, 100% damage).
//          
//      Thanks:
//     ¯¯¯¯¯¯¯¯¯
//          - Romek, for helping me find a better way to think about damage blocking.
//
library Damage uses AIDS, Event
    //============================================================
    //! external ObjectMerger w3a AIlz dprv anam "Life Bonus" ansf "(Damage System)" Ilif 1 500000 aite 0
    globals
        private constant integer LIFE_BONUS_ABIL='dprv'
    endglobals
    
    //============================================================
    globals
        private Event OnDamageEvent
        private Event OnZeroDamageEvent
        private boolean EventEnabled=true
    endglobals
    
    public function RegisterEvent takes trigger whichTrigger returns nothing
        call OnDamageEvent.register(whichTrigger)
    endfunction
    
    public function RegisterZeroEvent takes trigger whichTrigger returns nothing
        call OnZeroDamageEvent.register(whichTrigger)
    endfunction
    
    public function EnableEvent takes boolean enable returns nothing
        set EventEnabled=enable
    endfunction
    
    //============================================================
    globals
        private integer TypeStackLevel=0
        private damagetype array TypeStackValue
        private boolean array TypeStackAttack
        private real array ToBlock
    endglobals
    
    public function GetType takes nothing returns damagetype
        return TypeStackValue[TypeStackLevel]
    endfunction
    
    public function IsAttack takes nothing returns boolean
        return TypeStackAttack[TypeStackLevel]
    endfunction
    
    public function Block takes real amount returns nothing
        set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+amount
    endfunction
    
    public function BlockAll takes nothing returns nothing
        set ToBlock[TypeStackLevel]=ToBlock[TypeStackLevel]+GetEventDamage()
    endfunction
    
    //============================================================
    globals
        private integer BlockNum=0
        private unit array BlockUnit
        private real array BlockUnitLife
        private real array BlockRedamage
        private unit array BlockDamageSource
        
        private timer BlockTimer=CreateTimer()
    endglobals
    
    //============================================================
    globals
        private unit array RemoveBoosted
        private integer RemoveBoostedMax=0
        
        private timer RemoveBoostedTimer=CreateTimer()
    endglobals
    
    globals//locals
        private real BoostedLifeTemp
        private unit BoostedLifeUnit
    endglobals
    private function RemoveBoostedTimerFunc takes nothing returns nothing
        loop
            exitwhen RemoveBoostedMax==0
            set BoostedLifeUnit=RemoveBoosted[RemoveBoostedMax]
            set BoostedLifeTemp=GetWidgetLife(BoostedLifeUnit)
            call UnitRemoveAbility(BoostedLifeUnit,LIFE_BONUS_ABIL)
            if BoostedLifeTemp>0.405 then
                call SetWidgetLife(BoostedLifeUnit,BoostedLifeTemp)
            endif
            set RemoveBoostedMax=RemoveBoostedMax-1
        endloop
    endfunction
    
    //============================================================
    private keyword Detector // Darn, I actually had to do this. XD
    globals//locals
        private unit ForUnit
        private real NextHealth
    endglobals
    private function OnDamageActions takes nothing returns boolean
        if EventEnabled then
            if GetEventDamage()==0. then
                call OnZeroDamageEvent.fire()
            else
                call OnDamageEvent.fire()
            endif
            
            if ToBlock[TypeStackLevel]!=0. then
                //====================================================
                // Blocking
                set ForUnit=GetTriggerUnit()
                
                set NextHealth=GetEventDamage()
                if ToBlock[TypeStackLevel]>=NextHealth then
                    set NextHealth=GetWidgetLife(ForUnit)+NextHealth
                else
                    set NextHealth=GetWidgetLife(ForUnit)+ToBlock[TypeStackLevel]
                endif
                
                call SetWidgetLife(ForUnit,NextHealth)
                if GetWidgetLife(ForUnit)<NextHealth then
                    // NextHealth is over max health.
                    call UnitAddAbility(ForUnit,LIFE_BONUS_ABIL)
                    call SetWidgetLife(ForUnit,NextHealth)
                    
                    set RemoveBoostedMax=RemoveBoostedMax+1
                    set RemoveBoosted[RemoveBoostedMax]=ForUnit
                    call ResumeTimer(RemoveBoostedTimer)
                endif
                //====================================================
                set ToBlock[TypeStackLevel]=0.
            endif
        endif
        return false
    endfunction
    
    //============================================================
    function UnitDamageTargetEx takes unit whichUnit, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
        local boolean result
        set TypeStackLevel=TypeStackLevel+1
        set TypeStackValue[TypeStackLevel]=damageType
        set TypeStackAttack[TypeStackLevel]=attack
        set result=UnitDamageTarget(whichUnit,target,amount,attack,ranged,attackType,damageType,weaponType)
        set TypeStackLevel=TypeStackLevel-1
        return result
    endfunction
    //! textmacro Damage__DealTypeFunc takes NAME, TYPE
        public function $NAME$ takes unit source, unit target, real amount returns boolean
            return UnitDamageTargetEx(source,target,amount,false,false,ATTACK_TYPE_NORMAL,$TYPE$,WEAPON_TYPE_WHOKNOWS)
        endfunction
        public function Is$NAME$ takes nothing returns boolean
            return GetType()==$TYPE$
        endfunction
    //! endtextmacro
    
    //! runtextmacro Damage__DealTypeFunc("Pure","DAMAGE_TYPE_UNIVERSAL")
    //! runtextmacro Damage__DealTypeFunc("Spell","DAMAGE_TYPE_MAGIC")
    
    // Uses different stuff, but works much the same way.
    public function Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
        return UnitDamageTargetEx(source,target,amount,attack,ranged,whichType,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)
    endfunction
    public function IsPhysical takes nothing returns boolean
        return GetType()==DAMAGE_TYPE_NORMAL
    endfunction
    
    //============================================================
    private struct Detector extends array // Uses AIDS.
        //! runtextmacro AIDS()
        
        private static conditionfunc ACTIONS_COND
        
        private trigger t
        
        private method AIDS_onCreate takes nothing returns nothing
            set this.t=CreateTrigger()
            call TriggerAddCondition(this.t,thistype.ACTIONS_COND)
            call TriggerRegisterUnitEvent(this.t,this.unit,EVENT_UNIT_DAMAGED)
        endmethod
        
        private method AIDS_onDestroy takes nothing returns nothing
            call DestroyTrigger(this.t)
        endmethod
        
        private static method AIDS_onInit takes nothing returns nothing
            set thistype.ACTIONS_COND=Condition(function OnDamageActions)
        endmethod
    endstruct
    
    //============================================================
    private module InitModule
        private static method onInit takes nothing returns nothing
            local unit abilpreload=CreateUnit(Player(15),'uloc',0,0,0)
            call UnitAddAbility(abilpreload,LIFE_BONUS_ABIL)
            call RemoveUnit(abilpreload)
            set abilpreload=null
            
            set OnDamageEvent=Event.create()
            set OnZeroDamageEvent=Event.create()
            set TypeStackValue[TypeStackLevel]=DAMAGE_TYPE_NORMAL
            set TypeStackAttack[TypeStackLevel]=true
            call TimerStart(RemoveBoostedTimer,0.0,false,function RemoveBoostedTimerFunc)
        endmethod
    endmodule
    private struct InitStruct extends array
        implement InitModule
    endstruct
endlibrary

TESH Highlighting:
JASS:
//
//      _____ ___ ___ _   _ 
//     |_   _| __/ __| |_| |
//       | | | _|\__ \  _  |
//       |_| |___|___/_| |_| Highlighting:
//                            - Damage by Jesus4Lyf.
//
//      What is this?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Implementing this allows the TESH syntax highlighter in Jass NewGen
//          to highlight the syntax for this system (and autocomplete the functions).
//          
//      How to import?
//     ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//          Copy this into a blank text file, and save it at:
//          <Your Jass NewGen folder>\tesh\includes\Damage.j
//
function Damage_RegisterEvent takes trigger whichTrigger returns nothing
    // Registers an event: Any unit is damaged.
endfunction
function Damage_RegisterZeroEvent takes trigger whichTrigger returns nothing
    // Registers an event: Any unit is dealt zero damage.
endfunction
function Damage_GetType takes nothing returns damagetype
    // Requires all damage in the map (except basic attacks) to be dealt with one of:
    //  - UnitDamageTargetEx
    //  - Damage_Physical
    //  - Damage_Spell
    //  - Damage_Pure
endfunction
function Damage_IsPhysical takes nothing returns boolean
    // Requires all damage in the map (except basic attacks) to be dealt with one of:
    //  - UnitDamageTargetEx
    //  - Damage_Physical
    //  - Damage_Spell
    //  - Damage_Pure
endfunction
function Damage_IsSpell takes nothing returns boolean
    // Requires all damage in the map (except basic attacks) to be dealt with one of:
    //  - UnitDamageTargetEx
    //  - Damage_Physical
    //  - Damage_Spell
    //  - Damage_Pure
endfunction
function Damage_IsPure takes nothing returns boolean
    // Requires all damage in the map (except basic attacks) to be dealt with one of:
    //  - UnitDamageTargetEx
    //  - Damage_Physical
    //  - Damage_Spell
    //  - Damage_Pure
endfunction
function Damage_IsAttack takes nothing returns boolean
    // Requires all damage in the map (except basic attacks) to be dealt with one of:
    //  - UnitDamageTargetEx
    //  - Damage_Physical
    //  - Damage_Spell
    //  - Damage_Pure
endfunction
function Damage_Block takes real amount returns nothing
    // Must only be used from a trigger with the event from:
    //  - Damage_RegisterEvent
endfunction
function Damage_BlockAll takes nothing returns nothing
    // Must only be used from a trigger with the event from:
    //  - Damage_RegisterEvent
endfunction
function Damage_EnableEvent takes boolean enable returns nothing
endfunction
function UnitDamageTargetEx takes unit source, widget target, real amount, boolean attack, boolean ranged, attacktype attackType, damagetype damageType, weapontype weaponType returns boolean
    // The same parameters as the native UnitDamageTarget, but allows type detection.
endfunction
function Damage_Physical takes unit source, unit target, real amount, attacktype whichType, boolean attack, boolean ranged returns boolean
    // "attack" is whether or not the damage is an attack.
    // "ranged" is whether or not the damage is a ranged attack (set "attack" to true also).
endfunction
function Damage_Spell takes unit source, unit target, real amount returns boolean
endfunction
function Damage_Pure takes unit source, unit target, real amount returns boolean
endfunction

"Damage" is a full damage system for any map. It doesn't leak events internally, supports damage-on-damage functions without bugging (so it supports recursion), etc.

The main features are:
  • An AnyUnitDamaged event (which supports dynamic triggers just fine)
  • Instant damage blocking (only for triggers registered on the above event)
  • Get dealt damage type (as long as all damage is dealt with the functions from this system - except for basic attacks - which means the map's spells must damage through this system and not use damage from things like frost nova... so this feature is only for maps where the map is built to run on this system).
Demo map is a simple demonstration of stopping everything from dealing damage on the map. :)

Updates:
- Version 1.0.5: Added Damage_RegisterZeroEvent(trig).
- Version 1.0.4: Changed initialiser to module/struct to make it fire first.
- Version 1.0.3: Stopped detection of 0.0 damage events.
- Version 1.0.2: Added Damage_IsPure(), Damage_IsSpell(), Damage_IsPhysical() and Damage_IsAttack() (so damage can be physical but not count as an attack).
- Version 1.0.1: Changed the syntax from EnableEvent and DisableEvent to EnableEvent(boolean).
- Version 1.0.0: Release.
 

Attachments

  • Damage.w3x
    38.3 KB · Views: 1,925
Finally you submit this, once you told me about it on the chat I couldn't wait. :thup:
Looks good.
 
It would be better to use use one trigger with multiple events to detect damage and recycle units to avoid event leaks, but I guess this is ok too...
 
Recycle units is not easy, and i guess a good universal system can't be done without any Warcraft III 3rd party tools like GMSI .
If you want a good recycle system you should use many instant morph abilities and there are many side effect to play around them ...
 
It would be a good idea to benchmark your system with a small, medium, large and very large number of units at once. I know from experience that having too many units in a system like this that has too many function calls or conditions can cause noticeable slowdowns. You may want to examine this because the slowdowns can get to the point where players can see what is happening and you always want to mask what your system is doing.
 
Who cares if this is one hundredth of a milisecond slower than another system, as long as it's easily used and actually works, that's enough for me.
 
JASS:
    globals//locals
        private real BoostedLifeTemp
        private unit BoostedLifeUnit
    endglobals


What do you mean with Globals/Locals?
I don't see how they behave like locals, actually... Since they ARE globals, or?
I havn't used vJASS for a while now...
Many things changed :X
 
He just uses global variables instead of local variables in the instant functions.
They're about 0.000000000001 nanoseconds faster, and don't need nulling. :p
 
Yay, replies.

>It would be better to use use one
I'm not going to release a system that assumes players took the ridiculous measure to recycle units, and if they did, I believe the triggers in this would never actually get destroyed, so this supports unit recycling just fine anyway. :thup:

>It would be a good idea to benchmark your system
Benchmark -what- part of my system? Every single part of this system is O(1) complexity (in relation to its interface) so nothing should slow down anything at all. I don't know what you're talking about with units slowing things down, can you give me an example of why it might slow?

Looking at that alternative (no offense to the author, but these are the things I noticed):
IDDS:
  • Doesn't work: If you have a damage on damage action, the damage type and stuff screws up completely. It isn't recursively defined, which is VITAL to a system like this actually being reliable. I would never use IDDS for that reason - it breaks.
  • Uses TriggerUnregisterDamageEvent which isn't a nice interface, so this isn't behaving like a real event anyway, because you can't just destroy triggers.
  • Damage type is an integer (how is that intuitive?) which is actually one of the reasons I wrote this.
  • Uses H2I (Table) which will break on 1.24, etc. I do not want any of my maps to break when new patches come out. Purely personal choice, but I wrote this system out of necessity.
  • Has an O(n) complexity trigger sorting mechanism for some reason.
That was just at a quick glance.

>Who cares if this is one hundredth of a milisecond slower than another system
No, this system should be faster than other systems which try to accomplish the same thing. AND actually work. :) :thup:
 
I've updated most triggers to use Damage and most things are running faster/better than they did. For example my trigger used to be delayed since I had to use a wait in a trigger for my old system. But now, it works perfectly without delays.
 
>Uses H2I (Table) which will break on 1.24, etc. I do not want any of my maps to break >when new patches come out. Purely personal choice, but I wrote this system out of >necessity.

Hell, no. Since he uses Table as a abstraction everyone using IDDS just have to update
Table.

>Has an O(n) complexity trigger sorting mechanism for some reason.

An O(n) sorting algorithm wouls be awesome....


>>Who cares if this is one hundredth of a milisecond slower than another system
>No, this system should be faster than other systems which try to accomplish the >same thing. AND actually work. :) :thup:

Ahh, that kind of mapper...
And don't use Dusks System but i would prefer his to this, because those priorities are actualy quite nice.
 
>Hell, no. Since he uses Table as a abstraction everyone using IDDS just have to update Table.
Actually, he incorporated his own H2I and didn't use HandleTables. Besides (and this is irrelevant), even using HandleTables in your map will make it break for 1.24. I want my 1.23 RELEASE to work on 1.24.

>An O(n) sorting algorithm wouls be awesome....
Actually, his is O(n^2).

>Ahh, that kind of mapper...
Yes, that kind of mapper. One who makes things which work. The fact that most of my stuff is highly efficient is a side bonus.

By the way, you can do sequencing just fine. Just register multiple conditions or actions on one trigger in the order you want them run...? <_<

By all means, use whatever you like. I wrote this because I needed it, so I figured it would be useful for others. :)
 
Awesome, finally a good all-purpose full damage system for maps. Looks very cool, and interface is simple as, love it.

Once again, if I actually needed damage detection, I think I found the system to use.

Nice work. :D
 
JASS:
function UnitDamageTargetEx takes lots of things returns boolean


What if a GUI user wanted to use this? He would have to search your code to find out what function calls he needs to do and even if he found it, he still might not know how to call the function.
 
This system wasn't designed for GUI users.
 
But what if a GUI user want to use it? You could atleast just wright what the function takes.
 
'But what if a foreign medical aid service wanted to use the Topol-M missile launch vehicle? You should at least include instructions on how to load medical supplies into the missile tube.'


Using AIDS within GUI would be horrifying to consider even if you were a master of both Jass and GUI. There's really no point facilitating it. I mean, if you're so beastly that you can actually use AIDS within GUI's structure, you'll have no trouble figuring out what that function takes.
 
But what if a GUI user want to use it?

Then he can spend the day or two learning JASS, instead of the week or two trying to figure out how to use a custom event system within GUI.

There are very few systems that should actually be used within GUI, and those are the one-function-call do-it-all-for-you systems, such as a knockback system.

Since there is no native way to add GUI function calls, every part of a system like this would need to deal with custom script. There are even conditional functions in here. There isn't any *native* custom script for conditions.

I would recommend adding in documentation about what the returned booleans mean for the functions, but other than that, good job. :)
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • tom_mai78101 tom_mai78101:
    Currently in the middle of getting the probate process going. We're doing the informal probate process.
    +3
  • Varine Varine:
    A probate is usually done with a will, yes? If so I am sorry for your loss
    +1
  • The Helper The Helper:
    Yeah Tom, me too sorry for your loss buddy my mom told me she finds out her olds friend died from Google searching them. She had not talked to one of her old friends in a year and found out she died from Google. Also another one in the same session. RIP all of them my sincere condolences Tom
    +1
  • Varine Varine:
    We have some elderly guests that regularly come hang out at the bar at the end of the night, and every once in a while we don't see someone for a few weeks and then someone shows up with their obituary.
  • Varine Varine:
    We usually let them do their memorials there in the morning if they want to and I'll make them some snacks and drinks. There was one guy named Tom that came in like every night and would sit by himself and get a bunch of soup and a glass of wine. idk why but he LOVED our fucking soup, like he would order a fucking quart of it at a time and would always get so sad when we stop doing it for the summer.
    +1
  • Varine Varine:
    But he also loved our calamari, which is another thing I hate but it sells super well so I can't change it. There was one day he came in and was asking me how to make it, because he tried to at home once in the off season when we stop running it and he really wanted it lol
  • Varine Varine:
    I think he's one of the only people I've made recipes for for free because he really wanted a broccoli cheddar, and it was like dude I don't have a recipe, it's just whatever I have, but here, this is how you do it
  • Varine Varine:
    I don't think he ever figured out how to do the calamari in a pan though, like idk how to do that either. He was afraid of the at home deep fryers though and it's like yeah, that's fair, I am too
  • Varine Varine:
    He was just such a sweet old man, we had two servers pregnant and they held a baby shower together, he was soooooo fucking excited to get to see a baby. Unfortunately he died a month or so before they were born
  • The Helper The Helper:
    So I decided to Google some people that I had not seen or heard from in a while and sure enough one of my old best friends, we had a falling out years ago but whatever, find out he died of Pancreatic Cancer in January. I have also lost a few of my closer acquaintances from growing up the last year. Getting old - people die - I kinda thought it was going to be this way a few years ago....
    +2
  • The Helper The Helper:
    Forum running super slow again
  • Ghan Ghan:
    Not really clear from the stats as to what is causing the slowness.
  • Ghan Ghan:
    We get a lot of guest traffic so it may just be the load is getting too high and not from any particular source.
  • Ghan Ghan:
    Looks like the server is maxed out on CPU.
  • Ghan Ghan:
    Oh it looks like a lot of the traffic is Silkroad Forums. That domain isn't protected by Cloudflare.
  • Ghan Ghan:
    But the old Silkroad site is still on its own server. I just had a test site set up on this server for it.
  • Ghan Ghan:
    I just disabled that test site. Let's see if that helps the load.
  • Ghan Ghan:
    Looks much better already.
  • The Helper The Helper:
    I had actually forgot about the Silkroad site. I had asked
  • The Helper The Helper:
    SD Ryoko about it and he said the couple of people left on there really like it, that was a few years ago, maybe I should check back
  • jonas jonas:
    I guess when you're getting old, and the last day of soup season draws near, you start wondering
  • jonas jonas:
    will I make it to the start of the next season? or was this the last time I'll ever have my favorite dish?
  • The Helper The Helper:
    I am doing my first Vibe Coding project. In installed the environment and tools according to instructions but it is all chat doing this for me at my direction. It is fun really and holy shit I might finish in 2 hours what it would have taken a day to in my Access and this would be an electron app complete new
  • Ghan Ghan:
    Good stuff.
  • Ghan Ghan:
    Just make sure it is secure. :)

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials
      Top