1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
|
--[[
Copyright (c) 2014 Scott Furry
This file is part of Freedroid
Freedroid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Freedroid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Freedroid; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
]]--
-- lua module for parsing FDRPG data files for ship/level data
local modWP_Levels = {}
-- modWPCommon reference
modWP_Levels.modcommon = {}
-- Variable will contain all parsed level information after completion of ProcessLevelData()
modWP_Levels.AllLevelData = {}
-- levels.dat file parsed line-by-line into table
modWP_Levels.LevelFileData = {}
-- Storage of 2D grid map of levels at ground
modWP_Levels.GridData = {}
-- table of level numbers at ground stored by level number
modWP_Levels.LevelsGround = {}
-- table of level numbers found not at ground stored by level number
modWP_Levels.LevelsNonGround = {}
-- table of level numbers used as tutorial levels stored by level number
modWP_Levels.LevelsTutorial = {}
-- table of level numbers used for debugging/development stored by level number
modWP_Levels.LevelsDebug = {}
-- names in table format for looping
modWP_Levels.TypeNames = {
{ name = "LevelsGround", display = "Ground Levels"},
{ name = "LevelsNonGround", display = "Non-Ground Levels"},
{ name = "LevelsTutorial", display = "Tutorial Levels"},
{ name = "LevelsDebug", display = "Debug Levels"},
}
-- table of level numbers found to be unconnected/unused in FDRPG stored by level number
modWP_Levels.LevelsUnreferenced = {}
-- table of filepaths to FDRPG files used for parsing level information
modWP_Levels.files = { levels="" }
-- names of required modules - "modWP_Events"
modWP_Levels.requiredModules = { moduleNames[2].id }
-- Default grid center - value will change after trimming
modWP_Levels.grid_center = {
x = 11,
y = 11
}
-- Default grid size - value will change after trimming
modWP_Levels.grid_max = {
x = 21,
y = 21
}
-- "struct" of level information for each level
modWP_Levels.leveldata = {
levelnumber = -1,
levelname="",
bgSong = "",
is_groundlvl = false,
is_tutorial = false,
is_debug = false,
is_random = false,
levelnumber_north = -1,
levelnumber_east = -1,
levelnumber_south = -1,
levelnumber_west = -1,
levelnumber_above = -1,
levelnumber_below = {-1},
xlen = 0,
ylen = 0
}
-- text items for Level parsing and presentation
-- id) key, label) text to display loop) can use in loop when search for text
-- srchPatn) text/pattern to use to find data
-- extrctPatn) how to extract found data
modWP_Levels.textLevel = {
{ id = "levelnumber", label = "Level Number", loop = true, srchPatn = "Levelnumber:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelname", label = "Level Name", loop = true, srchPatn = "Name of this level=", extrctPatn = "[EOL]", },
{ id = "levelsize", label = "Level Size", loop = false, srchPatn = "" },
{ id = "xlen", label = "X: ", loop = true, srchPatn = "xlen of this level:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "ylen", label = "Y: ", loop = true, srchPatn = "ylen of this level:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "bgSong", label = "Background Song", loop = true, srchPatn = "BgSong=", extrctPatn = "[EOL]", },
{ id = "is_groundlvl", label = "Level at Ground", loop = false, srchPatn = "" },
{ id = "is_tutorial", label = "Tutorial Level", loop = false, srchPatn = "tutorial", extrctPatn = "[TEXT]", },
{ id = "is_debug", label = "Debug Level", loop = false, srchPatn = "debug level", extrctPatn = "[TEXT]", },
{ id = "debugcomment", label = "", loop = false, srchPatn = "%s+%-%-%s+", extrctPatn = "[TEXT]", },
{ id = "is_unref", label = "Unreferenced Level", loop = false, srchPatn = "" },
{ id = "is_random", label = "Random Generated Level", loop = true, srchPatn = "random dungeon:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelnumber_north", label = "Level To North", loop = true, srchPatn = "jump target north:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelnumber_east", label = "Level To East", loop = true, srchPatn = "jump target east:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelnumber_south", label = "Level To South", loop = true, srchPatn = "jump target south:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelnumber_west", label = "Level To West", loop = true, srchPatn = "jump target west:%s*[%d]+", extrctPatn = "[%d]+", },
{ id = "levelnumber_above", label = "Level Above", loop = false, srchPatn = "" },
{ id = "levelnumber_below", label = "Levels Below", loop = false, srchPatn = "" },
{ id = "end_of_level", label = "end_of_level", loop = true, srchPatn = "end_of_level", extrctPatn = "[TEXT]", },
}
-- test if level is a debug level
-- [in] levelnumber level to be tested
-- [ret] boolean - Y level is debug
function modWP_Levels.LevelIsDebug( levelnumber )
local retval = false
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumber, "levelnumber" )
if (( levelindex ~= nil ) and ( levelindex > 0 )) then
retval = modWP_Levels.AllLevelData[levelindex].is_debug
end
return retval
end
-- test if level is a tutorial level
-- [in] levelnumber level to be tested
-- [ret] boolean - Y level is tutorial
function modWP_Levels.LevelIsTutorial( levelnumber )
local retval = false
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumber, "levelnumber" )
if (( levelindex ~= nil ) and ( levelindex > 0 )) then
retval = modWP_Levels.AllLevelData[levelindex].is_tutorial
end
return retval
end
-- Look up leveldata variable value and its presentation label
-- Assumes AllLevelData is populated and processed
-- [in] levelitemdata object under examination (type leveldata)
-- [in] idvalue search id - same as id value in textLevel
-- [ret] pair of strings representing label|data from level item
function modWP_Levels.GetLevelItemStringsPair( levelitemdata, idvalue )
local retLabel, retData = "", ""
if (( idvalue == nil ) or ( type(idvalue) ~= 'string' ) or ( idvalue:len() <= 0 )) then
return retLabel, retData
end
local labelitem = select(1,modWP_Levels.modcommon.Extract.GetTableItem( modWP_Levels.textLevel, "id", idvalue))
if ( labelitem ~= nil ) then
retLabel = labelitem.label
if ( idvalue == "is_unref") then
retData = ""
elseif ( idvalue == "levelnumber_below" ) then
local str = ""
for key,value in pairs(levelitemdata[idvalue]) do
if (key > 1) then
str = str .. " " .. tostring(value)
else
str = tostring(value)
end
end
retData = str
elseif ( idvalue == "levelsize" ) then
retData = string.format("%02d X %02d ", levelitemdata.xlen, levelitemdata.ylen )
else
retData = tostring(levelitemdata[idvalue])
end
end
return retLabel, retData
end
-- Read in FDRPG levels and events data file.
-- Process extracted information for different level
-- information: ground, underground, debug and tutorial.
-- All level information is saved into lua tables.
-- A map of the levels at ground (GridData) is also produced.
function modWP_Levels.ProcessData()
modWP_Levels.modcommon = require("modWPCommon")
-- test for presence of source data files
modWP_Levels.files.levels = tostring(modWP_Levels.modcommon.paths.srcData .. modWP_Levels.modcommon.datafiles["levels"])
modWP_Levels.modcommon.Test.Files(modWP_Levels.files)
-- read levels.dat and process into table objects
modWP_Levels.LevelFileData = modWP_Levels.modcommon.Process.FileToLines(modWP_Levels.files["levels"])
modWP_Levels.ParseLevel()
-- generate grid from parsed Level Data
modWP_Levels.GridProcess()
-- update level data to reflect all found ground levels
-- if its referenced in the "map" grid - that level is at the same level as town or "ground level"
-- populate modWP_Levels.LevelsGround -> making 1D table of levels at ground from grid
for y = 1, modWP_Levels.grid_max.y do
for x = 1, modWP_Levels.grid_max.x do
local value = tonumber(modWP_Levels.GridSquareRead(x,y))
if (value >= 0) then
table.insert(modWP_Levels.LevelsGround, value)
end
end
end
if (#modWP_Levels.LevelsGround > 0) then
table.sort(modWP_Levels.LevelsGround)
end
local templeveldata = {}
for key,value in pairs(modWP_Levels.LevelsGround) do
local index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, value, "levelnumber" )
templeveldata = modWP_Levels.AllLevelData[index]
templeveldata.is_groundlvl = true
end
-- flag the rest - except debug/tutorial - as NON-ground levels (i.e. subterrainian)
for key, LevelItem in pairs(modWP_Levels.AllLevelData) do
if (not(LevelItem.is_groundlvl) and not(LevelItem.is_debug) and not(LevelItem.is_tutorial)) then
table.insert(modWP_Levels.LevelsNonGround, LevelItem.levelnumber)
end
end
modWP_Levels.events = require(modWP_Levels.requiredModules[1])
assert( modWP_Levels.events ~= nil )
-- find all transport events - used to map the vertical connections between levels
for key, event in pairs(modWP_Levels.events.AllEventData) do
if (( event.trigger == "teleport" ) and ( event.teleport ~= nil )) then
local indexP = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, event.teleport.lvlA, "levelnumber" )
local indexQ = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, event.teleport.lvlB, "levelnumber" )
modWP_Levels.ProcessParentChild( indexP, indexQ )
end
end
-- found all ground/non-ground/debug/tutorial levels
-- anything left over is "unreferenced" - flag and update tables with this data
for key,LevelItem in pairs(modWP_Levels.AllLevelData) do
if (not(modWP_Levels.hasreferenceIndex(key))) then
modWP_Levels.LevelsUnreferenced[#modWP_Levels.LevelsUnreferenced + 1] = LevelItem.levelnumber
-- remove reference of this level in other tables
for subkey, tbl in pairs(modWP_Levels.TypeNames) do
local levelindex = modWP_Levels.GetIndexByValue(modWP_Levels[tbl.name],LevelItem.levelnumber)
if (levelindex > 0) then
table.remove(modWP_Levels[tbl.name],levelindex)
end
end -- loop through other tables
end -- Level as reference
LevelItem["urlAnchor"] = modWP_Levels.modcommon.Wiki.HLink .. modWP_Levels.modcommon.Wiki.WikifyLink( "level" .. LevelItem.levelnumber )
end -- loop through AllLevelData
modWP_Levels.GridTrim()
end
-- retrieve the anchortext associated with this id value
function modWP_Levels.GetItemUrlText( idvalue )
local retText = ""
if ( not idvalue ) then
return retText
end
local index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, idvalue, "levelnumber" )
if ( index ) then
local item = modWP_Levels.AllLevelData[index]
retText = modWP_Levels.modcommon.outputfilenames.levels .. item.urlAnchor
end
return retText
end
-- Process Level Above/Below for each level in AllLevelData table
-- Action to update AllLevelData - level above/below information.
-- Assumes AllLevelData is populated and processed.
-- [in] indexP index value of level in AllLevelData to be processed
-- [in] indexQ index value of level in AllLevelData to be processed
function modWP_Levels.ProcessParentChild( indexP, indexQ )
local parentlvl = -1
local childlvl = -1
local parentdata = {}
local childdata = {}
local parentIsP = false
-- determine which of these two numbers is the "parent" level (above)
local isgroundP = (modWP_Levels.AllLevelData[indexP].is_groundlvl)
local isgroundQ = (modWP_Levels.AllLevelData[indexQ].is_groundlvl)
if ((isgroundP) and (not(isgroundQ))) then
parentIsP = true
elseif ((not(isgroundP)) and (isgroundQ)) then
parentIsP = false
else
-- which level is closer to ground level?
-- and would indicate it has been processed/touched
if ( (modWP_Levels.AllLevelData[indexP].levelnumber_above >= 0)
and not(modWP_Levels.AllLevelData[indexQ].levelnumber_above >= 0)) then
parentIsP = true
elseif (not(modWP_Levels.AllLevelData[indexP].levelnumber_above >= 0)
and (modWP_Levels.AllLevelData[indexQ].levelnumber_above >= 0)) then
parentIsP = false
else
-- unable to determine parent level
parentIsP = nil
end
end
if (parentIsP ~= nil) then
if (parentIsP) then
-- process modWP_Levels.AllLevelData[indexP] as parent
-- process modWP_Levels.AllLevelData[indexQ] as child
parentdata = modWP_Levels.AllLevelData[indexP]
childdata = modWP_Levels.AllLevelData[indexQ]
else
-- process modWP_Levels.AllLevelData[indexP] as child
-- process modWP_Levels.AllLevelData[indexQ] as parent
parentdata = modWP_Levels.AllLevelData[indexQ]
childdata = modWP_Levels.AllLevelData[indexP]
end
parentlvl = parentdata.levelnumber
childlvl = childdata.levelnumber
--process child/parent values
local foundlvl = false
if (not modWP_Levels.hasChildren(parentdata.levelnumber)) then
parentdata.levelnumber_below = {}
parentdata.levelnumber_below[#parentdata.levelnumber_below + 1] = childlvl
foundlvl = true
else
for key,lvldata in pairs(parentdata.levelnumber_below) do
if (lvldata == childlvl) then
-- found the child level number in the list
foundlvl = true
break
end
end
end
if (not(foundlvl)) then
parentdata.levelnumber_below[#parentdata.levelnumber_below + 1] = childlvl
end
childdata.levelnumber_above = parentlvl
if (parentIsP) then
modWP_Levels.AllLevelData[indexP] = parentdata
modWP_Levels.AllLevelData[indexQ] = childdata
else
modWP_Levels.AllLevelData[indexP] = childdata
modWP_Levels.AllLevelData[indexQ] = parentdata
end
end -- test flag parentIsP
end
-- Find the location of a level number in a table
-- [in] tabletosearch table to search for levelnumbertosearch
-- [in] levelnumbertosearch level number of level to find
-- [ret] table index or -1 if not found
function modWP_Levels.GetIndexByValue( tabletosearch, levelnumbertosearch, keyvalue )
local index = -1
for key,value in pairs(tabletosearch) do
local match = false
if ( keyvalue ~= nil ) then
match = (value[keyvalue] == levelnumbertosearch)
else
match = (value == levelnumbertosearch)
end
if (match) then
index = key
break
end
end
return index
end
-- Determine if level under examination has levels below ( using level number )
-- [in] levelnumbertosearch level number of level under examination
-- [ret] boolean (True = level has levels below)
function modWP_Levels.hasChildren( levelnumbertosearch )
local index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumbertosearch, "levelnumber" )
return modWP_Levels.hasChildrenIndex(index)
end
-- Determine if level under examination has levels below ( using table index )
-- [in] location index in AllLevelData table of level under examination
-- [ret] boolean (True = level has levels below)
function modWP_Levels.hasChildrenIndex( index )
local boolreturn = false
if (modWP_Levels.AllLevelData[index].levelnumber ~= -1) then
-- not a valid level item
for key,value in pairs(modWP_Levels.AllLevelData[index].levelnumber_below) do
if (value >= 0) then
boolreturn = true
break
end
end
end
return boolreturn
end
-- Determine if level is connected to any another levels ( using level number )
-- check the processed level data for connections N/S/E/W, above and below.
-- [in] levelnumbertosearch level number to be examined
-- [ret] boolean - does level have any connections? (true = yes)
function modWP_Levels.hasreference( levelnumbertosearch )
local index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumbertosearch, "levelnumber" )
return modWP_Levels.hasreferenceIndex(index)
end
-- Determine if level is connected to another level ( using table index )
-- check the processed level data for connections N/S/E/W, above and below
-- [in] index table index in AllLevelData of level to be examined
-- [ret] boolean - does level have any connections? (true = yes)
function modWP_Levels.hasreferenceIndex( index )
local hasref = false
if (index >= 1) then
hasref = ((modWP_Levels.AllLevelData[index].levelnumber_north >= 0)
or (modWP_Levels.AllLevelData[index].levelnumber_east >= 0)
or (modWP_Levels.AllLevelData[index].levelnumber_south >= 0)
or (modWP_Levels.AllLevelData[index].levelnumber_west >= 0)
or (modWP_Levels.AllLevelData[index].levelnumber_above >= 0)
or (modWP_Levels.AllLevelData[index].is_tutorial)
or (modWP_Levels.AllLevelData[index].is_debug)
or modWP_Levels.hasChildrenIndex(index)
)
end
return hasref
end
-- Process file data for all level information
-- Populates AllLevelData variable
function modWP_Levels.ParseLevel()
local templeveldataitem = modWP_Levels.modcommon.Extract.TblDeepCopy(modWP_Levels.leveldata)
for key,line in pairs(modWP_Levels.LevelFileData) do
for key, textitem in pairs(modWP_Levels.textLevel) do
if ( not textitem.loop ) then goto PARSE_LEVEL_NEXT_PATTERN end
-- pattern can be used in a loop
local value = modWP_Levels.modcommon.Extract.SearchText( line, textitem.srchPatn, textitem.extrctPatn )
if ( not value ) then goto PARSE_LEVEL_NEXT_PATTERN end
-- data returned from search/extract
if ( textitem.id == "end_of_level" ) then
if ( value == textitem.id ) then
modWP_Levels.AllLevelData[#modWP_Levels.AllLevelData + 1] = templeveldataitem
templeveldataitem = nil
templeveldataitem = modWP_Levels.modcommon.Extract.TblDeepCopy(modWP_Levels.leveldata)
end
elseif ( textitem.id == "levelname" ) then
templeveldataitem[textitem.id] = value
value = string.lower(templeveldataitem.levelname)
local subitem = select(1,modWP_Levels.modcommon.Extract.GetTableItem( modWP_Levels.textLevel, "id", "is_tutorial" ))
local subvalue = modWP_Levels.modcommon.Extract.SearchText( value, subitem.srchPatn, subitem.extrctPatn )
if ( subvalue ) then
templeveldataitem.is_tutorial = true
table.insert(modWP_Levels.LevelsTutorial, templeveldataitem.levelnumber)
end
local subitem = select(1,modWP_Levels.modcommon.Extract.GetTableItem( modWP_Levels.textLevel, "id", "is_debug" ))
local subvalue = modWP_Levels.modcommon.Extract.SearchText( value, subitem.srchPatn, subitem.extrctPatn )
if ( subvalue ) then
templeveldataitem.is_debug = true
table.insert(modWP_Levels.LevelsDebug, templeveldataitem.levelnumber)
-- remove everything after " -- " -> debug commentary
textpattern = select(1,modWP_Levels.modcommon.Extract.GetTableItem( modWP_Levels.textLevel, "id", "debugcomment"))
local debug_start = select(1,templeveldataitem.levelname:find(textpattern.srchPatn))
if (debug_start) then
templeveldataitem.levelname = templeveldataitem.levelname:sub(1,(debug_start - 1))
end
end
elseif ( textitem.id == "is_random" ) then
templeveldataitem.is_random = (value ~= 0)
else
templeveldataitem[textitem.id] = value
end -- process found data based on id
break -- goto next line of text
::PARSE_LEVEL_NEXT_PATTERN::
end -- loop through textLevel table looking for patterns
end -- loop through level file data
end
-- Grid Function - Process level data parsed from file into a 2D grid of levels at ground level
-- GridProcess takes the populated AllLevelData variable and attempts to build a 2D grid \"map\" of levels at ground.
--
-- Process starts with an arbitrary grid containing values all set to -1. The grid is sized to the values in grid_max.
--
-- Processing starts with the Level 0 (or \"Town" Level) located at variable grid_center. The level numbers in the
-- surrounding squares (N, E, S and W) are populated (GridSquarePopulateCross()). The \"focus\" (or CurGridLoc) is
-- changed and the process is repeated until the entire grid is populated.
--
-- Changing \"focus\" is done in a spiral movement outwards from Level 0 moving in the sequence of directions
-- S -> E -> N -> W - uses fn GridSquareChangeFocus(). Spiral movement is achieved by changing the value of curDirWriteLimit.
-- When curDirWriteLimit is equal to MaxWriteLimit(how far to write for a given direction), the direction of movement for
-- focus is changed (S -> E -> N -> W).
--
-- For example, after writing the town square, focus is moved south one, east one.
-- curDirWriteLimit is found to be equal to MaxWriteLimit. MaxWriteLimit is incremented. curDirWriteLimit is reset to 1.
-- Focus is moved north then west. curDirWriteLimit increments to two - equal to MaxWriteLimit. MaxWriteLimit is incremented.
-- curDirWriteLimit is reset to 1. Focus is moved south then east. The sequence is repeated until the grid is populated.
--
-- If grid square under focus does not have a level number( value is -1), focus is changed and processing continues with
-- the next square in sequence.
--
-- The function GridSquarePopulate() prevents bad data being stored by limiting stored values to be > 1.
--
-- Note: grid definition -> Y is row data and X is column data.
-- If accessing the grid directly, do so by using GridData[y][x], or use the function GridSquareRead().
function modWP_Levels.GridProcess()
-- populate the grid with default value
for y = 1, modWP_Levels.grid_max.y do
modWP_Levels.GridData[y] = {}
for x = 1, modWP_Levels.grid_max.x do
modWP_Levels.GridSquarePopulate( x, y, -1 )
end
end
-- fill in center square - town
local CurGridLoc = { x = modWP_Levels.grid_center.x, y = modWP_Levels.grid_center.y }
local CurLvlIndex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, 0 , "levelnumber" )
modWP_Levels.GridSquarePopulate(CurGridLoc.x, CurGridLoc.y, modWP_Levels.AllLevelData[CurLvlIndex].levelnumber)
modWP_Levels.GridSquarePopulateCross(CurGridLoc.x, CurGridLoc.y, modWP_Levels.AllLevelData[CurLvlIndex])
-- now fill in map levels for the rest of grid
local MaxWriteLimit = 2 * (modWP_Levels.grid_center.x - 2) + 1
local curDirWriteLimit = 1
local curdir = 1 -- start filling in other grid squares going south
CurGridLoc.x, CurGridLoc.y = modWP_Levels.GridSquareChangeFocus(CurGridLoc.x , CurGridLoc.y, curdir)
local curlvl = modWP_Levels.GridSquareRead(CurGridLoc.x, CurGridLoc.y)
-- we spiral outwards from center(town - level 0) going S(1)/E(2)/N(3)/W(4)
local countOfWriteCurDir = 1
local index = -1
while (curDirWriteLimit < MaxWriteLimit) do
if (curlvl >= 0) then
index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, curlvl , "levelnumber" )
modWP_Levels.GridSquarePopulateCross(CurGridLoc.x, CurGridLoc.y, modWP_Levels.AllLevelData[index])
end
countOfWriteCurDir = countOfWriteCurDir + 1
if (countOfWriteCurDir > curDirWriteLimit) then
curdir = curdir + 1
if (curdir > 4) then
curdir = 1
end
if ((curdir == 1) or (curdir == 3)) then
curDirWriteLimit = curDirWriteLimit + 1
end
countOfWriteCurDir = 1
end
if (curlvl < 0) then
CurGridLoc.x, CurGridLoc.y = modWP_Levels.GridSquareChangeFocus(CurGridLoc.x , CurGridLoc.y, curdir)
curlvl = modWP_Levels.GridSquareRead(CurGridLoc.x, CurGridLoc.y)
else
curlvl = modWP_Levels.GridGetNextSquare(modWP_Levels.AllLevelData[index], curdir)
CurGridLoc.x, CurGridLoc.y = modWP_Levels.GridSquareChangeFocus(CurGridLoc.x , CurGridLoc.y, curdir)
end
end
end
-- Grid Function - Read Level Number at a grid location
-- This is a convenience function to hide the details of grid construction.
-- See description of GridProcess()
-- [in] localx X coordinate of grid square data to read
-- [in] localy Y coordinate of grid square data to read
-- [ret] Level number found stored at grid square(x,y)
function modWP_Levels.GridSquareRead( localx, localy )
return modWP_Levels.GridData[localy][localx]
end
-- Grid Function - Write Level Number to a grid location
-- This is a convenience function to hide the details of grid construction.
-- See description of GridProcess()
-- [in] localx X coordinate of grid square data to write
-- [in] localy Y coordinate of grid square data to write
-- [in] value Level number to be written at grid square(x,y)
function modWP_Levels.GridSquarePopulate( localx, localy, value )
local gridvalue = modWP_Levels.GridData[localy][localx]
if (gridvalue ~= value) then
modWP_Levels.GridData[localy][localx] = value
end
end
-- Grid Function - Populate grid data in a N/S/E/W direction from current grid square in focus
-- [in] cross_center_x X coordinate of current grid square being processed
-- [in] cross_center_y Y coordinate of current grid square being processed
-- [in] lvldata Level data associated with the grid square being processed
function modWP_Levels.GridSquarePopulateCross( cross_center_x, cross_center_y, lvldata )
modWP_Levels.GridSquarePopulate(cross_center_x, (cross_center_y + 1), lvldata.levelnumber_south)
modWP_Levels.GridSquarePopulate((cross_center_x + 1), cross_center_y, lvldata.levelnumber_east)
modWP_Levels.GridSquarePopulate(cross_center_x, (cross_center_y - 1), lvldata.levelnumber_north)
modWP_Levels.GridSquarePopulate((cross_center_x - 1), cross_center_y, lvldata.levelnumber_west)
end
-- Grid Function - Change the grid focus for next grid square to be processed
-- [in] grid_locx X coordinate of current grid square
-- [in] grid_locy Y coordinate of current grid square
-- [in] curdir direction of processing
-- == direction can be one of four values: 1 = south, 2 = east, 3 = north, 4 = west.
-- [ret] table of x,y coordinates of grid square to be processed next
function modWP_Levels.GridSquareChangeFocus( grid_locx, grid_locy, curdir )
if (curdir == 1) then
-- south
grid_locx = grid_locx
grid_locy = grid_locy + 1
elseif (curdir == 2) then
-- east
grid_locx = grid_locx + 1
grid_locy = grid_locy
elseif (curdir == 3) then
-- north
grid_locx = grid_locx
grid_locy = grid_locy - 1
elseif (curdir == 4) then
-- west
grid_locx = grid_locx - 1
grid_locy = grid_locy
else -- shouldn't receive direction outsite of 1 <= curdir <= 4
grid_locx = -1
grid_locy = -1
end
return grid_locx, grid_locy
end
-- Grid Function - Determine the next level for grid processing
-- [in] lvldata current level being processed
-- [in] curdir direction of processing
-- == direction can be one of four values: 1 = south, 2 = east, 3 = north, 4 = west.
-- [ret] level number that is to be processed next OR -1 if not determined
function modWP_Levels.GridGetNextSquare( lvldata, curdir )
local nextlvl = -1
if (curdir == 1) then
nextlvl = lvldata.levelnumber_south
elseif (curdir == 2) then
nextlvl = lvldata.levelnumber_east
elseif (curdir == 3) then
nextlvl = lvldata.levelnumber_north
elseif (curdir == 4) then
nextlvl = lvldata.levelnumber_west
-- else -- shouldn't receive direction outsite of 1 <= curdir <= 4
end
return nextlvl
end
-- Grid Function - Examine global GridData (ground levels) and trim excess rows/columns
-- see GridDataIsTrimmable() for definition of 'Trimmable'
function modWP_Levels.GridTrim()
local trim_columns = {}
local trim_rows = {}
local size = {x = modWP_Levels.grid_max.x, y = modWP_Levels.grid_max.y}
local center = {x = modWP_Levels.grid_center.x, y = modWP_Levels.grid_center.y}
-- find all columns that can be trimmed
for y = size.y, 1, -1 do
if (modWP_Levels.GridDataIsTrimmable(y, false)) then
table.insert(trim_rows, y)
end
end
table.sort(trim_rows)
-- find all rows that can be trimmed
for x = size.x, 1, -1 do
if (modWP_Levels.GridDataIsTrimmable(x, true)) then
table.insert(trim_columns, x)
end
end
table.sort(trim_columns)
-- trim rows
for value = #trim_rows, 1, -1 do
local rowToRemove = trim_rows[value]
table.remove(modWP_Levels.GridData, rowToRemove)
if (rowToRemove < center.y) then
center.y = center.y - 1
end
size.y = size.y - 1
end
-- trim columns
for value = #trim_columns, 1, -1 do
local columnToRemove = trim_columns[value]
for n = 1, size.y do
-- for each row - remove the column
table.remove(modWP_Levels.GridData[n],columnToRemove )
end
if (columnToRemove < center.x) then
center.x = center.x - 1
end
size.x = size.x - 1
end
modWP_Levels.grid_max = { x = size.x, y = size.y }
modWP_Levels.grid_center = { x = center.x, y = center.y }
end
-- Grid Function - Determine if row/column in global GridData can be trimmed
-- Definition of a "Trimmable" column/row
-- element[j][i] = -1 for all j[1 to #col] or [1 to #row]i
-- [in] index row/column index number in grid to be examined
-- [in] isrow bool: true - index is a row value
-- false - index is a column value
-- [ret] bool - Is row/column "Trimmable" (True = Yes)
function modWP_Levels.GridDataIsTrimmable( index, isrow )
local cantrim = false
-- check incoming values are useful
if ((index == nil) or (isrow == nil)) then
return false
end
local valuefirst = -1
if (isrow) then
-- checking against row data
if ((index <= modWP_Levels.grid_max.y) and
(index >= 1)) then
for dirY = 1, modWP_Levels.grid_max.y do
valuefirst = modWP_Levels.GridSquareRead(index, dirY)
if (valuefirst >= 0) then
cantrim = false
break
else
cantrim = true
end -- check grid data at {[index | secondIndex], dirY}
end -- for loop on grid Y dir
end -- check index value will not cause read beyond grid bounds
else
-- checking against column data
if ((index <= modWP_Levels.grid_max.x) and
(index >= 1)) then
for dirX = 1, modWP_Levels.grid_max.x do
valuefirst = modWP_Levels.GridSquareRead(dirX, index)
if (valuefirst >= 0) then
cantrim = false
break
else
cantrim = true
end -- check grid data at {dirX, [index | secondIndex]}
end -- for loop on grid X dir
end -- check index value will not cause read beyond grid bounds
end -- is index a row or column value
return cantrim
end
-- Build up wiki string of underground FDRPG levels
-- This function is used recursively!
-- [in] levelnumbertosearch examine all children of this level
-- [in] indent amount of push in text from left margin
-- [ret] underlevels array of underground levels for this levelnumber
function modWP_Levels.TraverseLevels( levelnumbertosearch, indent )
local modWIKI = modWP_Levels.modcommon.Wiki
indent = indent or 0
local underlevels = {}
if (levelnumbertosearch >= 0) then
local leveltext = modWP_Levels.WikiEntryLevelAnchorText( levelnumbertosearch )
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumbertosearch , "levelnumber" )
local strindent = string.rep(" ", indent)
underlevels[#underlevels + 1] = strindent .. leveltext
if (modWP_Levels.hasChildrenIndex(levelindex)) then
for key, value in pairs(modWP_Levels.AllLevelData[levelindex].levelnumber_below) do
local underchildren = modWP_Levels.TraverseLevels(value,(indent + 2))
for k,v in pairs(underchildren) do
underlevels[#underlevels + 1] = v
end
end
end
end
return underlevels
end
-- Write FDRPG level information to file in a wiki format
function modWP_Levels.WikiWrite()
local modWIKI = modWP_Levels.modcommon.Wiki
local colourCryo = "#5f5fff"
local colourTown = "green"
local filename = modWP_Levels.modcommon.outputfilenames.levels .. ".html.md.eco"
local filepath = tostring(modWP_Levels.modcommon.paths.destRootFile .. filename)
local wikitbl = {
{ name = "LevelsDebug", link = "lvlsmapdebug", head = "Debug Levels", verbage = "Following level(s) are used for game testing/debug only:"},
{ name = "LevelsTutorial", link = "lvlsmaptutorial", head = "Tutorial Levels", verbage = "Following level(s) are used as tutorials for helping users learn how to play:"},
{ name = "LevelsUnreferenced", link = "lvlsmapunref", head = "Unreferenced Levels", verbage = "Following level(s) were found to be unconnected in the level map:"}
}
local wikitext = {}
wikitext[#wikitext + 1] = "---"
wikitext[#wikitext + 1] = "layout: 'page'"
wikitext[#wikitext + 1] = "title: 'Map Guide'"
wikitext[#wikitext + 1] = "comment: 'Description of the subparts (levels) of the map.'"
wikitext[#wikitext + 1] = ""
-- convert 'trimmed' grid to table
-- structured table
wikitext[#wikitext + 1] = "map:"
modWIKI.StartSequence()
wikitext[#wikitext + 1] = modWIKI.AddAttr('nb_columns', modWP_Levels.grid_max.x)
wikitext[#wikitext + 1] = modWIKI.AddAttr('nb_rows', modWP_Levels.grid_max.y)
wikitext[#wikitext + 1] = modWIKI.AddAttr('rows', nil)
for y = 1, modWP_Levels.grid_max.y do
modWIKI.StartMapping()
wikitext[#wikitext + 1] = modWIKI.AddAttr('columns', nil)
for x = 1, modWP_Levels.grid_max.x do
modWIKI.StartMapping()
local levelnum = modWP_Levels.GridSquareRead(x,y)
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnum , "levelnumber" )
local levelname = ""
wikitext[#wikitext + 1] = modWIKI.AddAttr('num', modWP_Levels.LevelShortLinkText(levelnum))
if levelnum ~= -1 then
levelname = modWP_Levels.AllLevelData[levelindex].levelname
wikitext[#wikitext + 1] = modWIKI.AddAttr('name', levelname)
end
if levelnum == 0 then
wikitext[#wikitext + 1] = modWIKI.AddAttr('color', colourTown)
elseif levelnum == 12 then
wikitext[#wikitext + 1] = modWIKI.AddAttr('color', colourCryo)
end
modWIKI.EndMapping()
end
modWIKI.EndMapping()
end
modWIKI.EndSequence()
wikitext[#wikitext + 1] = ""
wikitext[#wikitext + 1] = "undergrounds:"
for key, levelnumber in pairs(modWP_Levels.LevelsGround) do
if (modWP_Levels.hasChildren(levelnumber)) then
modWIKI.StartMapping()
wikitext[#wikitext + 1] = modWIKI.AddAttrArray(nil, modWP_Levels.TraverseLevels(levelnumber))
modWIKI.EndMapping()
end
end
wikitext[#wikitext + 1] = ""
wikitext[#wikitext + 1] = "special_categories:"
for key, tbl in pairs(wikitbl) do
modWIKI.StartMapping()
wikitext[#wikitext + 1] = modWIKI.AddAttr('name', tbl.head)
wikitext[#wikitext + 1] = modWIKI.AddAttr('descr', tbl.verbage)
local lvls = {}
for key, levelnumber in pairs(modWP_Levels[tbl.name]) do
lvls[#lvls + 1] = modWP_Levels.WikiEntryLevelAnchorText(levelnumber)
end
wikitext[#wikitext + 1] = modWIKI.AddAttr('levels', lvls)
modWIKI.EndMapping()
end
wikitext[#wikitext + 1] = ""
wikitext[#wikitext + 1] = "levels:"
for key, levelitem in pairs(modWP_Levels.AllLevelData)do
-- processing for surrounding levels
local index_north = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelitem.levelnumber_north, "levelnumber" )
local index_east = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelitem.levelnumber_east, "levelnumber" )
local index_south = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelitem.levelnumber_south, "levelnumber" )
local index_west = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelitem.levelnumber_west, "levelnumber" )
local level_northeast = -1
local level_northwest = -1
local level_southeast = -1
local level_southwest = -1
if index_north > 0 then
level_northeast = modWP_Levels.AllLevelData[index_north].levelnumber_east
level_northwest = modWP_Levels.AllLevelData[index_north].levelnumber_west
else
if index_east > 0 then
level_northeast = modWP_Levels.AllLevelData[index_east].levelnumber_north
end
if index_west > 0 then
level_northwest = modWP_Levels.AllLevelData[index_west].levelnumber_north
end
end
if index_south > 0 then
level_southeast = modWP_Levels.AllLevelData[index_south].levelnumber_east
level_southwest = modWP_Levels.AllLevelData[index_south].levelnumber_west
else
if index_east > 0 then
level_southeast = modWP_Levels.AllLevelData[index_east].levelnumber_south
end
if index_west > 0 then
level_southwest = modWP_Levels.AllLevelData[index_west].levelnumber_south
end
end
local levelcolour = nil
if levelitem.levelnumber == 0 then
-- town
levelcolour = colourTown
elseif levelitem.levelnumber == 12 then
-- cryo facility
levelcolour = colourCryo
end
--
modWIKI.StartMapping()
wikitext[#wikitext + 1] = modWIKI.AddAttr('id', modWIKI.WikifyLink( "level" .. levelitem.levelnumber ))
wikitext[#wikitext + 1] = modWIKI.AddAttr('name', modWP_Levels.WikiEntryLevelText(levelitem.levelnumber))
wikitext[#wikitext + 1] = modWIKI.AddAttrArray('size', { levelitem.xlen, levelitem.ylen })
wikitext[#wikitext + 1] = modWIKI.AddAttr('song', levelitem.bgSong)
if levelcolour then
wikitext[#wikitext + 1] = modWIKI.AddAttr('name_color', levelcolour)
end
local specials = {}
specials[#specials + 1] = modWIKI.AddAttr('specials', nil)
if ( not modWP_Levels.hasreference(levelitem.levelnumber) ) then
modWIKI.StartMapping()
specials[#specials + 1] = modWIKI.AddAttr('text', select(1, modWP_Levels.GetLevelItemStringsPair( levelitem, "is_unref")))
specials[#specials + 1] = modWIKI.AddAttr('color', modWIKI.ColourWarn)
modWIKI.EndMapping()
end -- level is unreferenced
if (levelitem.is_random) then
modWIKI.StartMapping()
specials[#specials + 1] = modWIKI.AddAttr('text', select(1, modWP_Levels.GetLevelItemStringsPair( levelitem, "is_random")))
specials[#specials + 1] = modWIKI.AddAttr('color', modWIKI.ColourCaution)
modWIKI.EndMapping()
end -- level is random
if (levelitem.is_tutorial) then
modWIKI.StartMapping()
specials[#specials + 1] = modWIKI.AddAttr('text', select(1, modWP_Levels.GetLevelItemStringsPair( levelitem, "is_tutorial")))
specials[#specials + 1] = modWIKI.AddAttr('color', modWIKI.ColourCaution)
modWIKI.EndMapping()
end -- level is tutorial
if (levelitem.is_debug) then
modWIKI.StartMapping()
specials[#specials + 1] = modWIKI.AddAttr('text', select(1, modWP_Levels.GetLevelItemStringsPair( levelitem, "is_debug")))
specials[#specials + 1] = modWIKI.AddAttr('color', modWIKI.ColourCaution)
modWIKI.EndMapping()
end -- level is debug
if #specials > 1 then
for k,text in ipairs(specials) do
wikitext[#wikitext + 1] = text
end
end
wikitext[#wikitext + 1] = modWIKI.AddAttrArray('neighbors',
{ modWP_Levels.LevelShortLinkText(level_northwest),
modWP_Levels.LevelShortLinkText(levelitem.levelnumber_north),
modWP_Levels.LevelShortLinkText(level_northeast),
modWP_Levels.LevelShortLinkText(levelitem.levelnumber_west),
levelitem.levelnumber,
modWP_Levels.LevelShortLinkText(levelitem.levelnumber_east),
modWP_Levels.LevelShortLinkText(level_southwest),
modWP_Levels.LevelShortLinkText(levelitem.levelnumber_south),
modWP_Levels.LevelShortLinkText(level_southeast) })
if levelitem.levelnumber_above >= 0 then
wikitext[#wikitext + 1] = modWIKI.AddAttr('level_above', modWP_Levels.WikiEntryLevelAnchorText(levelitem.levelnumber_above))
end
if modWP_Levels.hasChildren(levelitem.levelnumber) then
-- make a table of levels below
local levelsbelow = {}
for key, level in pairs(levelitem.levelnumber_below) do
levelsbelow[#levelsbelow + 1] = modWP_Levels.WikiEntryLevelAnchorText(level)
end
wikitext[#wikitext + 1] = modWIKI.AddAttrArray('levels_below', levelsbelow)
end
modWIKI.EndMapping()
end
wikitext[#wikitext + 1] = "---"
wikitext[#wikitext + 1] = ""
wikitext[#wikitext + 1] = [[
# FreedroidRPG Levels
## Map Guide
<div class="bordered-table">
<table width="100%">
<tbody>
<% for row in @document.map.rows: %>
<tr>
<% for cell in row.columns: %>
<td align="center" width="<%- 100/@document.map.nb_columns %>%">
<% if cell.num != "-1": %>
<%- cell.num %><br/>
<% if cell.color: %>
<span style="color: <%- cell.color %>;"><%- cell.name %></span>
<% else: %>
<%- cell.name %>
<% end %>
<% else: %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
# Map of Underground Levels
<% for lvl in @document.undergrounds: %>
<ul><li>
<% for s in lvl: %>
<%- s %><br/>
<% end %>
</li></ul>
<% end %>
<% for category in @document.special_categories: %>
# <%- category.name %>
<%- category.descr %>
<ul><% for lvl in category.levels: %>
<li><%- lvl %></li>
<% end %></ul>
<% end %>
# List of All FreedroidRPG Levels
<% for lvl in @document.levels: %>
<h3 id="<%- lvl.id %>" style="color: <% if lvl.name_color: %><%- lvl.name_color %><% else: %>white<% end %>;"><b><%- lvl.name %></b></h3>
<div class="row">
<div class="col-md-3 bordered-table">
<table width="100%"><tbody>
<% for idx in [0..2]: %>
<tr>
<% for neighbor in lvl.neighbors[3*idx..3*idx+2]: %>
<td align="center" width="30%">
<% if neighbor == "-1": %><span class="glyphicon glyphicon-ban-circle"></span><% else: %><%- neighbor %><% end %>
</td>
<% end %>
</tr>
<% end %>
</tbody></table>
</div>
<div class="col-md-9">
<p>
<% if lvl.specials: %>
<% for special in lvl.specials: %>
<b><span style="color: <%- special.color %>;"><%- special.text %></b><br/>
<% end %>
<% end %>
<b>Level Size:</b> X: <%- lvl.size[0] %> Y: <%- lvl.size[1] %><br/>
<b>Background Song:</b> <%- lvl.song %>
</p>
<% if lvl.level_above: %>
<p><b>Level Above:</b><br/> <%- lvl.level_above %></p>
<% end %>
<% if lvl.levels_below: %>
<p><b>Levels Below:</b><br/>
<% for lvlb in lvl.levels_below: %>
<%- lvlb %><br/>
<% end %>
</p>
<% end %>
</div>
</div>
<% end %>
]]
modWP_Levels.modcommon.Process.DataToFile(filepath, table.concat(wikitext, "\n"))
end
-- convert level number and name to text format
-- [in] levelnumber level to be converted
-- [in] label text to be used for wiki presentation
-- [in] withURL false - return just formatted anchor
-- true - return full url#anchor to level information
-- [ret] string "XX - level name"
function modWP_Levels.WikiEntryLevelText( levelnumber, label, withURL )
local asLink = false
if (( label == nil) or ( not label )) then
label = ""
else
asLink = true
end
local useURL = false
if (( withURL == nil ) or ( not withURL )) then
useURL = false
else
useURL = true
end
levelnumber = assert(tonumber(levelnumber), "WikiEntryLevelText: unable to convert " .. levelnumber)
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumber, "levelnumber" )
local levelname = modWP_Levels.AllLevelData[levelindex].levelname
local strText = string.format("%02d", tostring(levelnumber)) .. " - " .. levelname
if ( not asLink ) then
return strText
else
strText = "Level " .. strText
local urltext = ""
if ( not useURL ) then
urltext = modWP_Levels.AllLevelData[levelindex].urlAnchor
else
urltext = modWP_Levels.modcommon.outputfilenames.levels .. modWP_Levels.AllLevelData[levelindex].urlAnchor
end
return modWP_Levels.modcommon.Wiki.LinkText( urltext, strText )
end
end
function modWP_Levels.WikiEntryLevelAnchorText( levelnumber )
levelnumber = assert(tonumber(levelnumber), "WikiEntryLevelAnchorText: unable to convert " .. tostring(levelnumber))
local levelindex = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumber, "levelnumber" )
local levelname = modWP_Levels.AllLevelData[levelindex].levelname
local anchortext = modWP_Levels.AllLevelData[levelindex].urlAnchor
local levelnum = string.format("%02d", tostring(levelnumber))
return modWP_Levels.modcommon.Wiki.LinkText( anchortext, levelnum ) .. " - " .. levelname
end
function modWP_Levels.LevelShortLinkText( levelnumber )
if (( levelnumber == nil ) or ( levelnumber < 0 )) then
return tostring(levelnumber)
end
local index = modWP_Levels.GetIndexByValue( modWP_Levels.AllLevelData, levelnumber, "levelnumber" )
if ( index ) then
local levelnumformat = string.format("%02d", tostring(levelnumber))
local leveltext = modWP_Levels.AllLevelData[index].urlAnchor
return modWP_Levels.modcommon.Wiki.LinkText( leveltext, levelnumformat )
else
return tostring(levelnumber)
end
end
-- Print out level information based on selected verbosity.
function modWP_Levels.Verbosity()
if (( not modWP_Levels.modcommon.verbose) and ( not modWP_Levels.modcommon.doubleverbose)) then
return
end
local copyType = modWP_Levels.TypeNames
copyType[#copyType + 1] = { name = "LevelsUnreferenced", display = "Unreferenced Levels" }
io.stdout:write(modWP_Levels.modcommon.VerboseHeader)
io.stdout:write("All Level Data\n")
io.stdout:write(modWP_Levels.modcommon.VerboseHeader)
local sum = 0
for key, tbl in pairs(copyType) do
sum = sum + #modWP_Levels[tbl.name]
end
local printoutput = "=== Level Check ===\n"
for key, tbl in pairs(copyType) do
printoutput = printoutput .. "size of " .. tbl.display .. ": " .. #modWP_Levels[tbl.name] .. "\n"
end
printoutput = printoutput .. "size of AllLevelData = sum of above: " .. tostring((#modWP_Levels.AllLevelData == sum )) .. "\n"
io.stdout:write(printoutput)
for key, tbl in pairs(copyType) do
local str = modWP_Levels.modcommon.Extract.OneDTableToString(modWP_Levels[tbl.name])
io.stdout:write("\n=== Listing " .. tbl.display .. ":\n " .. str .. "\n")
end
io.stdout:write("\n=== Printing Ground Level Map (Grid):\n")
local writedata = ""
for y = 1, modWP_Levels.grid_max.y do
local row_data = ""
for x = 1, modWP_Levels.grid_max.x do
row_data = row_data .. string.format("%02d ", tostring(modWP_Levels.GridSquareRead(x,y)))
end
writedata = writedata .. row_data .. "\n"
end
io.stdout:write(writedata)
io.stdout:write(modWP_Levels.modcommon.VerboseHeader)
if (modWP_Levels.modcommon.doubleverbose) then
modWP_Levels.modcommon.Process.TblPrint( modWP_Levels.AllLevelData, nil, nil, "AllLevelData: " .. #modWP_Levels.AllLevelData )
for key, tbl in pairs(copyType) do
modWP_Levels.modcommon.Process.TblPrint( modWP_Levels[tbl.name], nil, nil, tbl.name .. ": " .. #modWP_Levels[tbl.name])
end
end
io.stdout:write(modWP_Levels.modcommon.VerboseHeader)
end
return modWP_Levels
|