The problem wouldn't be that you're using NPC 30 for other things on other maps, and those are getting turned into chickens, would it?
Wall detection isn't easy. You could try tracing a line from the hero to the NPC and seeing whether there are any walls on any of the tiles. You'll still get a few non-optimal cases around corners, but at least it's still reasonably simple. Definitely don't do what I did, and try to take into account the angle of the hero in the guard's field of view, partial obscuring by (potentially half-tile width) objects and shadows. What a disaster that script was.
But if you're really keen, go look on roguebasin for a discussion of dozens of different FOV and LOS algorithms.
TMC wrote:
The problem wouldn't be that you're using NPC 30 for other things on other maps, and those are getting turned into chickens, would it?
I don't think so, there are never guards and chickens at the same time on a map. The guard problem is mostly fixed, though the chicken one still isn't working optimally. Some chickens work, others don't. I can't figure out why it's so sporadic.
As for wall detection, I was thinking of using zones, and then doing as you suggested and just checking along a straight line between the npc and the hero. If the path doesn't cross a set zone, then it continues with the existing hero detection. If not, it stops right there and goes to the next npc.
Oh, and aye, I've spent a lot of time mucking about on roguebasin reading up all sorts of theory on FOV and LOS, hehe. I should prolly go back and re-read those, as it's been a while since I worked on my roguelike, so most of the theory is a bit muddy in my head right now.
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
I suggest using the NPC debugger (Ctrl+F11) to check what ID numbers the chickens on your map have. You can use the script debugger to check that the timer triggering the chicken script is also ticking over smoothly.
If your roguelike is anything like Legacy, I think I would want to play it :)
If your roguelike is anything like Legacy, I think I would want to play it :)
Hmm, I'll give that a shot. I'll be back later within the day (It's morning here right now) with updates as to the results.
And the roguelike? I got as far as random dungeon generation, random monster type (name, limbs, stats, armor, wealth, etc...) generation, random weapon generation, movement, wall detection, and dungeon features. But I never got around to actually designing combat or monster movement, so it's not exactly playable, hehehe.
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
And the roguelike? I got as far as random dungeon generation, random monster type (name, limbs, stats, armor, wealth, etc...) generation, random weapon generation, movement, wall detection, and dungeon features. But I never got around to actually designing combat or monster movement, so it's not exactly playable, hehehe.
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Righto, walls now work! Guards will still detect the hero, but if there's a wall in-between, then the rest of the detection script won't run thereby leaving the hero to go about his dastardly business!
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Code:
script, los checker, begin
variable(total npcs, counter, npc ref, currentX, currentY, myX, myY, baseX, baseY, counterX, counterY, npcFace, spreadCounter, spread)
variable(startX, startY, finalX, finalY, checkX, checkY, breakcheck, stepX, stepY)
if(los ID <> 0) then(
total npcs := npc copy count(los ID) -- 1 #Set the number of NPCs in the map
for(counter, 0, total npcs) do( #Cycle through all of those npcs
npc ref := npc reference(los ID, counter) #Get the reference for the npc
baseX := npc X(npc ref) #Set the base X value to the NPC's X coordinate
baseY := npc Y(npc ref) #Set the base Y value to the NPC's Y coordinate
npcFace := npc direction(npc ref) #Get the direction the particular NPC is facing
#This will check that there isn't a wall. If there is a wall, then it won't continue.
if(is wall(baseX, baseY, hero x(me), hero y(me)) == FALSE) then(
#This block sets the values of the starting and final Xs and Ys. What the block does is to set the x1, y1, x2, y2 coordinates of a
#line that will be the basis for checking what that npc can see.
#===================================================================================================================================
startX := baseX
startY := baseY
finalX := baseX
finalX := baseX
stepX := 1
stepY := 1
switch(npcFace) do(
case(North) do(finalY := baseY -- 5, stepY := -1)
case(South) do(finalY := baseY + 5)
case(West) do(finalX := baseX -- 5, stepX := -1)
case(East) do(finalX := baseX + 5)
)
#===================================================================================================================================
#spreadCounter is how wide the checking cone is. It will grow either each X
#or Y cycle based on the direction the NPC is moving.
spreadCounter := 0
#This block will go through the box (coordinates above) to check for the hero
#===============================================================================================================================
for(counterX, startX, finalX, stepX) do(
for(counterY, startY, finalY, stepY) do(
#This block expands the box (above) into a cone of sorts
#================================================================================================
for(spread, -1 -- spreadCounter, 1 + spreadCounter) do(
#checkX and checkY are the actual values that are checked against the hero's position
checkX := counterX
checkY := counterY
#myX and myY are the hero's coordinates
myX := hero X(me)
myY := hero Y(me)
#This will expand the checking area by increasing either X or Y depending on where the NPC is facing
#If the npc is moving horizontally, then the Y will expand; if vertical, then the X will expand.
if(npcFace == North || npcFace == South) then(checkX := counterX + (spread))
if(npcFace == West || npcFace == East) then(checkY := counterY + (spread))
if(checkX == myX && checkY == myY) then( #Check if the check coordinates equal the hero coordinates
suspend player
suspend npcs
breakcheck := TRUE #If it's a match, then break out of the entire loop and restart the timer
#This block was meant to have the triggered NPC run towards the player. It's disabled for now
#until I can get the rest of the script working smoothly
#----------------------------------------------------------------------------------------------
change npc id(npc ref, npc:TheocracyGuardsmanChase)
embiggen npcs
walk npc to x(npc ref, myX)
walk npc to y(npc ref, myY)
# wait for npc(npc ref)
#----------------------------------------------------------------------------------------------
use npc(npc ref) #Activate the NPC if the coordinates match up
resume npcs
resume player
)
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
)
#================================================================================================
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
if(npcFace == North || npcFace == South) then(increment(spreadCounter,1)) #Increment spread counter if vertical
)
if(npcFace == West || npcFace == East) then(increment(spreadCounter,1)) #Increment spread counter if horizontal
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
)
)
#===============================================================================================================================
)
)
end
script, is wall, x1, y1, x2, y2, begin
variable(x3, y3, stepvalue, counter, distance)
#Check for walls vertically
if(y2 -- y1 <= 0) then(stepvalue := -1) else(stepvalue := 1)
for(counter, y1, y2, stepvalue) do(
if(read zone(zone:Walls, x1, counter) == TRUE) then(exit returning(TRUE))
)
#Check for walls horizontally horizontal
if(x2 -- x1 <= 0) then(stepvalue := -1) else(stepvalue := 1)
for(counter, x1, x2, stepvalue) do(
if(read zone(zone:Walls, counter, counter) == TRUE) then(exit returning(TRUE))
)
end
script, los checker, begin
variable(total npcs, counter, npc ref, currentX, currentY, myX, myY, baseX, baseY, counterX, counterY, npcFace, spreadCounter, spread)
variable(startX, startY, finalX, finalY, checkX, checkY, breakcheck, stepX, stepY)
if(los ID <> 0) then(
total npcs := npc copy count(los ID) -- 1 #Set the number of NPCs in the map
for(counter, 0, total npcs) do( #Cycle through all of those npcs
npc ref := npc reference(los ID, counter) #Get the reference for the npc
baseX := npc X(npc ref) #Set the base X value to the NPC's X coordinate
baseY := npc Y(npc ref) #Set the base Y value to the NPC's Y coordinate
npcFace := npc direction(npc ref) #Get the direction the particular NPC is facing
#This will check that there isn't a wall. If there is a wall, then it won't continue.
if(is wall(baseX, baseY, hero x(me), hero y(me)) == FALSE) then(
#This block sets the values of the starting and final Xs and Ys. What the block does is to set the x1, y1, x2, y2 coordinates of a
#line that will be the basis for checking what that npc can see.
#===================================================================================================================================
startX := baseX
startY := baseY
finalX := baseX
finalX := baseX
stepX := 1
stepY := 1
switch(npcFace) do(
case(North) do(finalY := baseY -- 5, stepY := -1)
case(South) do(finalY := baseY + 5)
case(West) do(finalX := baseX -- 5, stepX := -1)
case(East) do(finalX := baseX + 5)
)
#===================================================================================================================================
#spreadCounter is how wide the checking cone is. It will grow either each X
#or Y cycle based on the direction the NPC is moving.
spreadCounter := 0
#This block will go through the box (coordinates above) to check for the hero
#===============================================================================================================================
for(counterX, startX, finalX, stepX) do(
for(counterY, startY, finalY, stepY) do(
#This block expands the box (above) into a cone of sorts
#================================================================================================
for(spread, -1 -- spreadCounter, 1 + spreadCounter) do(
#checkX and checkY are the actual values that are checked against the hero's position
checkX := counterX
checkY := counterY
#myX and myY are the hero's coordinates
myX := hero X(me)
myY := hero Y(me)
#This will expand the checking area by increasing either X or Y depending on where the NPC is facing
#If the npc is moving horizontally, then the Y will expand; if vertical, then the X will expand.
if(npcFace == North || npcFace == South) then(checkX := counterX + (spread))
if(npcFace == West || npcFace == East) then(checkY := counterY + (spread))
if(checkX == myX && checkY == myY) then( #Check if the check coordinates equal the hero coordinates
suspend player
suspend npcs
breakcheck := TRUE #If it's a match, then break out of the entire loop and restart the timer
#This block was meant to have the triggered NPC run towards the player. It's disabled for now
#until I can get the rest of the script working smoothly
#----------------------------------------------------------------------------------------------
change npc id(npc ref, npc:TheocracyGuardsmanChase)
embiggen npcs
walk npc to x(npc ref, myX)
walk npc to y(npc ref, myY)
# wait for npc(npc ref)
#----------------------------------------------------------------------------------------------
use npc(npc ref) #Activate the NPC if the coordinates match up
resume npcs
resume player
)
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
)
#================================================================================================
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
if(npcFace == North || npcFace == South) then(increment(spreadCounter,1)) #Increment spread counter if vertical
)
if(npcFace == West || npcFace == East) then(increment(spreadCounter,1)) #Increment spread counter if horizontal
if(breakcheck == TRUE) then(break) #If it's a match, then break out of the entire loop and restart the timer
)
)
#===============================================================================================================================
)
)
end
script, is wall, x1, y1, x2, y2, begin
variable(x3, y3, stepvalue, counter, distance)
#Check for walls vertically
if(y2 -- y1 <= 0) then(stepvalue := -1) else(stepvalue := 1)
for(counter, y1, y2, stepvalue) do(
if(read zone(zone:Walls, x1, counter) == TRUE) then(exit returning(TRUE))
)
#Check for walls horizontally horizontal
if(x2 -- x1 <= 0) then(stepvalue := -1) else(stepvalue := 1)
for(counter, x1, x2, stepvalue) do(
if(read zone(zone:Walls, counter, counter) == TRUE) then(exit returning(TRUE))
)
end
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Your iswall function is really not right. Instead of stepping along a line between the hero and the guard, you're checking for walls along two orthogonal lines from the guard.
You can use Bresenham's algorithm, but you can get away with something simpler, using fixed-point arithmetic. Psuedo-code:
You can use Bresenham's algorithm, but you can get away with something simpler, using fixed-point arithmetic. Psuedo-code:
Code:
# assuming xdiff, ydiff not both 0
if (abs(xdiff) <= abs(ydiff)):
ystep := sign(ydiff)
xstep := xdiff / ydiff #ie. abs(xstep) <= 1
else:
xstep := sign(xdiff)
ystep := ydiff / xdiff
for (i, 0, max(abs(xdiff), abs(ydiff))) do
(
x := x1 + xstep * i
y := y1 + ystep * i
check for wall at (x, y), rounded to nearest tile
)
# assuming xdiff, ydiff not both 0
if (abs(xdiff) <= abs(ydiff)):
ystep := sign(ydiff)
xstep := xdiff / ydiff #ie. abs(xstep) <= 1
else:
xstep := sign(xdiff)
ystep := ydiff / xdiff
for (i, 0, max(abs(xdiff), abs(ydiff))) do
(
x := x1 + xstep * i
y := y1 + ystep * i
check for wall at (x, y), rounded to nearest tile
)
Aye, it doesn't go on a diagonal, but I didn't quite pay enough attention during high school math class to figure it out. Still, it works well enough so far, but further testing is required.
I may try the algorithm you provided, or perhaps hit the math books and figure out more efficient code, hehe.
EDIT: Out of curiosity, do you work with code professionally? Or is it just a hobby?
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
I may try the algorithm you provided, or perhaps hit the math books and figure out more efficient code, hehe.
EDIT: Out of curiosity, do you work with code professionally? Or is it just a hobby?
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
You probably have the illusion that your iswall function works well because all your walls are large rectangles and you haven't tried the (literal!) corner cases.
Oh, it turns out that the pseudocode I gave IS for a form of Bresenham's algorithm (if you do the rounding carefully).
I don't know what you mean by 'efficient'. If you're worried about speed, don't be. That's already about as fast as possible anyway.
I'm a maths + theoretical computer science student.
Oh, it turns out that the pseudocode I gave IS for a form of Bresenham's algorithm (if you do the rounding carefully).
I don't know what you mean by 'efficient'. If you're worried about speed, don't be. That's already about as fast as possible anyway.
I'm a maths + theoretical computer science student.
Hmm, I'll give it a shot then, though I'll prolly have to break out the math textbooks to wrap my head around the equations again, hehe. I've just tested it with corners, and you're right, it doesn't function as well as it should. Back to the drawing board!
"Efficient" with regards to my existing code, it's rather kludgy, and isn't really as elegant as I could hope
Still, until I've gotten better code working properly, I'll stick with the current ISWALL function. Though it'll definitely get re-written by the time Legacy hits its first beta release.
Maths and computer science, sweet. I'm looking to get into computer science myself, but that's a bit further down the line in the future. Though I'm looking to go into computational linguistics, rather than computer science proper. And then, for my PhD, I shall create Skynet! *insert maniacal cackling here*
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
"Efficient" with regards to my existing code, it's rather kludgy, and isn't really as elegant as I could hope
Still, until I've gotten better code working properly, I'll stick with the current ISWALL function. Though it'll definitely get re-written by the time Legacy hits its first beta release.
Maths and computer science, sweet. I'm looking to get into computer science myself, but that's a bit further down the line in the future. Though I'm looking to go into computational linguistics, rather than computer science proper. And then, for my PhD, I shall create Skynet! *insert maniacal cackling here*
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
If it's that much trouble, here's the full function
Untested.
Computational linguistics: great! I quite interested in it myself. There seems to have a good group on it here in Auckland (at AUT).
Code:
script, is wall, x1, y1, x2, y2, begin
variable (xdiff, ydiff, xstep, ystep, i, x, y)
xdiff := x2 -- x1
ydiff := y2 -- y1
# assuming xdiff, ydiff not both 0
if (abs(xdiff) <= abs(ydiff)) then (
ystep := 1000* sign(ydiff)
xstep := 1000* xdiff / ydiff #ie. abs(xstep) <= 1
) else (
xstep := 1000* sign(xdiff)
ystep := 1000* ydiff / xdiff
)
for (i, 0, max(abs(xdiff), abs(ydiff))) do
(
x := x1 + (500 + xstep * i) / 1000
y := y1 + (500 + ystep * i) / 1000
if (read zone(zone:Walls, x, y)) then (exit returning(true))
)
end
variable (xdiff, ydiff, xstep, ystep, i, x, y)
xdiff := x2 -- x1
ydiff := y2 -- y1
# assuming xdiff, ydiff not both 0
if (abs(xdiff) <= abs(ydiff)) then (
ystep := 1000* sign(ydiff)
xstep := 1000* xdiff / ydiff #ie. abs(xstep) <= 1
) else (
xstep := 1000* sign(xdiff)
ystep := 1000* ydiff / xdiff
)
for (i, 0, max(abs(xdiff), abs(ydiff))) do
(
x := x1 + (500 + xstep * i) / 1000
y := y1 + (500 + ystep * i) / 1000
if (read zone(zone:Walls, x, y)) then (exit returning(true))
)
end
Untested.
Computational linguistics: great! I quite interested in it myself. There seems to have a good group on it here in Auckland (at AUT).
Development Update v0.1.7 201206242214
New Features and Developments
1. Weapons and Attacks
So, I've restructured pretty much all of my attacks. All weapons now have specific attacks, so rather than a mace and a club both sharing an attack called Bash, the mace now has an attack called Mace and the club has an attack called Club. These names aren't shown in-game, but are more a reference for me, the developer, to keep myself organized. There are currently 643 different attacks in place (Thank you again for the bulk importer TMC) ranging from physical attacks, to magical, to healing.
I now also have 70% of all the basic weapons inputted into CUSTOM. The weapon list is currently good for up to level 50. The way I have the game planned, lvl 50 will be the highest a player can get to, though I'm not quite sure how to go about doing that... Still, I'll cross that bridge when I get there.
All weapons now have elemental (12 different magical elements) attacks. Not every weapon will have an elemental attack, but 80% of them have elemental versions in their family. i.e. an iron sword won't have an elemental attack, but a fire sword (within the "sword family") does have an elemental attack.
In-game, most weapons can be given one (some up to two, and katara even more) elemental attacks through crafting. Random elemental weapons can be found or dropped by enemies, but only rarely.
2. Enemies
All enemies have been restructured within CUSTOM to sort them alphabetically rather than when they were added as before. Granted, they will be restructured again as soon as I add more enemies, but for now, everything is nice and organized.
There are currently 126 enemies imported into CUSTOM with all their stats in place. Approximately 15% of them have their attacks entered, though this should now be a fairly simple matter now that I have more attacks defined.
3. Battles
OK, I'll be the first to admit that my scripting skills aren't what I want them to be. I tried writing a custom battle engine, and got as far as placing the heroes and enemies, calculating initiative, and movement. I was, however, stopped dead by sorting initiative, tracking damage, and animating attacks. I'm sure if I really put my head to it, I'd be able to figure it out, but I decided that that would be better for another project. I'll instead focus on actually finishing Legacy first.
What I did take away from that, however, was the random choosing of enemies. Rather than creating a different formation for different levels and creatures, I instead set a marker for all maps. Dungeons will be type:dungeon, forests are type:forest, etc... within scripts. This tells my script what enemies to choose. The script then checks the map type, the time, the level of the party (averages all levels together), and the difficulty of the map. Based on that data, it chooses a set of enemies. How many enemies and what enemies are chosen are all dependent on the data. That way, you can enter a cave early in the game, fight some bats, and then later in the game at a higher level, enter the same cave and instead fight gargoyles.
This makes it so areas will always be around the same level as the player, hopefully preventing ridiculously easy fights. This does not, however, mean that all areas will be challenging. Because some areas are tagged as being easier than others, the script will choose from weaker opponents in those areas.
Another treat is that because I'm calling battles from scripts, I can randomly generate reward items. All enemies still use the built in exp and gold rewards, but not all will use the item reward option. This is instead handled by the script, allowing for a greater variety of potential drops.
One caveat though, I have yet to extensively test battles, so certain formations that I think should be appropriate for a party based on my spreadsheets, could instead be overwhelmingly difficult and nigh impossible to beat.
4. Guard Line of Sight
Partially broken, partially working. Guards can now "see" whether or not the hero is within a cone of vision in front of them. The script goes through a set number of tiles and checks for the hero, if it does, another script is triggered. Currently, the only npcs that use this are the guards in the first dungeon, but it will also be used whenever stealth is required.
It's also broken in that guards can currently sometimes see through walls. A player can currently hide behind walls and be fine, but it gets a bit funky around corners. (undergoing testing now) This will definitely be fixed before the first beta, so fear not!
Updates to Old Features
1. Menu-based dialogue
So, I initially planned for all npcs to have custom portraits (still on) and to have different colored text boxes. I soon realized though, that with the limited number of custom box appearances that I have to work with, it would be impossible to use the built in custom text box appearances to deal with every npc in the game. Instead, I designed a script that is called whenever NPCs are talked to. The script then checks who the npc is, and creates a box slice colored depending on who called the script. All the color values are stored in the script, so whenever I create a new npc, I just have to add another couple of lines to the script to deal with that npc.
2. NPC Schedules
Currently on hold, and some schedules aren't working as well as they should. Some time back, I went and restructured a lot of my scripts that left some things broken. All the machinery is in place, it just needs some tweaking to work with the new architecture. The things that are broken mostly are the individual npc actions, such as hammering iron at a forge, moving boxes, etc... Day/night schedules are still working though, and npcs will appear or disappear at different locations dependent on the time.
3. Random treasure chests
Updated. Rather than having chests marked only as vLow, Low, Average, etc... They can also take arguments such as chest:General, chest:Armor, etc... to skew the rewards towards a specific reward. chest:General, for example, is the usual random rewards that can be pretty much anything. chest:Weapon though, will only give weapon rewards. As before, the rewards are dependent on the level of the party (averaged together). Unfortunately, this means that a player could always do some meta-gaming and leave an easily accessible chest:Weapon until alter in the game, to ensure getting a more powerful weapon. I'm still figuring out an elegant way to go about this, but I haven't though of anything yet.
Anywho, that's all for now, until next time, cheers!
EDIT: Whoops! TMC posted while I was writing this, looks like my guard/walls problem is fixed. Thanks again!
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
New Features and Developments
1. Weapons and Attacks
So, I've restructured pretty much all of my attacks. All weapons now have specific attacks, so rather than a mace and a club both sharing an attack called Bash, the mace now has an attack called Mace and the club has an attack called Club. These names aren't shown in-game, but are more a reference for me, the developer, to keep myself organized. There are currently 643 different attacks in place (Thank you again for the bulk importer TMC) ranging from physical attacks, to magical, to healing.
I now also have 70% of all the basic weapons inputted into CUSTOM. The weapon list is currently good for up to level 50. The way I have the game planned, lvl 50 will be the highest a player can get to, though I'm not quite sure how to go about doing that... Still, I'll cross that bridge when I get there.
All weapons now have elemental (12 different magical elements) attacks. Not every weapon will have an elemental attack, but 80% of them have elemental versions in their family. i.e. an iron sword won't have an elemental attack, but a fire sword (within the "sword family") does have an elemental attack.
In-game, most weapons can be given one (some up to two, and katara even more) elemental attacks through crafting. Random elemental weapons can be found or dropped by enemies, but only rarely.
2. Enemies
All enemies have been restructured within CUSTOM to sort them alphabetically rather than when they were added as before. Granted, they will be restructured again as soon as I add more enemies, but for now, everything is nice and organized.
There are currently 126 enemies imported into CUSTOM with all their stats in place. Approximately 15% of them have their attacks entered, though this should now be a fairly simple matter now that I have more attacks defined.
3. Battles
OK, I'll be the first to admit that my scripting skills aren't what I want them to be. I tried writing a custom battle engine, and got as far as placing the heroes and enemies, calculating initiative, and movement. I was, however, stopped dead by sorting initiative, tracking damage, and animating attacks. I'm sure if I really put my head to it, I'd be able to figure it out, but I decided that that would be better for another project. I'll instead focus on actually finishing Legacy first.
What I did take away from that, however, was the random choosing of enemies. Rather than creating a different formation for different levels and creatures, I instead set a marker for all maps. Dungeons will be type:dungeon, forests are type:forest, etc... within scripts. This tells my script what enemies to choose. The script then checks the map type, the time, the level of the party (averages all levels together), and the difficulty of the map. Based on that data, it chooses a set of enemies. How many enemies and what enemies are chosen are all dependent on the data. That way, you can enter a cave early in the game, fight some bats, and then later in the game at a higher level, enter the same cave and instead fight gargoyles.
This makes it so areas will always be around the same level as the player, hopefully preventing ridiculously easy fights. This does not, however, mean that all areas will be challenging. Because some areas are tagged as being easier than others, the script will choose from weaker opponents in those areas.
Another treat is that because I'm calling battles from scripts, I can randomly generate reward items. All enemies still use the built in exp and gold rewards, but not all will use the item reward option. This is instead handled by the script, allowing for a greater variety of potential drops.
One caveat though, I have yet to extensively test battles, so certain formations that I think should be appropriate for a party based on my spreadsheets, could instead be overwhelmingly difficult and nigh impossible to beat.
4. Guard Line of Sight
Partially broken, partially working. Guards can now "see" whether or not the hero is within a cone of vision in front of them. The script goes through a set number of tiles and checks for the hero, if it does, another script is triggered. Currently, the only npcs that use this are the guards in the first dungeon, but it will also be used whenever stealth is required.
Updates to Old Features
1. Menu-based dialogue
So, I initially planned for all npcs to have custom portraits (still on) and to have different colored text boxes. I soon realized though, that with the limited number of custom box appearances that I have to work with, it would be impossible to use the built in custom text box appearances to deal with every npc in the game. Instead, I designed a script that is called whenever NPCs are talked to. The script then checks who the npc is, and creates a box slice colored depending on who called the script. All the color values are stored in the script, so whenever I create a new npc, I just have to add another couple of lines to the script to deal with that npc.
2. NPC Schedules
Currently on hold, and some schedules aren't working as well as they should. Some time back, I went and restructured a lot of my scripts that left some things broken. All the machinery is in place, it just needs some tweaking to work with the new architecture. The things that are broken mostly are the individual npc actions, such as hammering iron at a forge, moving boxes, etc... Day/night schedules are still working though, and npcs will appear or disappear at different locations dependent on the time.
3. Random treasure chests
Updated. Rather than having chests marked only as vLow, Low, Average, etc... They can also take arguments such as chest:General, chest:Armor, etc... to skew the rewards towards a specific reward. chest:General, for example, is the usual random rewards that can be pretty much anything. chest:Weapon though, will only give weapon rewards. As before, the rewards are dependent on the level of the party (averaged together). Unfortunately, this means that a player could always do some meta-gaming and leave an easily accessible chest:Weapon until alter in the game, to ensure getting a more powerful weapon. I'm still figuring out an elegant way to go about this, but I haven't though of anything yet.
Anywho, that's all for now, until next time, cheers!
EDIT: Whoops! TMC posted while I was writing this, looks like my guard/walls problem is fixed. Thanks again!
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Ok, so I'm stumped. Here's the scenario:
I have 4 different potions, Potion, Potion3/4, Potion1/2, and Potion1/4. Each are linked to different attacks. Ideally, when the player drinks Potion, he should lose the item Potion, and receive a new item Potion3/4, as if he only drank a fourth of the potion. This is the same when drinking Potion3/4, it should go down to Potion1/2, and then to Potion1/4. After drinking Potion1/4, the player loses Potion1/4 and then receives an item, Empty, which is basically a glass bottle.
In certain shops, the player can buy new potions, or just get refills of potions at lower prices. Because bottles are cheap, it becomes more economical to use refills instead of buying new potions. To prevent Empty items from piling up, there is a 10% chance that after drinking the final amount from a potion, the bottle is destroyed. This translates into the bottle being through so much use, that it finally broke.
And now my problem:
The new Potion items don't show up. Each item has the same When used in battle and [b]When used out of battle[/] attack. The attacks have the following bitsets attached to them:
-Cure Instead of Harm
-%based attacks damage instead of set (because healing potions heal by percentages, rather than by a fixed amount)
-Check costs when used as an item
The Costs section gives a negative value for the item, so as to increase the amount the players has.
So... Any pointers as to what I'm doing wrong? Thanks!
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
I have 4 different potions, Potion, Potion3/4, Potion1/2, and Potion1/4. Each are linked to different attacks. Ideally, when the player drinks Potion, he should lose the item Potion, and receive a new item Potion3/4, as if he only drank a fourth of the potion. This is the same when drinking Potion3/4, it should go down to Potion1/2, and then to Potion1/4. After drinking Potion1/4, the player loses Potion1/4 and then receives an item, Empty, which is basically a glass bottle.
In certain shops, the player can buy new potions, or just get refills of potions at lower prices. Because bottles are cheap, it becomes more economical to use refills instead of buying new potions. To prevent Empty items from piling up, there is a 10% chance that after drinking the final amount from a potion, the bottle is destroyed. This translates into the bottle being through so much use, that it finally broke.
And now my problem:
The new Potion items don't show up. Each item has the same When used in battle and [b]When used out of battle[/] attack. The attacks have the following bitsets attached to them:
-Cure Instead of Harm
-%based attacks damage instead of set (because healing potions heal by percentages, rather than by a fixed amount)
-Check costs when used as an item
The Costs section gives a negative value for the item, so as to increase the amount the players has.
So... Any pointers as to what I'm doing wrong? Thanks!
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Wait that doesn't answer it at all... But I think the problem may be in there somewhere...
—- So anyway, how are you?
I thought it might be that, but if it was, then the costs should still kick in and either prevent me from using the potion (can't fulfil the cost for +1 Empty) or it should go ahead and give me the Empty. Still, you may be on to something, and there may be something I've set that's cancelling out the costs.
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
Being from the third world, I reserve the right to speak in the third person.
Using Editor version wip 20170527 gfx_sdl+fb music_sdl
I'm gonna go ahead and assume it costs 1 of one thing an -1 of the other...
Check costs if used as an item should be set as well... perhaps rechecking is causing a missfire? Try testing it without that.
EDIT: Just to be sure, you're not setting -1 to the one it's supposed to take away are you?
—- So anyway, how are you?
Check costs if used as an item should be set as well... perhaps rechecking is causing a missfire? Try testing it without that.
EDIT: Just to be sure, you're not setting -1 to the one it's supposed to take away are you?
—- So anyway, how are you?



