Merge remote-tracking branch 'udb/master'

This commit is contained in:
spherallic 2024-04-05 15:25:28 +02:00
commit 2b627b0e8a
5 changed files with 89 additions and 266 deletions

View file

@ -222,26 +222,6 @@ secact_flagsrename
} }
} }
pathnode_flagsrename
{
DoomMapSetIO
{
8 = "Transition";
}
HexenMapSetIO
{
8 = "Transition";
16384 = "Invert Size Check";
}
UniversalMapSetIO
{
ambush = "Transition";
standing = "Invert Size Check";
}
}
// Default sector brightness levels // Default sector brightness levels
sectorbrightness sectorbrightness
{ {

View file

@ -1284,41 +1284,6 @@ zdoom
} }
} }
9022
{
title = "Path Node";
sprite = "internal:PathFollower";
class = "PathNode";
flagsrename { include("ZDoom_misc.cfg", "pathnode_flagsrename") }
radius = 16;
height = 56;
arg0
{
title = "TID 1";
type = 14;
}
arg1
{
title = "TID 2";
type = 14;
}
arg2
{
title = "TID 3";
type = 14;
}
arg3
{
title = "TID 4";
type = 14;
}
arg4
{
title = "TID 5";
type = 14;
}
}
9024 9024
{ {
title = "Patrol Point"; title = "Patrol Point";

View file

@ -1,114 +0,0 @@
/// <reference path="../../../udbscript.d.ts" />
`#version 4`;
`#name Connect Nodes`;
`#description Connects nodes to/from the first selected PathNode.`;
`#scriptoptions
direction
{
description = "Assignment Direction";
default = 2;
type = 11; // Enum
enumvalues {
0 = "To First";
1 = "From First";
2 = "Both";
}
}
doclear
{
description = "Clear first thing's arguments";
default = "False";
type = 3; // Boolean
}
`;
let things = UDB.Map.getSelectedThings();
if(things.length < 2)
UDB.die('You have to select at least 2 things.');
let dir = UDB.ScriptOptions.direction;
let clr = UDB.ScriptOptions.doclear;
let receiver = things[0];
let pos = 0;
let i = 0;
if (clr)
{
for (i; i < 5; i++)
receiver.args[i] = 0;
}
things.forEach(n =>
{
if (n != receiver)
{
if (dir > 0)
{
// look for the tid first, make sure it's not already assigned.
let found = false;
for (i = 0; i < 5; i++)
{
if (n.args[i] == receiver.tag)
{
found = true;
break;
}
}
// Not found, so assign it.
if (!found) for (i = 0; i < 5; i++)
{
if (n.args[i] == 0)
{
n.args[i] = receiver.tag;
break;
}
}
}
if ((dir == 0 || dir == 2) && (pos < 5 && n.tag != 0))
{
if (clr) // No special management necessary.
{
receiver.args[pos] = n.tag;
pos++;
}
else // Look for a free spot.
{
let found = false;
for (i = 0; i < 5; i++)
{
if (receiver.args[i] == n.tag)
{
found = true;
break;
}
}
if (!found)
{
for (i = pos; i < 5; i++)
{
if (receiver.args[i] == 0)
{
receiver.args[i] = n.tag;
pos = i;
found = true;
break;
}
}
}
}
}
}
});

View file

@ -1,87 +0,0 @@
/// <reference path="../../../udbscript.d.ts" />
`#version 4`;
`#name New Path Node`;
`#description Creates a new node and assigns it a TID. If a Path Node is already selected, connects the two automatically.`;
`#scriptoptions
gridsnap
{
description = "Grid Snap";
default = 1;
type = 11; // enum
enumvalues {
0 = "Disabled";
1 = "Enabled";
}
}
`;
let mpos = UDB.Map.mousePosition;
if(!mpos.isFinite())
UDB.die('Mouse cursor must be inside the map');
let nodetype = 9022;
let ntag = UDB.Map.getNewTag();
let things = UDB.Map.getSelectedThings();
let node = UDB.Map.createThing(mpos, nodetype);
if (UDB.ScriptOptions.gridsnap > 0)
node.snapToGrid();
node.tag = ntag;
let i = 0;
let count = 0;
if(things.length > 0)
{
things.forEach(n =>
{
if (n.type == nodetype)
{
// For the new node, assign the path IDs to it, up to max arguments.
if (n.tag != 0 && count < 5)
{
node.args[count] = n.tag;
count++;
}
// For the selected nodes, check for an empty slot.
let pos = -1;
for(i = 0; i < 5; i++)
{
if (n.args[i] != 0)
continue;
pos = i;
break;
}
// Check if the tag is already used first.
if (pos >= 0)
{
for (i = 0; i < 5; i++)
{
if (n.args[i] == ntag)
{
pos = -1;
break;
}
}
}
// Free slot, and unpresent. Set it in.
if (pos >= 0)
n.args[pos] = ntag;
}
});
}
UDB.Map.clearSelectedThings();
node.selected = true;

View file

@ -24,9 +24,11 @@ namespace CodeImp.DoomBuilder.ZDoom
public bool IsMixin { get; internal set; } public bool IsMixin { get; internal set; }
public bool IsExtension { get; internal set; } public bool IsExtension { get; internal set; }
public List<ZScriptClassStructure> Extensions { get; internal set; } public List<ZScriptClassStructure> Extensions { get; internal set; }
public bool IsFinal { get; internal set; }
public List<string> PermittedInheritedClassNames { get; internal set; }
// these are used for parsing and error reporting // these are used for parsing and error reporting
public ZScriptParser Parser { get; internal set; } public ZScriptParser Parser { get; internal set; }
public Stream Stream { get; internal set; } public Stream Stream { get; internal set; }
public long Position { get; internal set; } public long Position { get; internal set; }
public BinaryReader DataReader { get; internal set; } public BinaryReader DataReader { get; internal set; }
@ -36,7 +38,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// textresourcepath // textresourcepath
public string TextResourcePath { get; internal set; } public string TextResourcePath { get; internal set; }
internal ZScriptClassStructure(ZScriptParser parser, string classname, string replacesname, string parentname, bool ismixin, bool isextension, DecorateCategoryInfo region) internal ZScriptClassStructure(ZScriptParser parser, string classname, DecorateCategoryInfo region, string replacesname=null, string parentname=null, bool ismixin=false, bool isextension=false, bool isfinal=false, List<string> permittedinheritedclassnames=null)
{ {
Parser = parser; Parser = parser;
@ -56,6 +58,8 @@ namespace CodeImp.DoomBuilder.ZDoom
IsMixin = ismixin; IsMixin = ismixin;
IsExtension = isextension; IsExtension = isextension;
Extensions = new List<ZScriptClassStructure>(); Extensions = new List<ZScriptClassStructure>();
IsFinal = isfinal;
PermittedInheritedClassNames = permittedinheritedclassnames == null ? new List<string>() : new List<string>(permittedinheritedclassnames); // for the "sealed" class modifier
} }
internal void RestoreStreamData() internal void RestoreStreamData()
@ -100,6 +104,20 @@ namespace CodeImp.DoomBuilder.ZDoom
Parser.ReportError("Fatal: Class \"" + _cname + "\" is trying to inherit from \"" + _pname + "\" which does not exist."); Parser.ReportError("Fatal: Class \"" + _cname + "\" is trying to inherit from \"" + _pname + "\" which does not exist.");
return false; return false;
} }
// Make sure that the parent class isn't "final"
if(_pstruct.IsFinal)
{
Parser.ReportError($"Fatal: Class \"{_cname}\" is trying to inherit from \"{_pname}\" which is final");
return false;
}
// Make sure we're allowed to inherit from parent class
if(_pstruct.PermittedInheritedClassNames.Count > 0 && !_pstruct.PermittedInheritedClassNames.Contains(_cname.ToLowerInvariant()))
{
Parser.ReportError($"Fatal: Class \"{_cname}\" is not allowed to inherit from \"{_pname}\"");
return false;
}
} }
else _pstruct = null; else _pstruct = null;
} }
@ -730,8 +748,10 @@ namespace CodeImp.DoomBuilder.ZDoom
ZScriptToken tok_native = null; ZScriptToken tok_native = null;
ZScriptToken tok_scope = null; ZScriptToken tok_scope = null;
ZScriptToken tok_version = null; ZScriptToken tok_version = null;
ZScriptToken tok_final = null;
string[] class_scope_modifiers = new string[] { "clearscope", "ui", "play" }; string[] class_scope_modifiers = new string[] { "clearscope", "ui", "play" };
string[] other_modifiers = new string[] { "abstract" }; string[] other_modifiers = new string[] { "abstract" };
List<string> permitted_inherited_class_names = new List<string>();
while (true) while (true)
{ {
tokenizer.SkipWhitespace(); tokenizer.SkipWhitespace();
@ -777,6 +797,20 @@ namespace CodeImp.DoomBuilder.ZDoom
tok_native = token; tok_native = token;
} }
else if(token.Value.ToLowerInvariant() == "final")
{
if(tok_final != null)
{
ReportError("Cannot have two final keywords");
return false;
}
tok_final = token;
}
else if(token.Value.ToLowerInvariant() == "sealed")
{
permitted_inherited_class_names = ParseSealed();
}
else if (Array.IndexOf(class_scope_modifiers, token.Value.ToLowerInvariant()) >= 0) else if (Array.IndexOf(class_scope_modifiers, token.Value.ToLowerInvariant()) >= 0)
{ {
if (tok_scope != null) if (tok_scope != null)
@ -874,7 +908,7 @@ namespace CodeImp.DoomBuilder.ZDoom
// now if we are a class, and we inherit actor, parse this entry as an actor. don't process extensions. // now if we are a class, and we inherit actor, parse this entry as an actor. don't process extensions.
if (!isstruct && !extend && !mixin) if (!isstruct && !extend && !mixin)
{ {
ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, false, false, region); ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, (tok_replacename != null) ? tok_replacename.Value : null, (tok_parentname != null) ? tok_parentname.Value : null, false, false, tok_final != null, permitted_inherited_class_names);
cls.Position = cpos; cls.Position = cpos;
string clskey = cls.ClassName.ToLowerInvariant(); string clskey = cls.ClassName.ToLowerInvariant();
if (allclasses.ContainsKey(clskey)) if (allclasses.ContainsKey(clskey))
@ -904,7 +938,7 @@ namespace CodeImp.DoomBuilder.ZDoom
return false; return false;
} }
ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, false, true, region); ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, isextension: true);
cls.Position = cpos; cls.Position = cpos;
allclasses[clskey].Extensions.Add(cls); allclasses[clskey].Extensions.Add(cls);
} }
@ -912,7 +946,8 @@ namespace CodeImp.DoomBuilder.ZDoom
{ {
// This is a bit ugly. We're treating mixin classes as actors, even though they aren't. But otherwise the parser // This is a bit ugly. We're treating mixin classes as actors, even though they aren't. But otherwise the parser
// doesn't parse all the actor info we need // doesn't parse all the actor info we need
ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, true, false, region); // ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, null, null, true, false, false, null, region);
ZScriptClassStructure cls = new ZScriptClassStructure(this, tok_classname.Value, region, ismixin: true);
cls.Position = cpos; cls.Position = cpos;
string clskey = cls.ClassName.ToLowerInvariant(); string clskey = cls.ClassName.ToLowerInvariant();
if(mixinclasses.ContainsKey(clskey)) if(mixinclasses.ContainsKey(clskey))
@ -930,9 +965,9 @@ namespace CodeImp.DoomBuilder.ZDoom
return true; return true;
} }
// This parses the given decorate stream // This parses the given decorate stream
// Returns false on errors // Returns false on errors
public override bool Parse(TextResourceData data, bool clearerrors) public override bool Parse(TextResourceData data, bool clearerrors)
{ {
if (clearerrors) LastClasses = new HashSet<string>(); if (clearerrors) LastClasses = new HashSet<string>();
@ -1136,7 +1171,51 @@ namespace CodeImp.DoomBuilder.ZDoom
return true; return true;
} }
public bool Finalize() /// <summary>
/// Parses the class names after the "sealed" class modifier.
/// </summary>
/// <returns>A list of strings with the class names that can inherit this class</returns>
private List<string> ParseSealed()
{
ZScriptToken token;
List<string> permittedinheritedclassnames = new List<string>();
tokenizer.SkipWhitespace();
token = tokenizer.ExpectToken(ZScriptTokenType.OpenParen);
if(token == null || !token.IsValid)
{
ReportError("Expected (, got " + ((Object)token ?? "<null>").ToString());
return null;
}
while(true)
{
tokenizer.SkipWhitespace();
token = tokenizer.ExpectToken(ZScriptTokenType.Identifier);
if(token == null || !token.IsValid)
{
ReportError("Expected class name, got " + ((Object)token ?? "<null>").ToString());
return null;
}
permittedinheritedclassnames.Add(token.Value.ToLowerInvariant());
tokenizer.SkipWhitespace();
token = tokenizer.ExpectToken(ZScriptTokenType.Comma, ZScriptTokenType.CloseParen);
if(token == null || !token.IsValid)
{
ReportError("Expected , or ), got " + ((Object)token ?? "<null>").ToString());
return null;
}
if (token.Type == ZScriptTokenType.CloseParen)
break;
}
return permittedinheritedclassnames;
}
public bool Finalize()
{ {
ClearError(); ClearError();