Jump to content
The Dark Mod Forums

SteveL

Member
  • Posts

    3666
  • Joined

  • Last visited

  • Days Won

    62

Posts posted by SteveL

  1.  

    Yes, if you modify binding functionality. Currently the way binding works is that bound object will only change location, but not rotation.

    Are you sure about that? Keys bound to AI rotate correctly as the AI moves, for example.

  2. func_shaking makes an entity wobble, either a model or an fs created in DR. I don't think it could make the camera bob during normal play.

     

    It'd be possible to script moving the player (and therefore the eye camera) around, but it probably won't work if the player has to move around normally at the same time. The wobble script would probably get the player stuck in the surrounding geometry.

  3. trigger_hurt has spawnargs "on" and "delay", but it doesn't look like they'll let you do this.

     

    You could use a pair of triggers: give the trigger_hurt "on" "0" and then target it from a trigger_entityName set to activate by player1 only, and with "delay" "5" for a 5-second delay, for example. You'd also need to set "wait" "0" on the trigger_entityName so that it removes itself from the game the first time it's fired.

  4. Well, normally there should also be an arrow from the trigger to the speaker in this case, right? In one map, there is no arrow, in the other the arrow points from the speaker to somewhere in infinity. I tried with various sounds, none of which works.

    Setting these cvars might help you work it out:

    g_debugTriggers 1

    s_drawSounds 1

    con_noprint 0

     

    The last one makes console text appear on your screen without you having to open the console, so you can see the text when a trigger fires

     

    EDIT: ninja'd

    • Like 1
  5. No, 2.04 is too close to final build version. It's going to be a mostly a bug-fix release since some of the larger changes were taking too long

    and leaving players with some critical bugs like the "card player save state bug" and a nasty "SEED related memory allocation" behavior.

    Not to mention sound pops in this year's big maps like Sir Talbot's and House, and the bug with AI sitting their way out of the world. Those will be fixed too.

     

    Load times are definitely a nice to have, and grayman and I have both dug into it in the last year or so looking for options and testing a few things, but it's not top priority because the most obvious changes are huge work to implement -- background loading and processing of assets, for example, presumably ordered by how close the asset is to the player's current position -- that's a complicated change, and it feels like less of a priority than new features (imo). nbohr1more's suggestion of a texture load fix is an exception: we can try that without boiling the ocean, and there will be other quick fixes too, like the one to speed up particle loading.

     

    I've had confusing results from cpu and gpu profiling during the load procedure, which is another reason I haven't worked on it much: no clear lead.

    • Like 1
  6. There are quite a few. This csv file has just the spawnargs that are defined in each entity def. It doesn't include inherited spawnargs but I can tweak the script to include them if you want.
    ai_spawnargs.csv.txt

    How: I use python scripts to search TDM asset files and published FMs for compatibility problems when we do changes to the game. They parse text using regular expressions. I'll paste the code in case you want to mess with it. This was a quick fix because I just had to adapt a procedure I already had.

    The first file mapparse_general.py searches a TDM installation including inside pk4s and FMs, and generates the filenames and their contents. The second one parses .def files and constructs an inheritance tree of entity defs, then uses that to print out the spawnargs of all entities that inherit from tdm_ai_base.

    mapparse_general.py

     

    """Search text files in FMs and TDM assets"""
    import re, os, fnmatch, zipfile
     
     
    PATHS = [ r"C:\darkmod" ] #, r"E:\dm-dev\campaign"]  
    FILE_EXTS = ['.mtr'] # '.mtr', '.prt', ,'.skin','.fx','.md5mesh','.pfb', '.anim', '.md5anim','.gui','.map','.script','.gui','.def'
     
    def searchPk4(pk4, exts):
        """Look in a pk4 archive and yield files with any of the extensions 
        in exts. Returns ( filename, filecontents ). filename includes any
        directory path internal to the archive.
        
        pk4: full path, e.g. r'E:\darkmod\tdm_defs01.pk4'
        exts: list or tuple of bare extensions, e.g. ['def', 'mtr']
        """
        try:
            f = zipfile.ZipFile(pk4, 'r')
        except zipfile.BadZipfile:
            print "*** Error reading ", pk4
            return
        for member in f.infolist():
            ext = (os.path.splitext(member.filename)[1]).lower()
            if ext in exts:
                yield member.filename, f.read(member)
     
    def findTDMFiles(paths, exts):
        """Yield tuples: (filepath, filecontents) of all files 
        found in paths with any of the extensions in exts. Looks inside
        pk4 archives, but not nested archives.
        
        paths, exts are sequences containing one or more paths / extensions.
        """
        # Make sure params are both lists else we'll get weird results from a string
        assert(paths.append and exts.append)
        for path in set(paths):
            for root, dirnames, filenames in os.walk(path):
                for ext in set( ['.pk4'] + exts):
                    for filename in fnmatch.filter(filenames, '*'+ext):
                        fpath = os.path.join(root, filename)
                        if ext == '.pk4':
                            for internalname, content in searchPk4(fpath, exts):
                                yield ( fpath + ' -> ' + internalname,   content )
                        else:
                             yield fpath, file(fpath).read()
     
    

     




    ai_spawnarg.py

     

    """Re-useable functions:
    Parse entityDefs in unpacked FMs and TDM assets and compile class tree.
    Make spawnargs searchable including inherited ones.
    
    Currently set up to:
    Compile a CSV of AI spawnargs
    """
     
    import re, os, fnmatch
    from collections import Counter
    import mapparse_general
     
    GAMEPATH = r"C:\darkmod"
    FMPATH = r""
    DEBUGMODE = True
     
    # regexes
    NAME_PTN = re.compile(r'entityDef\s+(\S+)\s*\{.*?\}', re.IGNORECASE | re.DOTALL)
    ENT_PTN = re.compile(r'(entityDef\s+(\S+)\s*\{.*?\})', re.IGNORECASE | re.DOTALL)
    ARGS_PTN = re.compile(r'\{([^}]*)\}', re.IGNORECASE)
    SPAWNARG_PTN = re.compile(r'("[^"\n]*"|[^\s\n"]+)')
     
     
    def debugprint(text):
        if DEBUGMODE:
            print text
     
    def stripComments(text):
        """
        Strip text of /* block comments */ and // line comments, 
        except for those in a "string".
        """
        result = ''
        context = 'normal'
        pos = 0
        while pos < len(text):
            token = text[pos]
            next  = text[pos+1] if pos < len(text)-1 else ''
            skip = 0
            if context == 'string':
                result += token
                if token == '"':
                    context = 'normal'
            elif context == 'line comment':
                if token == '\n':
                    context = 'normal'
                    result += token
            elif context == 'block comment':
                if token + next == '*/':
                    context = 'normal'
                    skip = 1
            else:
                assert(context == 'normal')
                if token + next == '//':
                    context = 'line comment'
                    skip = 1
                elif token + next == '/*':
                    context = 'block comment'
                    skip = 1
                else:
                    result += token
                    if token == '"':
                        context = 'string'
            pos += (1 + skip)
        return result
     
     
    class entityDef:
        def __init__(self, name, filename, parentname='', spawnargs={}, inherited={}):
            self.name = name
            self.file = filename
            self.parentname = parentname
            self.parents = []      # Set by calling setParents() once all defs constructed
            self.children = set()  # Set by calling setParents() on all defs once constructed
            self.spawnargs=spawnargs
            self.inherited=inherited
     
        def _findParents(self, defs):
            """Return a list of parents, starting with the immediate parent."""
            parent = defs.get( self.spawnargs.get('inherit') )
            if parent:
                return [parent] + parent._findParents(defs)
            else:
                return []
     
        def setParents(self, defs):
            """Discover our ancestors and collect their spawnargs. 
            Make an inheritance list then work down it
            so spawnargs get overridden right, finally adding the our own."""
            self.parents = self._findParents(defs)
            for p in reversed(self.parents):
                self.inherited.update(p.spawnargs)
                p.children.add(self)
     
     
    def getFileDefs(fname, text):
        """Return a dict: { name : entityDef }"""
        text = stripComments(text)
        entdefs = ENT_PTN.findall(text) # [ ( deftext, name ), ... ]
        defs = {}
        for deftext, name in entdefs:
            spawnargs = {}
            sp_text = ARGS_PTN.search(deftext).group(1)
            #debugprint(sp_text)
            strings = SPAWNARG_PTN.findall(sp_text)
            #debugprint('%s Strings found: %d' % (name, len(strings)))
            for idx in range(0, len(strings), 2):
                spawnargs[strings[idx].strip('"').lower()] = strings[idx+1].lower().strip('"')
            parentname = spawnargs.get('inherit')
            defs[name] = entityDef(name, fname, parentname, spawnargs)
        return defs
     
     
    def getDefs(path, exclude_fms=False):
        """Compile a dict of entity defs from path: { name : entityDef }"""
        debugprint('Checking path ' + path)
        defs = {}   # { name : entityDef }
        for fname, text in mapparse_general.findTDMFiles( [path] , exts=['.def']):
            if exclude_fms and '\\fms\\' in fname:
                pass
            else:
                debugprint('Checking file ' + fname)
                defs.update(getFileDefs(fname, text))
                #debugprint('Def count %d' % len(defs))
        # Now we have all defs, populate ancestor details and inherited spawnargs
        for name, e in defs.items():
            e.setParents(defs)
        return defs
        
    if __name__ == '__main__':
        defs = getDefs(GAMEPATH, exclude_fms=True)
        filecount = len( set( d.file for d in defs.values() ) )
        print "Found %d files with %d defs" % (filecount, len(defs))
        # Print out a csv table of AI (anything inheriting from atdm:ai_base
        results = ['"Name","Spawnarg","Default value"']
        ai_base = defs["atdm:ai_base"]
        for ent in ai_base.children:
            sp = ent.spawnargs
            for s in sp.keys():
                results.append('"'+ent.name+'","'+s+'","'+sp[s]+'"')
        for row in results:
            print row
        outfile = file('ai_spawnargs.csv', 'w')
        outfile.writelines(r + '\n' for r in results)
        outfile.close()
    
    

     

     

  7. NB the only surfaces that cast shadows in our engine are those that face away from the light, in case that helps explain anything. So if you have two patches back to back between you and the light, like your tent wall, the one that's facing you will cast shadows at your feet. The one that's facing away from you will be invisible to you and also will cast no shadows from that light, because it's facing the light.

  8. Having some issues with patch mesh whilst attempting to build a tent. The outside looks alright, but the lighting on the inside is messed up (even though it's the same patch, just moved slightly and with the matrix inverted). Any suggestions on how to fix this?

    Hmm is there something in the scene that could be causing those multiple square shadows? If not you could use console command r_showShadows 2 and check it's definitely shadows, and see where they're ocming from. Judging by the guard's shadow, the sun shouldn't be lighting that wall of the tent at all.

     

    Is your tent a separate visleaf? And/or is the light source more than 2 visleafs away from the tent? There are engine optimizations that can cause missing or crazy shadows from distant visleafs.

  9. Hi. This thread will never be dead, it just goes quiet from time to time :) Yes the source code is available, both the current release (2.03) and the 2.04 alpha build both from the public svn that I think you can find at TheDarkMod.com main website. The compiled release version is the file TheDarkMod.exe that you get with a TDM download.

  10. The way I would do this is like the game Anchorhead. The gameplay is broken into chapters. When you complete the objectives for one chapter, it opens the next chapter later in the day or night. Then you can script the changes.

     

    It's more natural for our kind of game to advance time of day in parallel with the story/gameplay than procedurally.

    This, or a variation on it (say, update the skylight position every few seconds, not every frame) would be a big performance improvement.

     

    If you update a shadowcasting light position every frame, then the engine needs to calculate and upload to the GPU a new shadowcasting silhouette every frame. That's pricey, it's basically the same cost that already comes with moving torches and moving AI, known perf killers.

     

    The Strombine method of baking lighting by hand looks *really* labor-intensive. Has anyone tried it?

  11. You certainly could update the main ambient light, plus smaller local ambient lights too to stay in sync. But moving those small ambient lights around so that they stay looking natural with different sun angles would be a huge pain and no longer straightforward.

     

    A more practical plan would be katsbit's method of quickly simulating a reflected skylight by using a pair of parallel lights, the main one shadow casting and the opposing one not, and colored from the opposite side of the colour wheel.

     

    You'd want to use several parallel sun or moonlights instead of one for the whole map, for efficiency. You'd keep them all at the same angle, and cover the transitions between them with tunnels or indoor areas.

     

    One extra task with the dual light system is that you have to turn off your non-shadow-casting parallel lights when the player is indoors, using location scripts.

     

    The shadows would look the same as they do now. I don't know whether anyone has used light maps in TDM, but most rely on engine shadows plus a few ambients. The only thing like light maps in TDM is the pre caching of worldspawn shadows during dmapping. They get stored as models in your dmap file. With moving parallel lights they'd have to be calculated dynamically, but that in itself wouldn't be a problem. The perf hit from stencil shadows comes from their geometric complexity and the amount of overdraw that they create, not from having to create them in the vertex shader.

     

    Yes I have done this myself in a map... The one I was working on when I made this thread. For moonlight anyway.

     

    Daylight comes with its own problems. As someone pointed out to me in another thread, the AI spot you instantly in bright light.

    • Like 1

  12. LOL! Where, exactly?

     

    I was at the Greg (the Pontifical Gregorian University), one of the Vatican unis for a year, studying scholastic philosophy. I was living in the mediaeval English College in Rome, just off the Campo de' Fiori / Piazza Farnese. This was 20 years ago, and the CdF was a quiet square with a single vineria and no people at night. Bit different from now!

     

    No I'm not religious, although that education was :)

    • Like 2
  13. Do materials support using script variables to determine how multiple textures are combined on one surface?

     

    Yes. There's a script function setShaderParm() that you use to get numbers into material shaders.

     

    Everything is straightforward except the lit clouds, although of course setting up multiple AI paths is more work that setting up one set. And if you want a result as sophisticated as WS1, then you can multiply those multiple paths by all your multiple RIT paths too :blink:

  14. Cool, I'll give Unity a try when I get some time. I've only played 4 or 5.

     

    I was a student in Italy & love it, which is one reason why I was so hooked on the Italian episodes. It's not just the amazing reconstruction of the towns (yes, they were made smaller in AC2 too) but you can switch the game to Italian language and everyone is fully voiced, even background chat and market sellers etc. I don't know if they did that for every language, or just Italian because it was set there, but the depth of detail in AC is mind-blowing.

  15. [clouds] respecting the lighting of the sun behind them.

     

    It's not overkill :) Everything apart from the lit clouds would be do-able with a map script. You can see an example of the clocks and AI changes in grayman's WS1: In the North.

     

    For the lit clouds, you'd need a custom shader. I started work on one in the summer, developing it in shadertoy, but got sidetracked.

  16. AC2 is the best.

     

    +1

     

    AC2's graphics still look great and it captures Florence and Venice wonderfully and faithfully (except they made the canal water blue instead of green!). They didn't go to such efforts again, at least not in the next 3 episodes which is as far as I got in the series. The depiction of Rome in the next game is repetitive and generic and only recognizable by its landmarks, not by its unique architecture. Then again, Rome has changed a lot since 1500 unlike the other towns.

     

    AC isn't a full-on stealth game but it's hugely enjoyable -- the first game where physical movement is such a pleasure that it's a joy to run around even when you're not looking at stuff! It's got some stealth game mechanics: the AI aren't aware of you unless you are in their line of sight, and you can hide and do sneak kills once you get the weapons. But you won't be ghosting or studying patrols except in a few specific missions that're setup that way.

  17. Yes, parallel lights do the job perfectly. They sometimes behave weird especially if you stretch them over several visleafs, but there are workarounds like the one I posted on the last page, and once you've got them working right they are perfectly stable.

     

    Strictly speaking, parallel lights are not really parallel -- they are omni lights with the light origin moved 100000 times further away from the light centre than where you put it in DR -- but it's plenty good enough for the difference to be invisible. And in the unlikely event you can see the shadow diverge in a big scene, you can just move the light vertex further out in DR. However far you move it will be multiplied 100000x by the engine.

  18. Changing spawnargs during play will not change the model or skin. Those spawnargs are usually read once only, while the map is loading. You have to use setSkin() or setModel().

     

    Why do you want a cvar?

     

    There are 2 spare cvars built into the engine that are unused by the game, for devs to use in quick testing: r_ignore and r_ignore2. You can set them to anything you like, and read them in a script, then get the script to call setModel() etc. If you need a cvar for private testing, you can just go ahead and use them without having to recompile any c++ code.

     

    You can also set up a simple script without having to use "script objects", which are powerful but require you to learn more syntax. Again, if you just want to do some experimenting rather than package a new asset for release, you can use a simpler map script. What's it for?

  19. For the white parts of the cogs, make an alpha channel in your cog texture and set it to 0 where the white is and 1 elsewhere, where you want to see colour. Then add alphatest 0.5 to the diffuse stage in your material def like in RPGista's example. The rest of the material def isn't needed.

     

    You won't need two-sided for this, unless your cogs need to be seen from both sides and they are a simple 2d patch instead of modelled in 3d.

  20. A spawnarg on the entity sounds good... it doesn't have to toggle in realtime, just when the map loads. What would I write in the entity or model definition however, and are there any existing examples?

    Can't you just use the ordinary "model" and "skin" spawnargs in that case? The only reason to use a scriptobject or cvar would be to change it during run time.

     

    If you decide you want a script, you can use methods setSkin() and setModel() to change them during play. There're examples in tdm_lights.script because lights often change skin and model when they are switched on or off.

  21. Edit: So can I adjust the 128 so that the screen doesn't convulse so long? I'm worried it will have a heart attack :wacko:

    Yes, that was just for the test. You can make it 1.

     

    One nice thing about TDM's screenshot facility is you can take a s/shot much larger than your screen. The s/shot does a separate render, it doesn't copy directly from your screen. If you choose a huge size, like 16000x9000, you'll see bits of the scene rendered as separate tiles that fit on your screen. Then it all gets put back together again in your resulting file.

×
×
  • Create New...