From mwedel at sonic.net Wed Mar 1 00:18:18 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 28 Feb 2006 22:18:18 -0800 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <4404118B.6070008@telus.net> References: <20060227204815.GA4887@kirschbaum.myrealbox.com> <4403F14D.2060708@sonic.net> <4404118B.6070008@telus.net> Message-ID: <44053CAA.90005@sonic.net> Alex Schultz wrote: > Mark Wedel wrote: > >> One question I have is why even need a force. Is there any potential abuse >> just saying a player can't die when on his savebed? >> > Well, it would be trivial to make a small script on the dying player to > keep moving off of the savebed. But this then leads to an escalation of trying to prevent users from doing this vs the user that wants to do this writing scripts. After all, how hard would it be for that same player to write a script that takes them from their savebed to the newbie tower? Probably not very hard, yet it would seem that they should be allowed to be killed there. Or for that matter, the player could even just set up a portal to take him someplace. So I don't think the 'not getting player experience for killing him at or near his savebed' is really a viable way to fix this problem, as it won't be hard for players to get around that. From mwedel at sonic.net Wed Mar 1 00:33:32 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 28 Feb 2006 22:33:32 -0800 Subject: [crossfire] Unit tests In-Reply-To: <4404E4D7.5010203@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <44049C49.8000103@laposte.net> <4404E4D7.5010203@telus.net> Message-ID: <4405403C.7060804@sonic.net> Alex Schultz wrote: > Most of the tests in that directory are small tests of a specific > function, but are not very robust and have no automation. However they > may still be useful to look at for ideas of what to test and possibly > base some of the test maps off of. That python one seems like a decent > unit test of the python plugin, but not of other functions. Personally, > I think the most robust way to set up a unit test system would be > writing it mainly in C, reading from a text based script file of what to > do. The high level tests would be done mainly by map files and python > code, but I think the unit test framework should be in C as a server > plugin, so then could also have it run some lower level tests of some > individual functions of the server much easier. Yes - that seems reasonable. But at some level, higher level tests using maps are perhaps better - they are testing how the game works. It also means that if semantics of some function change (say a new flag value that can get passed), such tests should catch them better than the plugin if it makes the calls directly - it could be the function is working as expected with the new values. I certainly don't think any of the test maps I wrote would be that good for automated testing. They were useful for manual testing. I'd think for automated testing, more definable results are desired. For example, you'd want to better control the results - if doing a boulder movement test, you'd probably want walls so the boulder can move to just one or 2 spaces instead of eight to make testing the results easier, etc. > Also, I was thinking that when the server starts up with the unit test > plugin, it should fork a new copy of the server. This way, if a segfault > occurs, it can core dump, fail that test, and resume with the next test. > It also keeps the server states between the tests more separate and > helps to make sure one failed test doesn't cause other tests to fail > when they are fine. I'd think it also depends on the test. It could be nice in some regard to have 2 cycles - one where each test is run fairly isolated, and another where it does all the same tests consecutively on the same server (to better test for possible cases of structure corruption or something). It would only run this consecutive test if all the individual tests passed. That said, any test that results in a coredump is either broken code or broken test, either which should be fixed. From gabriele.diniciacci at gmail.com Wed Mar 1 08:47:44 2006 From: gabriele.diniciacci at gmail.com (Gabriele Dini Ciacci) Date: Wed, 1 Mar 2006 15:47:44 +0100 Subject: [crossfire] Ideas needed to fix exploit Message-ID: On Mon, 27 Feb 2006 21:48:15 +0100 Andreas Kirschbaum wrote: > c) Something else. > > Any ideas? > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire What about not allowing to kill a player that has not gained xp from his last death? (not that has only permaXP, but not gained xp from last death, this way we stop easy->hard skill xp transfering to some share too). So if player A is the one killed by player B the script driving player A should be more complex cause it have to locate a monster and kill it, but if a player can write a scipt that locate monster and kill it, the point of abuse does not exist anymore cause it can just run the script on player B and get easy xp while he sleep (given enougth monsters, that is the overall problem). Morover xp gain from pking imho should be related to xp lost by the pked player scaled by an ammount in server configuration file that must be basically less than 1, so a player with 2 characters can't pile xp naturally, values less than 0.5 are suggested cause this also stop easy->hard skill xp transfer. Ciao, Gabriele ----------- http://linux-wildo.sf.net http://www.diniciacci.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060301/02303668/attachment.htm From mwedel at sonic.net Thu Mar 2 00:55:47 2006 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 01 Mar 2006 22:55:47 -0800 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: References: Message-ID: <440696F3.8050502@sonic.net> Gabriele Dini Ciacci wrote: > What about not allowing to kill a player that has not gained xp from his > last death? > (not that has only permaXP, but not gained xp from last death, this way > we stop easy->hard skill xp transfering to some share too). > > So if player A is the one killed by player B the script driving player A > should be more complex cause it have to locate a monster and kill it, > but if a player can write a scipt that locate monster and kill it, the > point of abuse does not exist anymore cause it can just run the script > on player B and get easy xp while he sleep (given enougth monsters, that > is the overall problem). But I think the problem in this particular case is that killing the other player gets lots of exp - more so than killing monsters can. Also, I can think of some relatively easier ways to script exp gain - many of the item creation/identification skills can do so (smithery, jeweler, sense magic, etc). That won't get a player a whole bunch, but if the point is to reset that flag so that someone can kill that npc again, that is sufficient. Now you can start getting stuff like 'X amount of exp has to be gained before someone can get exp for killing the character'. And if X is sufficiently high, item identification won't work. > > Morover xp gain from pking imho should be related to xp lost by the pked > player scaled by an ammount in server configuration file that must be > basically less than 1, so a player with 2 characters can't pile xp > naturally, values less than 0.5 are suggested cause this also stop > easy->hard skill xp transfer. I agree on that much - as it is now, it would seem that at some point, you can get an infinite loop. So making it so that player get exp based on how much is lost seems like the safest thing to do, and also perhaps the easiest. From theapparatus at gmail.com Thu Mar 2 11:09:06 2006 From: theapparatus at gmail.com (Mike Wendell) Date: Thu, 2 Mar 2006 12:09:06 -0500 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <440696F3.8050502@sonic.net> References: <440696F3.8050502@sonic.net> Message-ID: Why not just allow the experience as a one time deal? After they kill that one other player one time, they don't get any more experience from them doing it again? -drmike On 3/2/06, Mark Wedel wrote: > Gabriele Dini Ciacci wrote: > > > What about not allowing to kill a player that has not gained xp from his > > last death? > > (not that has only permaXP, but not gained xp from last death, this way > > we stop easy->hard skill xp transfering to some share too). From nicolas.weeger at laposte.net Thu Mar 2 16:39:58 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Thu, 02 Mar 2006 23:39:58 +0100 Subject: [crossfire] Code cleanup Message-ID: <4407743E.4030400@laposte.net> Hello. Since 1.9.0 has been released, I'm gonna clean the server code some: * rename FunctionsWithCamelCaseNames to names_matching_other_functions * switch comments to Doxygen's format, to make the doc better * maybe some more tweaks This may impact quite a few files :) Nicolas From alex_sch at telus.net Thu Mar 2 17:18:04 2006 From: alex_sch at telus.net (Alex Schultz) Date: Thu, 02 Mar 2006 16:18:04 -0700 Subject: [crossfire] Code cleanup In-Reply-To: <4407743E.4030400@laposte.net> References: <4407743E.4030400@laposte.net> Message-ID: <44077D2C.9080205@telus.net> Nicolas Weeger wrote: >Hello. > >Since 1.9.0 has been released, I'm gonna clean the server code some: >* rename FunctionsWithCamelCaseNames to names_matching_other_functions >* switch comments to Doxygen's format, to make the doc better >* maybe some more tweaks > >This may impact quite a few files :) > >Nicolas > I'm currently doing some changes that affect alot of parts of the random map generator code, but that should be done soon (week or so), it it would be preferable if you wait till then do some of that there. Alex Schultz From nicolas.weeger at laposte.net Sat Mar 4 03:32:05 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Sat, 04 Mar 2006 10:32:05 +0100 Subject: [crossfire] Code cleanup In-Reply-To: <44077D2C.9080205@telus.net> References: <4407743E.4030400@laposte.net> <44077D2C.9080205@telus.net> Message-ID: <44095E95.6010207@laposte.net> > I'm currently doing some changes that affect alot of parts of the random > map generator code, but that should be done soon (week or so), it it > would be preferable if you wait till then do some of that there. Sure, I'll wait, no issue. Nicolas From antonoussik at gmail.com Mon Mar 6 09:10:50 2006 From: antonoussik at gmail.com (Anton Oussik) Date: Mon, 6 Mar 2006 15:10:50 +0000 Subject: [crossfire] Crossfire 2.0+ features/priorities In-Reply-To: <44026532.5080202@sonic.net> References: <44026532.5080202@sonic.net> Message-ID: On 27/02/06, Mark Wedel wrote: > OTOH, I'm firmly in the camp that I'd like a nice popup window on the client > where the player chooses his stats, race, class, and if we want to go in the > direction of choosing skills, that also. Me too, but then followed by two introductory maps, one for the race, where the player goes through a course learning about their race, its advantages and disadvantages and how to use it effectively, and another about their class, learning about its advantages and disadvantages and how to use it effectively. That does however requires some map making to make it interesting. From antonoussik at gmail.com Mon Mar 6 09:39:58 2006 From: antonoussik at gmail.com (Anton Oussik) Date: Mon, 6 Mar 2006 15:39:58 +0000 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <4403F14D.2060708@sonic.net> References: <20060227204815.GA4887@kirschbaum.myrealbox.com> <4403F14D.2060708@sonic.net> Message-ID: On 28/02/06, Mark Wedel wrote: > One question I have is why even need a force. Is there any potential abuse > just saying a player can't die when on his savebed? This would most likely cause most players to take unopened chests to bed with them, and practice bedroom alchemy. Going to bed when diseased would seem consistent with real life behaviour though :) Overall I agree that awarding experience based on exp loss is the best way of fixing this, although exp gained should be slightly lower than exp lost. This will prevent two players from levelling by repeatedly taking turns to kill each other. From tchize at myrealbox.com Mon Mar 6 12:31:10 2006 From: tchize at myrealbox.com (tchize) Date: Mon, 6 Mar 2006 19:31:10 +0100 Subject: [crossfire] Unit tests (was: Code cleanlieness and server stability) In-Reply-To: <44039950.8080304@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> Message-ID: <200603061931.15784.tchize@myrealbox.com> Le Mardi 28 F?vrier 2006 01:29, Alex Schultz a ?crit : >I was reading up a little bit on unit tests, and I was thinking, that it >might be an interesting idea to integrate some unit testing into the >server. The difficulty is, it would be difficult to create tests that >could work in a useful way with something as complex as the crossfire Not true, the difficult part is the work to do because nothing in server has been unit tested yet (ak lot's of unit tests to write). The complexity of code is not something that would prevent unit testing. There are 2 purpose of unit testing - Test every piece of code against expected behaviour. Those unit test are supposed to be written at the same time piece of code is written (well ideally in XP you write the unit test before you write the tested code, this way you have a clean api, but i suspect not all programmer are ready work this way) - Regression test. Each time a bug is discovered, a unit test must be written to reproduce the bug. When this unit test is written, fix code until unit test does not fail anymore. This way, you are sure if someone does something that could reactivate the bug, it will be visible at unit testing time. >The big question is, is this worth it? Well, in my opinion, it would >take a significant amount of effort to make, and useful results might >not be seen very often with it, however I feel that it might be good to >have some sort of 'stress test' like this, pushing game conditions to >their limits, and use that as yet another way to find some of the more >subtle bugs as them occur. I think that if this is implemented as a >plugin of some sort that can be optionally built, it wouldn't cutter the >server code too much either. This said, I'm not sure its the greatest >idea, but right now I'm brainstorming a bit and it does seem plausible >anyways and might have some benefits. This is very worth it, not to push server to it's limit, but simply, despite additionnal work involved by unit tests writting, you get those benefits - api stability (if a function change behaviour, unit tests success ensure the change did not break something else) - improved server stability (if there are enough unit tests to cover the code, potential server instabilities would be highlighted by failing unit tests) - better documentation. Because unit test describe the expected behaviour of a given function, we need to document the expected behaviour of a function to write it. Also a testcase is like a demo code telling other programmers how to use a given function) But i must raise my shield against the idea to make a unit testing plugin. A unit test is by definition a unit. This mean an execution unit. Unit testing is something done at compile time. A unit testing framework gather all the unit test, and runs them one after each other. For isolation purposes, each test is generally run in it's own process and/or memory address space. After each run, it gather informations on success and failures. This framework http://check.sourceforge.net/ looks very good to me, it has automake integration, a clean api and does fork to have each test on it's own address space. Unfortuately, it's not possible to run those unit test under visual studio (visual studio does not have fork()). But it should be possible to run it under cygwin or alike. List of existing unit testing frameworks: http://www.xprogramming.com/software.htm I have a good experience in java unit testing and will be glad to provide help on unit test enabling crossfire. Regards, Tchize > >Alex Schultz > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire -- -- Tchize (David Delbecq) tchize at myrealbox.com Public PGP KEY FINGERPRINT: ? ? F4BC EF69 54CC F2B5 4621 ?8DAF 1C71 8E6B 5436 C17C Public PGP KEY location: ? ? http://wwwkeys.pgp.net/pgpnet/wwwkeys.html -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060306/ca928fc1/attachment.pgp From alex_sch at telus.net Mon Mar 6 17:51:37 2006 From: alex_sch at telus.net (Alex Schultz) Date: Mon, 06 Mar 2006 16:51:37 -0700 Subject: [crossfire] Unit tests In-Reply-To: <200603061931.15784.tchize@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> Message-ID: <440CCB09.9080907@telus.net> tchize wrote: >But i must raise my shield against the idea to make a unit testing plugin. A >unit test is by definition a unit. This mean an execution unit. Unit testing >is something done at compile time. A unit testing framework gather all the >unit test, and runs them one after each other. For isolation purposes, each >test is generally run in it's own process and/or memory address space. After >each run, it gather informations on success and failures. > >This framework http://check.sourceforge.net/ looks very good to me, it has >automake integration, a clean api and does fork to have each test on it's own >address space. Unfortuately, it's not possible to run those unit test under >visual studio (visual studio does not have fork()). But it should be possible >to run it under cygwin or alike. > >List of existing unit testing frameworks: >http://www.xprogramming.com/software.htm > > Actually, I was looking at those a bit, including that one at http://check.sourceforge.net/ however I think that using one of those frameworks might be somewhat bloated for our needs, and more flexibility would be good. I believe that writing our own minimalistic framework, tuned to crossfire, would be a better solution. Also, I'm not sure how good those frameworks are at doing a core dump in the event that a test segfaults, which given that a significant amount of the bugs that are getting fixes are segfault ones, is an important feature for any test framework that will be used for crossfire. In terms of isolation, I agree that some is needed. I was thinking that forking for each test (perhaps starting a new server, with some argvs, would be an alternative method for platforms with no support for fork). One idea that Mark Wedel brought up on IRC a few days back, was possibly first running each test in isolation, then afterwards, run them in series without isolation, to make the test more robust. In terms of as a plugin, what I meant, is that to test, it could be loaded at startup time using some of the plugin code, and essentially overrides the normal server operation and reads a text file defining the tests. I'm not sure that is the best idea, but that was what I was thinking at the time. One flaw with that anyways, is it would be good for defining high level tests (see next paragraph), but it would be rather poor for defining lower level tests of functions. I think both high and low level tests are important, perhaps some 'hybrid' ones too. High level being ones were it loads and runs a map, and checks conditions after a certain number of ticks. Low level being running an isolated server function. Hybrid ones being ones that load a map and check a low level server function on that map. Also, thanks for clearing up a bit of that in the first paragraph of your original reply. I already became aware that some of what I said was not entirely accurate, but what you said clears it up further. --Alex Schultz From mwedel at sonic.net Tue Mar 7 00:38:16 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 06 Mar 2006 22:38:16 -0800 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: References: <20060227204815.GA4887@kirschbaum.myrealbox.com> <4403F14D.2060708@sonic.net> Message-ID: <440D2A58.2010409@sonic.net> Anton Oussik wrote: > On 28/02/06, Mark Wedel wrote: >> One question I have is why even need a force. Is there any potential abuse >> just saying a player can't die when on his savebed? > > This would most likely cause most players to take unopened chests to > bed with them, and practice bedroom alchemy. Going to bed when > diseased would seem consistent with real life behaviour though :) I hadn't thought about that. But I suppose if this was really a concern, then perhaps the check of a player not being killed/killing another player on his savebed could get around that without need of a force and still prevent players from opening chests on their savebed. I don't think the issue would be as much as going to bed, but rather that character that is about to die (poison/disease), not having the means to heal it and going to the savebed as a 'safe place'. > > Overall I agree that awarding experience based on exp loss is the best > way of fixing this, although exp gained should be slightly lower than > exp lost. This will prevent two players from levelling by repeatedly > taking turns to kill each other. Right - at most you could get is the amount the other character loses. That said, even if two players just took turns bashing themselves, the end result is they will have just as much exp at the end as when they start (presuming no loss) - the difference would be in which skills they have it in. Since combat exp is probably the easiest to get, this may not be a good trade off. From mwedel at sonic.net Tue Mar 7 00:51:46 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 06 Mar 2006 22:51:46 -0800 Subject: [crossfire] Crossfire 2.0+ features/priorities In-Reply-To: References: <44026532.5080202@sonic.net> Message-ID: <440D2D82.2080601@sonic.net> Anton Oussik wrote: > On 27/02/06, Mark Wedel wrote: >> OTOH, I'm firmly in the camp that I'd like a nice popup window on the client >> where the player chooses his stats, race, class, and if we want to go in the >> direction of choosing skills, that also. > > Me too, but then followed by two introductory maps, one for the race, > where the player goes through a course learning about their race, its > advantages and disadvantages and how to use it effectively, and > another about their class, learning about its advantages and > disadvantages and how to use it effectively. That does however > requires some map making to make it interesting. I could perhaps see some special maps for the special races (fireborn, dragon, maybe another). I can't really see the need of separate/unique maps for most of the humanoid races. Is an elf really much different than a dwarf than a human? Sure, there are a few different skills that each get, but they are similar in a larger regard (item identification/creation). The class one would perhaps sort of mimic the current newbie one? How to kill creatures, pick up objects, etc? I wonder if that could be expanded, like 'if you have a spell, this is how you cast it', etc. So new players could do what tasks are relevant for their class. Yet at the same time, see other things that can be done. I wonder if these could also be made as unique maps for each player, so they could also revisit them later (for example, it may be several levels, but that fighter may start picking up spellcasting, and being able to revisit the introductory dungeon and learn about spellcasting could be handy). This also has the advantage that if players bypass it/exit it prematurely, they could re-enter it. There should be a way for experience players to largely skip it, but then you get the case of inexperience players skipping out and realizing they need that stuff. IF they can be pointed with something like 'go to Introductory Building next to the inn', that would be easy enough. Another random thought - the idea of being able to start in different places has been raised. I wonder if this could be one of those places, which then just exits to scorn. If a player is experienced enough to start in navar, then they shouldn't need that introductory dungeon. From mwedel at sonic.net Tue Mar 7 01:06:28 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 06 Mar 2006 23:06:28 -0800 Subject: [crossfire] Unit tests In-Reply-To: <440CCB09.9080907@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> Message-ID: <440D30F4.4030801@sonic.net> While what tchize says about writing unit tests make sense, I'm also a little skeptical that it will actually get done in the way described and/or have other bad effects. For example, if there is the requirement that a unit test be written to test/confirm bug fixes, I could see it leading some people say they don't really want to spend the time to write such a test when the fix itself is trivial. And then they don't fix the bug. Likewise, while writing unit tests before any large changes are done, I know from my experience finding time to actually code the change and do basic testing is difficult. If it now takes 50% longer because unit tests also have to be written, that has various implications. In my ideal world, I'd love for there to be unit tests for everything. I'm just not sure what level we can really achieve. If we create/enforce draconian policies, I think the more likely scenario is people just stop writing new code, and not that they write unit tests (and/or they fork the code to a version such that they don't have to write unit tests). I'm certainly not saying unit tests are a bad thing. But I think we have to keep in mind the people who are likely to write the tests. All that said, quick thoughts: 1) Basic function/API tests should be easy to write in most cases (if I call xyz(a,b) does it do the right thing). Those shouldn't be much an issue. 2) A lot of the code operates on extensive external state (map data, archetypes, etc). So to test the function, you need to have a map set up in the right way (right objects on the map, etc). In this case, you want something that makes such a test easy. What may be easiest is in fact just a large set of test maps, and the unit test could effectively hard code those, with known coordinates (test object being only object at 0,0 and I know I want to insert that at 5,5) My thinking here is that if I can write the basic test to reproduce the bug in <10 minutes, I'll probably write the test. IF the framework is such that it will take me an hour, then I probably wouldn't. 3) If the number of tests grow, it is probably desirable to be able to run some specific subset of tests, eg, I don't want to have to wait 15 minutes for the server to run all the tests when I'm trying to fix some specific bug - I just want it to run my test. After all is done, then perhaps running all tests before commit makes sense. From tchize at myrealbox.com Tue Mar 7 02:14:07 2006 From: tchize at myrealbox.com (Tchize) Date: Tue, 07 Mar 2006 09:14:07 +0100 Subject: [crossfire] Unit tests In-Reply-To: <440D30F4.4030801@sonic.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D30F4.4030801@sonic.net> Message-ID: <440D40CF.7090409@myrealbox.com> Mark Wedel a ?crit : > While what tchize says about writing unit tests make sense, I'm also a little >skeptical that it will actually get done in the way described and/or have other >bad effects. > > For example, if there is the requirement that a unit test be written to >test/confirm bug fixes, I could see it leading some people say they don't really >want to spend the time to write such a test when the fix itself is trivial. And >then they don't fix the bug. > > If the bug is trivial, the unit test is trivial and could be written in a 1 or 2 minutes. Writting the test is simply the same as discovering how the bug can arise. If the bug happens on a specific map, for example, then it's just a matter of copying that map in test directory with a specific name, write a testcase using that map (should take no more than 3 lines of code to init this test), identify the wrong state of object (simply mean locate object a X,Y in map, check a given value for correctness). > Likewise, while writing unit tests before any large changes are done, I know >from my experience finding time to actually code the change and do basic testing >is difficult. If it now takes 50% longer because unit tests also have to be >written, that has various implications. > > From tchize at myrealbox.com Tue Mar 7 02:27:54 2006 From: tchize at myrealbox.com (Tchize) Date: Tue, 07 Mar 2006 09:27:54 +0100 Subject: [crossfire] Unit tests In-Reply-To: <440CCB09.9080907@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> Message-ID: <440D440A.204@myrealbox.com> Alex Schultz a ?crit : >tchize wrote: > > > >>But i must raise my shield against the idea to make a unit testing plugin. A >>unit test is by definition a unit. This mean an execution unit. Unit testing >>is something done at compile time. A unit testing framework gather all the >>unit test, and runs them one after each other. For isolation purposes, each >>test is generally run in it's own process and/or memory address space. After >>each run, it gather informations on success and failures. >> >>This framework http://check.sourceforge.net/ looks very good to me, it has >>automake integration, a clean api and does fork to have each test on it's own >>address space. Unfortuately, it's not possible to run those unit test under >>visual studio (visual studio does not have fork()). But it should be possible >>to run it under cygwin or alike. >> >>List of existing unit testing frameworks: >>http://www.xprogramming.com/software.htm >> >> >> >> >Actually, I was looking at those a bit, including that one at >http://check.sourceforge.net/ however I think that using one of those >frameworks might be somewhat bloated for our needs, and more flexibility >would be good. I believe that writing our own minimalistic framework, >tuned to crossfire, would be a better solution. Also, I'm not sure how >good those frameworks are at doing a core dump in the event that a test >segfaults, which given that a significant amount of the bugs that are >getting fixes are segfault ones, is an important feature for any test >framework that will be used for crossfire. > > check does fork(), it provide address space isolation, that mean a testcase doing a segfault will be marked as 'failed' but will not jeopardize running of other tests. check is just a mather of including a .m4 and a .a in the project, i don't think it's over bloated >In terms of isolation, I agree that some is needed. I was thinking that >forking for each test (perhaps starting a new server, with some argvs, >would be an alternative method for platforms with no support for fork). >One idea that Mark Wedel brought up on IRC a few days back, was possibly >first running each test in isolation, then afterwards, run them in >series without isolation, to make the test more robust. > > No you must isolate each of your fixture, provide each of them with a clean environment, this is because cf uses lots of static variables. Those must be reset before each test. If you have a few testcase that can be safely run in same address space, they are gathered in a fixture. A fixture is a setup methode, n testcases and a tearDown() method. >In terms of as a plugin, what I meant, is that to test, it could be >loaded at startup time using some of the plugin code, and essentially >overrides the normal server operation and reads a text file defining the >tests. I'm not sure that is the best idea, but that was what I was >thinking at the time. One flaw with that anyways, is it would be good >for defining high level tests (see next paragraph), but it would be >rather poor for defining lower level tests of functions. > >I think both high and low level tests are important, perhaps some >'hybrid' ones too. High level being ones were it loads and runs a map, >and checks conditions after a certain number of ticks. Low level being >running an isolated server function. Hybrid ones being ones that load a >map and check a low level server function on that map. > > Map loading, network protocol checking and so on are not really problems with a classical framework. unit testing framework are made easy to use, are robust and are able, at some level, to provide with clean test reports. Each project then add it's test toolkits around that to do general setup operations. Those frameworks are made to be adaptable to any project, what ever it's specificity. I can't see a specificity in crossfire that would justify to reinvent the wheel. >Also, thanks for clearing up a bit of that in the first paragraph of >your original reply. I already became aware that some of what I said was >not entirely accurate, but what you said clears it up further. > > > No problem. > --Alex Schultz > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From alex_sch at telus.net Tue Mar 7 08:11:40 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 07 Mar 2006 07:11:40 -0700 Subject: [crossfire] Unit tests In-Reply-To: <440D440A.204@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D440A.204@myrealbox.com> Message-ID: <440D949C.3070207@telus.net> Tchize wrote: >check does fork(), it provide address space isolation, that mean a >testcase doing a segfault will be marked as 'failed' but will not >jeopardize running of other tests. > I expected that it would mark tests as failed in those cases, but would (be able to) it generate a core dump of the fork at the point of segfault? Is this possible to add to it's existing framework? Alex Schultz From tchize at myrealbox.com Tue Mar 7 11:53:16 2006 From: tchize at myrealbox.com (tchize) Date: Tue, 7 Mar 2006 18:53:16 +0100 Subject: [crossfire] Unit tests In-Reply-To: <440D949C.3070207@telus.net> References: <44021342.9050604@telus.net> <440D440A.204@myrealbox.com> <440D949C.3070207@telus.net> Message-ID: <200603071853.22891.tchize@myrealbox.com> It is said in documentation you can disable the fork if you need to run debuggers on the unit test :) (This include generating a core i suppose) Le Mardi 7 Mars 2006 15:11, Alex Schultz a ?crit : >Tchize wrote: >>check does fork(), it provide address space isolation, that mean a >>testcase doing a segfault will be marked as 'failed' but will not >>jeopardize running of other tests. > >I expected that it would mark tests as failed in those cases, but would >(be able to) it generate a core dump of the fork at the point of >segfault? Is this possible to add to it's existing framework? > >Alex Schultz > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire -- -- Tchize (David Delbecq) tchize at myrealbox.com Public PGP KEY FINGERPRINT: ? ? F4BC EF69 54CC F2B5 4621 ?8DAF 1C71 8E6B 5436 C17C Public PGP KEY location: ? ? http://wwwkeys.pgp.net/pgpnet/wwwkeys.html -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060307/9566e259/attachment.pgp From kirschbaum at myrealbox.com Tue Mar 7 15:33:40 2006 From: kirschbaum at myrealbox.com (Andreas Kirschbaum) Date: Tue, 7 Mar 2006 22:33:40 +0100 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <20060227204815.GA4887@kirschbaum.myrealbox.com> References: <20060227204815.GA4887@kirschbaum.myrealbox.com> Message-ID: <20060307213340.GA7493@kirschbaum.myrealbox.com> It seems to me that the consensus is to base the exp gain of the attacker on the exp loss of the victim. The amount should be settable in the config file. A possible transferral of exp between skills is not considered a problem. That said, I think I'll add a new setting pk_exp_ratio which takes a value between 0 (no exp gain for pk) and 100 (attacker gains all exp the victim loses) with a default of 50. The current code limits the exp gain to 5 million. Should I keep this limit, or add just another settings variable (pk_exp_limit, defaults to 5 million)? From kirschbaum at myrealbox.com Tue Mar 7 15:44:22 2006 From: kirschbaum at myrealbox.com (Andreas Kirschbaum) Date: Tue, 7 Mar 2006 22:44:22 +0100 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <4403F14D.2060708@sonic.net> References: <20060227204815.GA4887@kirschbaum.myrealbox.com> <4403F14D.2060708@sonic.net> Message-ID: <20060307214422.GB7493@kirschbaum.myrealbox.com> Mark Wedel wrote: > Andreas Kirschbaum wrote: > > b) Reward a (pk) with MIN(5 million, (exp loss of victim)/10). > > > > I'm not sure if that really is a good idea since it probably creates > > another exploit: kill a player with some hard to train skill and gain > > lots of exp in that skill. > > I'm not sure I follow that logic - it doesn't seem to be any worse than now. > > If I can (hypothetically) kill someone with bad singing, that change above > doesn't make things any easier or harder. I won't get any more exp than I did > before that change, and will likely get less. If the player being killed is > down to having only permanent exp left (thus doesn't lose anything), I gain > no exp. The problem I see is that the current code calls calc_skill_exp() which probably returns a quite different value than the exp loss of the victim. Thus it may be possible to find a hard to train skill (which gives very few exp from calc_skill_exp()) which now gives lots of exp due to a huge exp loss of the victim. That said, the exploit would be to train a throw-away character with easily trainable skills, then kill it with the "real" character and with a hard to train skill. The result is that the "real" character gains lots of exp in the otherwise hard to train skill. From kirschbaum at myrealbox.com Tue Mar 7 16:04:35 2006 From: kirschbaum at myrealbox.com (Andreas Kirschbaum) Date: Tue, 7 Mar 2006 23:04:35 +0100 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: References: <440696F3.8050502@sonic.net> Message-ID: <20060307220434.GC7493@kirschbaum.myrealbox.com> Mike Wendell wrote: > Why not just allow the experience as a one time deal? After they kill > that one other player one time, they don't get any more experience > from them doing it again? When do you want to reset this flag? If it is reset after a fixed time period, how does a player know when he would gain exp again? If it is reset after some exp gain, it probably can be easily circumvented. Or does it never reset, and the victim and/or attacker accumulates pk-forces? (Which probably could be interesting for DMs to be able to check the pk-history of a player...) Note that using only one force ("last victim killed") is not sufficient: just kill two victims in turn. From alex_sch at telus.net Tue Mar 7 17:16:57 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 07 Mar 2006 16:16:57 -0700 Subject: [crossfire] Unit tests In-Reply-To: <200603071853.22891.tchize@myrealbox.com> References: <44021342.9050604@telus.net> <440D440A.204@myrealbox.com> <440D949C.3070207@telus.net> <200603071853.22891.tchize@myrealbox.com> Message-ID: <440E1469.1070305@telus.net> Hmm, I was thinking it could be nice though if it could automatically generate core dumps for segfaulted unit tests, and continue to further unit tests after. That would need both forks and integrated per fork core dump capability, which that unit test framework doesn't appear to allow. tchize wrote: >It is said in documentation you can disable the fork if you need to run >debuggers on the unit test :) (This include generating a core i suppose) > > >Le Mardi 7 Mars 2006 15:11, Alex Schultz a ?crit : > > >>Tchize wrote: >> >> >>>check does fork(), it provide address space isolation, that mean a >>>testcase doing a segfault will be marked as 'failed' but will not >>>jeopardize running of other tests. >>> >>> >>I expected that it would mark tests as failed in those cases, but would >>(be able to) it generate a core dump of the fork at the point of >>segfault? Is this possible to add to it's existing framework? >> >>Alex Schultz >> From mwedel at sonic.net Wed Mar 8 00:36:30 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 07 Mar 2006 22:36:30 -0800 Subject: [crossfire] Unit tests In-Reply-To: <440D40CF.7090409@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D30F4.4030801@sonic.net> <440D40CF.7090409@myrealbox.com> Message-ID: <440E7B6E.3090409@sonic.net> Note that the complexity of writing tests is likely to be directly inverse to how powerful the test utilities are. For example, a lot tests may require non trivial maps, so it takes some time to create that map. But specific actions perhaps also need to be done (casting a spell in direction X). So you need some framework which easily lets one cast that spell. Some bugs may be reproducible on existing maps, but using those as is may not be desirable, as they could change - so ideally, you want to copy the map(s) in question and minimize the map to just reproduce the bug, and not have a lot of other stuff (otherwise, I could envision an unrelated archetype change making the map not work the same (say spell effect no longer reaches target). That archetype change isn't testing the bug in question). One thought I have could also be those working on/writing the unit test suite to look at some of the current bugs and write unit tests for those (whether they want to fix the bug is separate) - just having the bug reports updated like 'unit test Z reproduces this bug' will make it easier for those that actually fix the bug. Also, I think there is probably some level of example code. The first few people to write the unit tests probably have a bit of a learning curve. But those later can look at those existing tests and probably more easily figure out how to modify them for their purpose. From mwedel at sonic.net Wed Mar 8 00:53:26 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 07 Mar 2006 22:53:26 -0800 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <20060307220434.GC7493@kirschbaum.myrealbox.com> References: <440696F3.8050502@sonic.net> <20060307220434.GC7493@kirschbaum.myrealbox.com> Message-ID: <440E7F66.9070705@sonic.net> Andreas Kirschbaum wrote: > Mike Wendell wrote: >> Why not just allow the experience as a one time deal? After they kill >> that one other player one time, they don't get any more experience >> from them doing it again? > > When do you want to reset this flag? If it is reset after a fixed time > period, how does a player know when he would gain exp again? If it is > reset after some exp gain, it probably can be easily circumvented. > > Or does it never reset, and the victim and/or attacker accumulates > pk-forces? (Which probably could be interesting for DMs to be able to > check the pk-history of a player...) If it is permanent, I'd probably suggest using just a single 'PK' force and subvert the msg field to contain the kill list, like : or something. that could be interesting on a PK server for even the players to see that. Since PKing is a relative infrequent event (even on PK happy servers I'm sure it is compared to monsters being killed) the time to process that probably isn't that bad. I do remember I think it was moria that would track how many of the different types of creatures you kill, and based on that number, you could get more info on the creatures themselves. While interesting, probably a bit overkill for crossfire. From lalo.martins at gmail.com Wed Mar 8 05:04:41 2006 From: lalo.martins at gmail.com (Lalo Martins) Date: Wed, 08 Mar 2006 19:04:41 +0800 Subject: [crossfire] Unit tests In-Reply-To: <440E7B6E.3090409@sonic.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D30F4.4030801@sonic.net> <440D40CF.7090409@myrealbox.com> <440E7B6E.3090409@sonic.net> Message-ID: And so says Mark Wedel on 08/03/06 14:36... > For example, a lot tests may require non trivial maps, so it takes some time > to create that map... note, we're talking about "unit" tests here. By definition, they don't use maps. The traditional "unit" for C unit tests is a function - so each test case (a set of individual tests) will test a given function. Unit tests are much more low-level than a few of the posters in this thread are thinking. The kind of tests that would include loading maps and checking for correct behaviour, is what we usually call "functional" tests. They are desirable too, but much harder to get right and complete than unit tests. best, Lalo Martins -- So many of our dreams at first seem impossible, then they seem improbable, and then, when we summon the will, they soon become inevitable. -- personal: http://www.laranja.org/ technical: http://lalo.revisioncontrol.net/ GNU: never give up freedom http://www.gnu.org/ From tchize at myrealbox.com Wed Mar 8 06:53:21 2006 From: tchize at myrealbox.com (Tchize) Date: Wed, 08 Mar 2006 13:53:21 +0100 Subject: [crossfire] Unit tests In-Reply-To: References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D30F4.4030801@sonic.net> <440D40CF.7090409@myrealbox.com> <440E7B6E.3090409@sonic.net> Message-ID: <440ED3C1.70004@myrealbox.com> Lalo Martins a ?crit : >And so says Mark Wedel on 08/03/06 14:36... > > >> For example, a lot tests may require non trivial maps, so it takes some time >>to create that map... >> >> > >note, we're talking about "unit" tests here. By definition, they don't >use maps. The traditional "unit" for C unit tests is a function - so >each test case (a set of individual tests) will test a given function. >Unit tests are much more low-level than a few of the posters in this >thread are thinking. > >The kind of tests that would include loading maps and checking for >correct behaviour, is what we usually call "functional" tests. They are >desirable too, but much harder to get right and complete than unit tests. > >best, > Lalo Martins > > You are right. Basic purpose of unit testing is to check the functions for correctness and prevent regression after future modifications. But it's also quite common to write unit test that test the behaviour of the integrated system. They then do test on a full life cycle of code. This is mainly used when bugs have been identified. But it is also incorrect to think functionnal unit test would not require maps. Some methods in code can not work properly without a map (like all get/put_ob_in_map()). Functional tests will never be complete (you can't cover all game situation, but you can cover all methods), that does not mean we shouldn't write them as they are about as easy to write as unit one, and use the same framework. I even think we should start by writing a few functionnal unit tests based on current sourceforge bugtrack, while in parallel begin to write unit tests to cover each crossfire function. Regards. >-- > So many of our dreams at first seem impossible, > then they seem improbable, and then, when we > summon the will, they soon become inevitable. >-- >personal: http://www.laranja.org/ >technical: http://lalo.revisioncontrol.net/ >GNU: never give up freedom http://www.gnu.org/ > > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From alex_sch at telus.net Wed Mar 8 08:09:58 2006 From: alex_sch at telus.net (Alex Schultz) Date: Wed, 08 Mar 2006 07:09:58 -0700 Subject: [crossfire] Unit tests In-Reply-To: <440ED3C1.70004@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603061931.15784.tchize@myrealbox.com> <440CCB09.9080907@telus.net> <440D30F4.4030801@sonic.net> <440D40CF.7090409@myrealbox.com> <440E7B6E.3090409@sonic.net> <440ED3C1.70004@myrealbox.com> Message-ID: <440EE5B6.7030509@telus.net> Tchize wrote: >Functional tests will never be complete (you can't cover all game >situation, but you can cover all methods), that does not mean we >shouldn't write them as they are about as easy to write as unit one, and >use the same framework. I even think we should start by writing a few >functionnal unit tests based on current sourceforge bugtrack, while in >parallel begin to write unit tests to cover each crossfire function. > Yes, and also functional tests for some things that haven't caused bugs in the past, but are sorts of things that often do would also be good to make functional unit tests for (such as, spells and ranged weapons fired infront of map edges). Also, even for the non-functional unit tests, the functions will often need a set of data to operate within, and this would in many cases, mean a map. Alex Schultz From tchize at myrealbox.com Wed Mar 8 08:37:46 2006 From: tchize at myrealbox.com (Tchize) Date: Wed, 08 Mar 2006 15:37:46 +0100 Subject: [crossfire] Unit tests In-Reply-To: <440E1469.1070305@telus.net> References: <44021342.9050604@telus.net> <440D440A.204@myrealbox.com> <440D949C.3070207@telus.net> <200603071853.22891.tchize@myrealbox.com> <440E1469.1070305@telus.net> Message-ID: <440EEC3A.8090806@myrealbox.com> A unit test that core dumps is a unit test that need immediate fixing :) Alex Schultz a ?crit : >Hmm, I was thinking it could be nice though if it could automatically >generate core dumps for segfaulted unit tests, and continue to further >unit tests after. That would need both forks and integrated per fork >core dump capability, which that unit test framework doesn't appear to >allow. > >tchize wrote: > > > > > From antonoussik at gmail.com Wed Mar 8 19:10:56 2006 From: antonoussik at gmail.com (Anton Oussik) Date: Thu, 9 Mar 2006 01:10:56 +0000 Subject: [crossfire] Ideas needed to fix exploit In-Reply-To: <440E7F66.9070705@sonic.net> References: <440696F3.8050502@sonic.net> <20060307220434.GC7493@kirschbaum.myrealbox.com> <440E7F66.9070705@sonic.net> Message-ID: A special case also has to be made for suicide. training up an easy to train skill and then killing yourself with a hard skill should not make training a hard skill too easy... Perhaps not gain any experience for a suicide, since it is conceptually a stupid thing to do. From antonoussik at gmail.com Wed Mar 8 19:38:34 2006 From: antonoussik at gmail.com (Anton Oussik) Date: Thu, 9 Mar 2006 01:38:34 +0000 Subject: [crossfire] Crossfire 2.0+ features/priorities In-Reply-To: <440D2D82.2080601@sonic.net> References: <44026532.5080202@sonic.net> <440D2D82.2080601@sonic.net> Message-ID: In that case it would make sense to make a big noobie map, with buildings, each of which contains a course to do some thing. If each of these noobie maps was personal to the player, the players could learn about playing cf without anyone else spoiling their fun. This would also enable them to come back later to complete learning if they can not be bothered with advanced stuff just yet. I propose each building award the player some experience towards the skill at the end to make it worthwhile. These are the general buildings I can think of: - Basics 1: Moving, applying things, reading signs, notes, etc. - Basics 2: Wearing, equipping, making active, opening/closing, marking, 'body command - Basics 3: Changing/learning skills, commands like 'statistics, 'skills, experience system - Traps 1: Finding/disarming traps (on the floor, in doors, on chests) - Traps 2: Setting traps - Melee combat 1: Attack things with punching/karate/etc. - Melee combat 2: If you can hold a weapon, how to use it to do things in 1, run attack - Ranged combat 1: How to pick up and equip bow, arrows, and shoot - Ranged combat 2: bowmode and arrow quivers - Spell casting 1: How to see what spells you have, select a spell you have, and fire a spell. - Spell casting 2: Learning new spells, types of spells (schools), sp requirement, spell level. - Spell casting 3: Different kinds of spells (cone/bolt/etc) and casting them - Identifying: List different ways of identify items - Healing: List different ways of healing different things - Alchemy: How to use alchemy-like things - Stealing: How to steal ...and possibly a few more buildings for things like oratory, climbing, jumping, literacy (scroll making?). Then there could be specific houses for the races like dragons explaining the whole food/focus thing, a house for firebournes explaining the whole "you are a ball of fire, don't get put out" thing, and a house for wraith explaining "You are dead - you don't digest food or heal" (when I make the patch balanced enough to be applied to the source tree) thing. From tchize at myrealbox.com Thu Mar 9 14:06:38 2006 From: tchize at myrealbox.com (tchize) Date: Thu, 9 Mar 2006 21:06:38 +0100 Subject: [crossfire] Unit tests, request for comments In-Reply-To: <44039950.8080304@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> Message-ID: <200603092107.01798.tchize@myrealbox.com> Hello, I have wrote draft documentation on testing. This will serve as a guide line on implementing unit testing in crossfire. All comment from community welcomed. Note, as nobody did come with other suggestiong i went on the use of check Regards, Tchize Unit tests and functional tests documentation. Crossfire uses the 'check' C automated testing framework available at http://check.sourceforge.net The presence of this framework at compile time is not required but is STRONGLY recommanded for developpers. You should not commit changes to the CVS if they are not unit tested. In fact you should even write you new test before writing the change. Organization ============ All automated tests are in subfolders of the test directory. Directory structure is as follow: test +-rsc ** contains all runtime ressources unit tests might need (maps, etc) +-include ** include files specific to unit tests +-toolkit ** generic function and toolkit shared by several tests +-unit ** contains all unit tests separated with same structure as tested code | +-headers | +-common | +-socket | +-random_maps | +-server | +-crossedit +-bugs ** contains test of known bugs (fixed and opened) | +-bugtrack ** Each file has the number of associated sourceforge bug id | | +-bug_.c | +-unrelated ** Bugs that for a reason or another where not referenced on sf +-functional ** contains all functional tests with structure of tested code | +-common | +-socket | +-random_maps | +-server | +-crossedit | +-general ** put here func test not in previous func categories +-plugins //structure still tonow be defined All source file having tests in them should be named test_*.c Unit Test ========= Put in subfolders of test/unit, They test the various crossfire functions. You must write exactly one test_xxx.c for each xxx.c in crossfire sourcecode. You must test in this test_xxx each function available in xxx.c. If you add a function to xxx.c, write a testcase in test_xxx.c Do no put files other than the test_xyz.c where xyz.c is a crossfire source file. If you need to write test that does not conform to this, this mean they are not unit tests and should go to functional/* when test/unit is complete, each function of crossfire will be tested at least once. Note: because crossfire make heavy use of macros, macros must be considered as function and so must be unit tested too. Because macros are define in .h file, the unit test should have the form test_xxx for testing xxx.h. All unit tests for .h files goes to test/headers Functional Test =============== While unit tests are testing each function of the code, functionnal tests are testing behaviour of the whole. They can test behaviour of server after a specific series of actions and check the integration of various modules. So they are not tied to specific .c file or specific function. However, most testcases will be concerned by specific module, so try to put the in corresponding test/function/ folder. If that's not possible, put them in test/functional/general. Bugs ==== When a bug is discovered, here is the procedure to follow: 1) write a testcase reproducing it (either in test/bugtrack either in test/unrelated, depending upon the bug being reported on sf or not) 2) if the bug was not reported on sourceforge, provide enough information in testcase comments to describe the bug, preferrably at the top of test file, after the GPL licence header. 3) when you successfully wrote a failing testcase demonstrating the bug, start to fix it (by writting the test you probably got a good idea of what goes wrong and the automated test will test each fix attempt for you) 4) provide short information in test source code on what was wrong. If a later change in crossfire revive the bug, it will help fix it quickly. 5) Commit your fix along with test. 6) If bug was reported on sourceforge, mark it closed or ask an admin to close it. Mention you wrote a testcase for the bug. Test ressources =============== Some test requires maps, archetype or other kind of ressources to run. Those are all provided in rsc or a subdirectory of it. Try to name those files explicitly. Do not name it things like test-map or alike. Prefer forms like rsc/maps/walls_blocks_move or like rsc/arch/selection_of_magic_books each file in src/* should be documented in rsc/index.txt so other coders can reuse those resources. each subdirectory of rsc should have it's own index file. Toolkits ======== For some testcases (specially the functionnal one), you may need to have a specific crossfire configuration loaded, or to do specific map operation. It won't be surprising some of those operation are generic enough to be shared amongst all testcases. such support function (aka toolkits) will be made available in the toolkit directory. Includes ======== Testcases will share some include files not present in crossfire core. Those test specific headers will be put in test/includes -- -- Tchize (David Delbecq) tchize at myrealbox.com Public PGP KEY FINGERPRINT: ? ? F4BC EF69 54CC F2B5 4621 ?8DAF 1C71 8E6B 5436 C17C Public PGP KEY location: ? ? http://wwwkeys.pgp.net/pgpnet/wwwkeys.html -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 189 bytes Desc: not available Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060309/d4757237/attachment.pgp From alex_sch at telus.net Thu Mar 9 17:31:58 2006 From: alex_sch at telus.net (Alex Schultz) Date: Thu, 09 Mar 2006 16:31:58 -0700 Subject: [crossfire] Unit tests, request for comments In-Reply-To: <200603092107.01798.tchize@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603092107.01798.tchize@myrealbox.com> Message-ID: <4410BAEE.9020500@telus.net> This looks good to me, just a couple things. What is the logic behind naming the directory for the runtime resources 'rsc'? I think something clearer should be used for that. Also, I'm not sure we need to have unit or functional tests for crossedit, and there probably isn't much of it anyways that one could write unit tests for as most of it to my understanding is GUI code, and glue code to the common directory. Also in terms of step 2 for dealing with bugs, I believe that even if it is reported on sourceforge, it may be helpful to still include a comment at the top of what the bug is, possibly copied from the sourceforge tracker's summary. I'm also wondering what sort of unit tests one could have for 'headers', that doesn't seem very clear to me. Another point, is some functional tests, could very well combine multiple parts of the server code, such as 'server' and 'common', or 'socket' and 'server'. It is difficult to make a clear separation for most functional tests. Alex Schultz tchize wrote: >Hello, > >I have wrote draft documentation on testing. This will serve as a guide line on implementing unit testing in crossfire. >All comment from community welcomed. Note, as nobody did come with other suggestiong i went on the use of check > >Regards, >Tchize > > From tchize at myrealbox.com Fri Mar 10 02:07:50 2006 From: tchize at myrealbox.com (Tchize) Date: Fri, 10 Mar 2006 09:07:50 +0100 Subject: [crossfire] Unit tests, request for comments In-Reply-To: <4410BAEE.9020500@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603092107.01798.tchize@myrealbox.com> <4410BAEE.9020500@telus.net> Message-ID: <441133D6.1060903@myrealbox.com> Alex Schultz a ?crit : >This looks good to me, just a couple things. What is the logic behind >naming the directory for the runtime resources 'rsc'? I think something >clearer should be used for that. Also, I'm not sure we need to have unit > > A reflex from java world :) Indeed using someting 'resources' would be better >or functional tests for crossedit, and there probably isn't much of it >anyways that one could write unit tests for as most of it to my >understanding is GUI code, and glue code to the common directory. Also > If you do unit testing, you must test each method, this include the gui related ones. Of course you can't easily write test saying 'interface must look ok' but you can write tests that ensure gui objects are created, that the event queues are working, and so on. > >in terms of step 2 for dealing with bugs, I believe that even if it is >reported on sourceforge, it may be helpful to still include a comment at >the top of what the bug is, possibly copied from the sourceforge >tracker's summary. > > Agree. >I'm also wondering what sort of unit tests one could have for 'headers', >that doesn't seem very clear to me. > > They are there to store all testcases related to macros defined in headers. Crossfire has a few quite complicated macros, we need to unit test them as there are used a lot. >Another point, is some functional tests, could very well combine >multiple parts of the server code, such as 'server' and 'common', or >'socket' and 'server'. It is difficult to make a clear separation for >most functional tests. > > > For tests that involve several modules, the 'general' folder is there, as stated in document. Suppose you want to write a functionnal test for socket, it may be that you need functions defined in common/ but as it is the socket module which is under test, put it in socket/ folder. On the other side, if you want to write a functionnal test based on 'map loading code should interact gracefully with protocol' then you test 2 modules at same time and put them in general/. >Alex Schultz > > > >tchize wrote: > > > >>Hello, >> >>I have wrote draft documentation on testing. This will serve as a guide line on implementing unit testing in crossfire. >>All comment from community welcomed. Note, as nobody did come with other suggestiong i went on the use of check >> >>Regards, >>Tchize >> >> >> >> > > > > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From elmex at ta-sa.org Fri Mar 10 08:57:43 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 10 Mar 2006 15:57:43 +0100 Subject: [crossfire] Code cleanlieness and server stability In-Reply-To: <4403EDBA.8040606@sonic.net> References: <44021342.9050604@telus.net> <44027D44.1030904@sonic.net> <44028F79.5070405@telus.net> <4402A59C.1020100@sonic.net> <20060227092244.GA1814@elmex> <4403EDBA.8040606@sonic.net> Message-ID: <20060310145743.GA13808@elmex> On Mon, Feb 27, 2006 at 10:29:14PM -0800, Mark Wedel wrote: > Robin Redeker wrote: > > > (btw. it would be easier for us to submit those patches directly to the > > mailing list) > > > > I hope i can find the time to submit our bug fixes to the sourceforge > > tracker, it would be much easier to just drop a mail to a mailing list > > than logging in at sf.net, finding the correct tracker, filling in the > > forms, adding the file and submitting it. > > The problem with submitting to the mailing list is that it is too easy for > things to just get lost. > > Simplest example being that every thinks someone else will take and apply the > patch, and no one ever does, and thus the patch is no longer applied. > > While the tracker may be less convenient, at least there is a definite record > - it is open until someone takes some action on it. No way for it to really > fall through the cracks. > Yes, ok, i've submitted 2 other patches in the last 2 days. One question that arose on the last patch: We found following code in server/monster.c (around line 1252): else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) { ????if (monster_should_cast_spell(mon, item->inv)) And in apply.c at void apply_scroll (object *op, object *tmp, int dir): if (!tmp->inv || tmp->inv->type != SPELL) { new_draw_info (NDI_UNIQUE, 0, op, "The scroll just doesn't make sense!"); return; So we patched it like this: if (item->inv && monster_should_cast_spell(mon, item->inv)) But the question is: How is a scroll with an empty inventory created in the first place? We weren't able to find out what behavoir is correct and where and how scrolls are created. But IMHO things like this and other inconsistencies should be fixed before doing unit tests :) Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From mwedel at sonic.net Sat Mar 11 00:39:05 2006 From: mwedel at sonic.net (Mark Wedel) Date: Fri, 10 Mar 2006 22:39:05 -0800 Subject: [crossfire] Code cleanlieness and server stability In-Reply-To: <20060310145743.GA13808@elmex> References: <44021342.9050604@telus.net> <44027D44.1030904@sonic.net> <44028F79.5070405@telus.net> <4402A59C.1020100@sonic.net> <20060227092244.GA1814@elmex> <4403EDBA.8040606@sonic.net> <20060310145743.GA13808@elmex> Message-ID: <44127089.5030704@sonic.net> Robin Redeker wrote: > > Yes, ok, i've submitted 2 other patches in the last 2 days. > > One question that arose on the last patch: > > We found following code in server/monster.c (around line 1252): > > else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) { > if (monster_should_cast_spell(mon, item->inv)) > > And in apply.c at void apply_scroll (object *op, object *tmp, int dir): > > if (!tmp->inv || tmp->inv->type != SPELL) { > new_draw_info (NDI_UNIQUE, 0, op, > "The scroll just doesn't make sense!"); > return; > > So we patched it like this: > > if (item->inv && monster_should_cast_spell(mon, item->inv)) I think you still need the item->type == SCROLL check in there - otherwise, the monster will try to use spellbooks, wands, rods, containers - anything with an inventory, as a spell. For wands, rods, etc, not an issue, since they do contain spells. But if the monster picks up a chest, item->inv is true, but not a spell object. > > But the question is: How is a scroll with an empty inventory created > in the first place? We weren't able to find out what behavoir is correct > and where and how scrolls are created. That is one of those mysteries - I've seen it, but can't figure out how it happens. The problem here is that we know there is an error, but don't know how we got into that state. One thought I've had, which would use more memory, is to use the glibc backtrace() functionality and add code to get_object() that stores away the backtrace. Thus, when we get an object in a funky state, we can hopefully see how the object was created (calling structure). However, this still doesn't catch the cases where the object is modified after creation, etc. From alex_sch at telus.net Sat Mar 11 11:35:44 2006 From: alex_sch at telus.net (Alex Schultz) Date: Sat, 11 Mar 2006 10:35:44 -0700 Subject: [crossfire] Code cleanlieness and server stability In-Reply-To: <44127089.5030704@sonic.net> References: <44021342.9050604@telus.net> <44027D44.1030904@sonic.net> <44028F79.5070405@telus.net> <4402A59C.1020100@sonic.net> <20060227092244.GA1814@elmex> <4403EDBA.8040606@sonic.net> <20060310145743.GA13808@elmex> <44127089.5030704@sonic.net> Message-ID: <44130A70.6000003@telus.net> I have a hunch this is one of those cases where the object is modified after creation. I'm not really sure, but perhaps it's something similar to the old bug with spellbooks losing their spell when thrown (which is a bug that I think has been fixed). Mark Wedel wrote: > One thought I've had, which would use more memory, is to use the glibc >backtrace() functionality and add code to get_object() that stores away the >backtrace. Thus, when we get an object in a funky state, we can hopefully see >how the object was created (calling structure). However, this still doesn't >catch the cases where the object is modified after creation, etc. > From alex_sch at telus.net Sat Mar 11 18:21:31 2006 From: alex_sch at telus.net (Alex Schultz) Date: Sat, 11 Mar 2006 17:21:31 -0700 Subject: [crossfire] Unit tests, request for comments In-Reply-To: <200603092107.01798.tchize@myrealbox.com> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603092107.01798.tchize@myrealbox.com> Message-ID: <4413698B.3020100@telus.net> Another thing, I'm thinking that in order to make such tests very easy to make, a variety of convenience macros would be good to put here. Such as perhaps one to run the main server cycle for x ticks, and perhaps one to run the main server cycle until another specified macro or function returns non-zero. It might also be good to make some little macros such as one for map loading, that has a slightly simpler interface than the normal one (don't need that last parameter for most functional tests). Having a good variety of such convenience functions and macros would make building functional tests easy to learn by example even for someone who does not know much C at all, and would make it faster for those who do. tchize wrote: >Includes >======== >Testcases will share some include files not present in crossfire core. Those >test specific headers will be put in test/includes > From mwedel at sonic.net Sat Mar 11 22:50:30 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sat, 11 Mar 2006 20:50:30 -0800 Subject: [crossfire] Code cleanlieness and server stability In-Reply-To: <44130A70.6000003@telus.net> References: <44021342.9050604@telus.net> <44027D44.1030904@sonic.net> <44028F79.5070405@telus.net> <4402A59C.1020100@sonic.net> <20060227092244.GA1814@elmex> <4403EDBA.8040606@sonic.net> <20060310145743.GA13808@elmex> <44127089.5030704@sonic.net> <44130A70.6000003@telus.net> Message-ID: <4413A896.9040208@sonic.net> Alex Schultz wrote: > I have a hunch this is one of those cases where the object is modified > after creation. I'm not really sure, but perhaps it's something similar > to the old bug with spellbooks losing their spell when thrown (which is > a bug that I think has been fixed). Perhaps. But if one was going to use this backtrace() functionality, could also put hooks in for insert_ob_in_{ob/map} calls as well as remove_ob calls, so one could perhaps get some clearer idea on the history of the object From tchize at myrealbox.com Sun Mar 12 04:07:22 2006 From: tchize at myrealbox.com (tchize) Date: Sun, 12 Mar 2006 11:07:22 +0100 Subject: [crossfire] Unit tests, request for comments In-Reply-To: <4413698B.3020100@telus.net> References: <44021342.9050604@telus.net> <44039950.8080304@telus.net> <200603092107.01798.tchize@myrealbox.com> <4413698B.3020100@telus.net> Message-ID: <4413F2DA.403@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Those won't be macros but function, they do too complicated stuff to be macros. Those will be part of the unit test toolkit (directory crossfire/test/toolkit), which will made available to each test_xxx. Various helpers will be developped and made available to users as unit test development advance. Alex Schultz a ?crit : > Another thing, I'm thinking that in order to make such tests very > easy to make, a variety of convenience macros would be good to put > here. Such as perhaps one to run the main server cycle for x ticks, > and perhaps one to run the main server cycle until another > specified macro or function returns non-zero. It might also be good > to make some little macros such as one for map loading, that has a > slightly simpler interface than the normal one (don't need that > last parameter for most functional tests). Having a good variety of > such convenience functions and macros would make building > functional tests easy to learn by example even for someone who does > not know much C at all, and would make it faster for those who do. > > > tchize wrote: > >> Includes ======== Testcases will share some include files not >> present in crossfire core. Those test specific headers will be >> put in test/includes >> > > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > > -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEE/LaHHGOa1Q2wXwRAkrxAJ0fJOLQZzftcr3z4/hiV5x8uSWGvACgxOas uuajkXK4Kt5rZzJptC5wxQc= =gRkG -----END PGP SIGNATURE----- From elmex at ta-sa.org Sun Mar 12 05:30:45 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Sun, 12 Mar 2006 12:30:45 +0100 Subject: [crossfire] Code cleanlieness and server stability In-Reply-To: <44127089.5030704@sonic.net> References: <44021342.9050604@telus.net> <44027D44.1030904@sonic.net> <44028F79.5070405@telus.net> <4402A59C.1020100@sonic.net> <20060227092244.GA1814@elmex> <4403EDBA.8040606@sonic.net> <20060310145743.GA13808@elmex> <44127089.5030704@sonic.net> Message-ID: <20060312113045.GA3641@elmex> On Fri, Mar 10, 2006 at 10:39:05PM -0800, Mark Wedel wrote: > Robin Redeker wrote: > > > [...] > > else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) { > > if (monster_should_cast_spell(mon, item->inv)) > > [...] > > So we patched it like this: > > > > if (item->inv && monster_should_cast_spell(mon, item->inv)) > > I think you still need the item->type == SCROLL check in there - otherwise, > the monster will try to use spellbooks, wands, rods, containers - anything with > an inventory, as a spell. Of course we did not remove the line with the else if :) Sorry if it was misleading. I only meant that we changed the line: if (monster_should_cast_spell(mon, item->inv)) to: if (item->inv && monster_should_cast_spell(mon, item->inv)) Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From tchize at myrealbox.com Sun Mar 12 11:17:56 2006 From: tchize at myrealbox.com (tchize) Date: Sun, 12 Mar 2006 18:17:56 +0100 Subject: [crossfire] first bug discovered by unit test Message-ID: <441457C4.9090701@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 While am still preparing check framework for crossfire, i found a bug in common/shstr.c where query_refcount was returning wrong value. Fixed and commited. I hope unit testing will discover more of those still undetected bugs :) Tchize -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEFFfEHHGOa1Q2wXwRAh24AKCAnbCQIhV7s8lHc/rWQWsiQ05DpwCg8a+l j9lkYAgdM+qrmtGnFsNUsVM= =/d7V -----END PGP SIGNATURE----- From froese at gmx.de Sun Mar 12 12:21:42 2006 From: froese at gmx.de (Edgar Toernig) Date: Sun, 12 Mar 2006 19:21:42 +0100 Subject: [crossfire] [PATCH (big)] Basic X11 client overhaul Message-ID: <20060312192142.12e0e65b.froese@gmx.de> Hi all! The standard font in the basic X11 client (8x13) was too small for my taste and when trying to use a bigger one I noticed, that this is not really supported. I decided to fix that. What started as a simple patch to support arbitrary font sizes became a major overhaul of the drawing routines of clclient. The resulting features: arbitrary font sizes, proper window resizing, dedicated input box with history, non-square map sizes, sorted resistancies/skills, X11 window classes, and a couple of minor tweaks. On the way I cleaned up the code a little bit. As far as I can tell, the only lost feature is the non-scrolling info window. The patch shouldn't break anything - if it does, holler. Sorry that the patch got that big. Ciao, ET. PS: At the moment I'm reading the ml via gmane. mailman.metalforge.org seems to be down. common/client.c | 10 common/commands.c | 20 common/external.h | 1 common/p_cmd.c | 2 x11/xutil.c | 8 x11/x11.h | 2 x11/x11proto.h | 3 x11/x11.c | 2289 +++++++++++++++++++------------------------- 8 files changed, 1051 insertions(+), 1284 deletions(-) diff -rup crossfire-client-1.9.0-orig/common/client.c crossfire-client-1.9.0/common/client.c --- crossfire-client-1.9.0-orig/common/client.c 2006-02-26 08:45:46 +0100 +++ crossfire-client-1.9.0/common/client.c 2006-03-02 02:01:01 +0100 @@ -61,11 +61,11 @@ Client_Player cpl; ClientSocket csocket; const char *const resists_name[NUM_RESISTS] = { -"armor", "magic", "fire", "elec", -"cold", "conf", "acid", "drain", -"ghit", "pois", "slow", "para", -"t undead", "fear", "depl","death", -"hword", "blind"}; +"Armor", "Magic", "Fire", "Elec", +"Cold", "Conf", "Acid", "Drain", +"GhHit", "Pois", "Slow", "Para", +"TUnd", "Fear", "Depl","Death", +"HWord", "Blind"}; typedef void (*CmdProc)(unsigned char *, int len); diff -rup crossfire-client-1.9.0-orig/common/commands.c crossfire-client-1.9.0/common/commands.c --- crossfire-client-1.9.0-orig/common/commands.c 2006-02-26 08:45:46 +0100 +++ crossfire-client-1.9.0/common/commands.c 2006-03-09 20:06:18 +0100 @@ -442,13 +442,11 @@ void DrawInfoCmd(char *data, int len) LOG(LOG_WARNING,"common::DrawInfoCmd","got no data"); buf=""; } - else buf++; - if (color!=NDI_BLACK) - draw_color_info(color, buf); else - draw_info(buf,NDI_BLACK); - + buf++; + draw_info(buf, color); } + TextManager* firstTextManager = NULL; void setTextManager(int type, ExtTextManager callback){ @@ -634,7 +632,7 @@ void StatsCmd(unsigned char *data, int l void handle_query (char *data, int len) { - char *buf,*cp; + char *buf,*cp=0; uint8 flags = atoi(data); (void)len; /* __UNUSED__ */ @@ -649,16 +647,16 @@ void handle_query (char *data, int len) /* The actual text is optional */ buf = strchr(data,' '); - if (buf) buf++; /* If we just get passed an empty string, why draw this? */ if (buf) { - cp = buf; + cp = ++buf; while ((buf=strchr(buf,'\n'))!=NULL) { *buf++='\0'; draw_info(cp, NDI_BLACK); cp = buf; } + } /* Yes/no - don't do anything with it now */ if (flags & CS_QUERY_YESNO) {} @@ -668,10 +666,10 @@ void handle_query (char *data, int len) else cpl.input_state = Reply_Many; - if (cp) draw_prompt(cp); - } + cpl.input_text[0] = 0; + draw_prompt(cp ? cp : ""); - LOG(0,"commands.c","Received query. Input state now %d\n", cpl.input_state); + LOG(0,"commands.c","Received query. Input state now %d\n", cpl.input_state); } /* Sends a reply to the server. text contains the null terminated diff -rup crossfire-client-1.9.0-orig/common/external.h crossfire-client-1.9.0/common/external.h --- crossfire-client-1.9.0-orig/common/external.h 2006-02-19 04:26:53 +0100 +++ crossfire-client-1.9.0/common/external.h 2006-03-09 20:07:33 +0100 @@ -46,7 +46,6 @@ extern void draw_magic_map(void); /* Info related functions */ extern void draw_info(const char *str, int color); -extern void draw_color_info(int colr, const char *buf); extern void draw_prompt(const char *str); extern void x_set_echo(void); extern void set_scroll(const char *s); diff -rup crossfire-client-1.9.0-orig/common/p_cmd.c crossfire-client-1.9.0/common/p_cmd.c --- crossfire-client-1.9.0-orig/common/p_cmd.c 2006-02-19 04:26:53 +0100 +++ crossfire-client-1.9.0/common/p_cmd.c 2006-03-02 02:01:15 +0100 @@ -405,7 +405,7 @@ static void do_resist(const char * ignor int i; char buf[256]; for (i=0; i"); cpl.input_state = Command_Mode; + cpl.input_text[0] = 0; cpl.no_echo=FALSE; + draw_prompt(">"); return; } if (keycode == firekey[0] || keysym==firekeysym[0] || @@ -640,8 +641,7 @@ void parse_key(char key, KeyCode keycode gtk_entry_set_text(GTK_ENTRY(entrytext),buf); gtk_widget_grab_focus (GTK_WIDGET(entrytext)); #else - sprintf(buf,">%s", cpl.input_text); - draw_prompt(buf); + draw_prompt(">"); #endif return; } diff -rup crossfire-client-1.9.0-orig/x11/x11.h crossfire-client-1.9.0/x11/x11.h --- crossfire-client-1.9.0-orig/x11/x11.h 2005-09-06 08:39:17 +0200 +++ crossfire-client-1.9.0/x11/x11.h 2006-03-07 19:53:13 +0100 @@ -40,7 +40,7 @@ struct PixmapInfo { extern struct PixmapInfo *pixmaps[MAXPIXMAPNUM]; extern Display *display; -extern uint8 image_size; +extern int image_size; extern Window win_root,win_game; extern GC gc_game; extern Colormap colormap; diff -rup crossfire-client-1.9.0-orig/x11/x11proto.h crossfire-client-1.9.0/x11/x11proto.h --- crossfire-client-1.9.0-orig/x11/x11proto.h 2006-02-15 09:03:14 +0100 +++ crossfire-client-1.9.0/x11/x11proto.h 2006-03-09 20:07:11 +0100 @@ -15,10 +15,8 @@ extern void SoundCmd(unsigned char *data extern int error_handler(Display *dp, XErrorEvent *xe); extern void event_loop(void); extern void end_windows(void); -extern void write_ch(char key); extern void draw_prompt(const char *str); extern void draw_info(const char *str, int color); -extern void draw_color_info(int colr, const char *buf); extern void draw_stats(int redraw); extern void draw_message_window(int redraw); extern void open_container(item *op); @@ -40,7 +38,6 @@ extern void x_set_echo(void); extern void display_map_doneupdate(int redraw, int notice); extern int display_mapscroll(int dx, int dy); extern int associate_cache_entry(Cache_Entry *ce, int pixnum); -extern void redisplay_stats(void); extern void display_map_startupdate(void); extern void draw_magic_map(void); extern void magic_map_flash_pos(void); diff -rup crossfire-client-1.9.0-orig/x11/x11.c crossfire-client-1.9.0/x11/x11.c --- crossfire-client-1.9.0-orig/x11/x11.c 2006-02-26 08:45:47 +0100 +++ crossfire-client-1.9.0/x11/x11.c 2006-03-12 17:57:57 +0100 @@ -37,6 +37,7 @@ const char *rcsid_x11_x11_c = */ #define X_PROG_NAME "cfclient" +#define X_CLASS "CFClient" /* Most functions in this file are private. Here is a list of * the global functions: @@ -83,6 +84,7 @@ const char *rcsid_x11_x11_c = #include #include +#include #include "mapdata.h" #include "x11proto.h" @@ -120,126 +122,137 @@ typedef struct { GC gc_icon; GC gc_status; - uint8 show_icon:1; /* show status icons */ - uint8 show_weight:1; /* show item's weight */ + int show_icon:1; /* show status icons */ + int show_weight:1; /* show item's weight */ char format_nw[20]; /* sprintf-format for text (name and weight) */ char format_nwl[20]; /* sprintf-format for text (name, weight, limit) */ char format_n[20]; /* sprintf-format for text (only name) */ - sint16 text_len; /* How wide the text-field is */ - sint16 width; /* How wide the window is in pixels */ - sint16 height; /* How height the window is in pixels */ + int width; /* How wide the window is in pixels */ + int height; /* How height the window is in pixels */ - sint16 item_pos; /* The sequence number of the first drawn item */ - sint16 item_used; /* How many items actually drawn. (0 - size) */ + int item_pos; /* The sequence number of the first drawn item */ + int item_used; /* How many items actually drawn. (0 - size) */ - sint16 size; /* How many items there is room to display */ - sint16 *faces; /* [size] */ - sint8 *icon1; /* status icon : locked */ - sint8 *icon2; /* status icon : applied / unpaid */ - sint8 *icon3; /* status icon : magic */ - sint8 *icon4; /* status icon : damned / cursed */ + int size; /* How many items there is room to display */ + int *faces; /* [size] */ + char *icon1; /* status icon : locked */ + char *icon2; /* status icon : applied / unpaid */ + char *icon3; /* status icon : magic */ + char *icon4; /* status icon : damned / cursed */ char **names; /* [size][NAME_LEN] */ /* The scrollbar */ - sint16 bar_length; /* the length of scrollbar in pixels */ - sint16 bar_size; /* the current size of scrollbar in pixels */ - sint16 bar_pos; /* the starting position of scrollbar in pixels */ + int bar_length; /* the length of scrollbar in pixels */ + int bar_size; /* the current size of scrollbar in pixels */ + int bar_y; /* the starting position of scrollbar in pixels */ + inventory_show show_what; /* What to show in inventory */ - uint32 weight_limit; /* Weight limit for this list - used for title */ + int weight_limit; /* Weight limit for this list - used for title */ } itemlist; -int noautorepeat = FALSE; /* turn off autorepeat detection */ - -static char *font_name="8x13", **gargv; - -#define SCROLLBAR_WIDTH 16 /* +2+2 for border on each side */ -#define INFOCHARS 50 -#define INFOLINES 36 -/* Perhaps decent defaults, but not quite right */ -static int FONTWIDTH= 8; -static int FONTHEIGHT= 13; -#define MAX_INFO_WIDTH 80 -#define MAXNAMELENGTH 50 - /* What follows is various constants (or calculations) for various * window sizes. */ -/* Width (and height) of the game window */ -#define GAME_WIDTH (image_size * use_config[CONFIG_MAPWIDTH] + 5) +#define GAP 3 /* spacing between windows */ +#define BW 3 /* internal border width */ + +#define SCROLLBAR_WIDTH 14 /* total width including border */ + +/* status bars (+2 for each border) */ +#define BAR_WIDTH 10 +#define BAR_HEIGHT (MSG_HEIGHT - BW - BW - 4) +#define BAR_TOTAL_WIDTH (FONT_WIDTH + 2 + BAR_WIDTH+4 + FONT_WIDTH) + +static int FONT_WIDTH = 8; +static int FONT_HEIGHT = 13; +static int FONT_BASE = 13; /* offset from top to baseline - aka ascent */ + +#define GAME_WIDTH (image_size * use_config[CONFIG_MAPWIDTH]) +#define GAME_HEIGHT (image_size * use_config[CONFIG_MAPHEIGHT]) + +#define STAT_HEIGHT (BW + 10 * FONT_HEIGHT + BW) +#define STAT_WIDTH (BW + 29 * FONT_WIDTH + BW) + +#define MSG_HEIGHT (BW + 5*FONT_HEIGHT + BW) +#define MSG_WIDTH (BW + 4*BAR_TOTAL_WIDTH + 16*FONT_WIDTH + BW) + +#define INPUT_HEIGHT (1 + BW + FONT_HEIGHT + BW) + +#define INFO_WIDTH (BW + 50*FONT_WIDTH + BW) +#define INFO_HEIGHT (STAT_HEIGHT + GAP + GAME_HEIGHT + GAP + MSG_HEIGHT) +#define INFO_CHARS 80 /* max chars per line */ -#define STAT_HEIGHT 140 /* Width of the inventory and look window */ -#define INV_WIDTH 300 -/* spacing between windows */ -#define WINDOW_SPACING 3 -/* Height of the master (root) window */ -#define ROOT_HEIGHT 522 +#define INV_WIDTH (BW + image_size + 24 + 21*FONT_WIDTH + BW+SCROLLBAR_WIDTH+BW) -static int gargc, old_mapx=11, old_mapy=11; +static int gargc; +static char **gargv; + +static int noautorepeat = FALSE; /* turn off autorepeat detection */ + +static char *font_name="8x13"; + +static int old_mapx=11, old_mapy=11; Display *display; static Window def_root; /* default root window */ static long def_screen; /* default screen number */ static unsigned long foreground,background; -Window win_stats,win_message; -Window win_root,win_game; +static Window win_stats, win_message; +Window win_root, win_game; Colormap colormap; static XColor discolor[16]; static XFontStruct *font; /* Font loaded to display in the windows */ static XEvent event; -static XSizeHints messagehint, roothint; +static XSizeHints roothint; static Atom wm_delete_window; /* This struct contains the information to draw 1 line of data. */ typedef struct { - char *info; /* Actual character data for a line */ - uint8 color; /* Color to draw that line */ + char text[INFO_CHARS+1]; /* Actual character data for a line */ + uint8 color; /* Color to draw that line */ } InfoLine; /* This contains all other information for the info window */ typedef struct { - uint16 info_chars; /* width in chars of info window */ - uint16 max_info_chars; /* Max value of info_chars */ - uint16 infopos; /* Where in the info arry to put new data */ - uint16 infoline; /* Where on the window to draw the line */ - uint16 scroll_info_window:1; /* True if we should scroll the window */ - uint16 numlines; /* How many have been stored the array */ - uint16 maxlines; /* Maxlines (how large the array below is) */ - uint16 maxdisp; /* How many lines can be displayed at once */ - uint8 lastcolor; /* Last color text was drawn in */ - InfoLine *data; /* An array of lines */ - Window win_info; /* Actual info window */ - GC gc_info; /* GC for this window */ + int width,height; /* width and height of window (pixels) */ + int cwidth, cheight;/* width and height in characters */ + int lines; /* number of lines in line[] */ + int pos; /* 'current' line in line[], always at bottom of win */ + InfoLine *line; /* An array of lines */ + + Window win; /* Actual info window */ + GC gc; /* GC for this window */ + /* The scrollbar */ - sint16 bar_length; /* the max length of scrollbar in pixels */ - sint16 bar_size; /* the current size (length) of scrollbar in pixels */ - sint16 bar_pos; /* the starting position of scrollbar. This is - * an offset, which is the number of lines from - * 0 for the text to end out.*/ - sint16 bar_y; /* X starting position of scrollbar */ - uint16 has_scrollbar:1;/* True if there is a scrollbar in the window */ - sint16 width,height; /* Width and height of window */ + int bar_length; /* the max length of scrollbar in pixels */ + int bar_pos; /* when bar_pos==pos bar is at the bottom */ + + char prompt[INFO_CHARS+1]; /* the current prompt */ } InfoData; -InfoData infodata = {0, 0, 0, 0, 0, 0, INFOLINES, INFOLINES, NDI_BLACK, - NULL, 0, 0,0,0,0,0,0,0,0}; +static InfoData info; -uint8 image_size=24; +#define HISTORY_SIZE 100 /* number of history lines */ +static struct { + int pos; + char *line[HISTORY_SIZE]; +} history; +int image_size=24; -static char stats_buff[7][600]; struct PixmapInfo *pixmaps[MAXPIXMAPNUM]; + /* Off the 'free' space in the window, this floating number is the * portion that the info takes up. */ static float info_ratio=0; -#define INFOLINELEN 500 #define XPMGCS 100 enum { @@ -262,11 +275,31 @@ static GC gc_copy; /* used for copying static itemlist look_list, inv_list; /* Used to know what stats has changed */ -static Stats last_stats = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static Stats last_stats; + +/*********************************************************************/ -/* info win */ -#define INFOCHARS 50 +static void * +xmalloc(size_t size) +{ + void *x; + x = malloc(size ? size : 1); + if (x) + return x; + fprintf(stderr, "Not enough memory to allocate %ud bytes\n", size); + exit(1); +} + +/* XDrawRectangle draws to x+w/y+h inclusive - not what one expects. */ +#define DrawRectangle(dpy, d, gc, x, y, w, h) \ + XDrawRectangle((dpy), (d), (gc), (x), (y), (w)-1, (h)-1) + +static void +DrawText(Drawable d, GC gc, int x, int y, const char *str) +{ + XDrawImageString(display, d, gc, x, y + FONT_BASE, str, strlen(str)); +} /* This is the loop that the client goes through once all the * initialization is done. Basically, it checks for input and @@ -278,8 +311,6 @@ static Stats last_stats = {0,0,0,0,0,0,0 * check_x_events takes all the events that are waiting. */ -extern int maxfd; - /* Handle errors. I really needed this when debugging * the crashes with the big image stuff - I need to know * what function is causing the crash. @@ -301,6 +332,7 @@ int error_handler(Display *dp, XErrorEve void event_loop() { fd_set tmp_read; + int maxfd; int pollret; struct timeval timeout; @@ -311,7 +343,8 @@ void event_loop() } maxfd = csocket.fd + 1; while (1) { - if (csocket.fd==-1) return; + if (csocket.fd==-1) + return; /* Do a quick check here for better performance */ check_x_events(); @@ -368,7 +401,7 @@ static void gen_draw_face(Drawable where total++; mask = pixmaps[face]->mask; /* Lets see if we can find a stored mask with matching gc */ - for(gcnum=0;gcnum=0;i--) { + for (i=gcnum-1;i>=0;i--) { xpm_masks[i+1] = xpm_masks[i]; gc_xpm[i+1] = gc_xpm[i]; } @@ -406,7 +439,7 @@ void end_windows() XFreeGC(display, gc_game); XFreeGC(display, gc_copy); XFreeGC(display, gc_stats); - XFreeGC(display, infodata.gc_info); + XFreeGC(display, info.gc); XFreeGC(display, inv_list.gc_text); XFreeGC(display, inv_list.gc_icon); XFreeGC(display, inv_list.gc_status); @@ -431,20 +464,18 @@ void end_windows() static int get_game_display(void) { XSizeHints gamehint; + XClassHint classhint; int i; - gamehint.x=INV_WIDTH + WINDOW_SPACING; - gamehint.y=STAT_HEIGHT + WINDOW_SPACING; - - gamehint.width=GAME_WIDTH; - gamehint.height=gamehint.width; - - gamehint.max_width=gamehint.min_width=gamehint.width; - gamehint.max_height=gamehint.min_height=gamehint.height; + gamehint.x = INV_WIDTH + GAP; + gamehint.y = STAT_HEIGHT + GAP; + gamehint.width = GAME_WIDTH; + gamehint.height = GAME_HEIGHT; gamehint.flags=PPosition | PSize; + win_game=XCreateSimpleWindow(display,win_root, - gamehint.x,gamehint.y,gamehint.width,gamehint.height,2, - background,foreground); + gamehint.x,gamehint.y,gamehint.width,gamehint.height,0, + foreground,foreground); icon=XCreateBitmapFromData(display,win_game, (_Xconst char *) crossfire_bits, (unsigned int) crossfire_width, (unsigned int)crossfire_height); @@ -456,8 +487,11 @@ static int get_game_display(void) { } else XSetWindowColormap(display, win_game, colormap); - XSetStandardProperties(display,win_game,X_PROG_NAME, X_PROG_NAME, - icon,gargv,gargc, &(gamehint)); + XSetStandardProperties(display,win_game,"Crossfire - map", "crossmap", + icon,gargv,gargc, &gamehint); + classhint.res_name = "map"; + classhint.res_class = X_CLASS; + XSetClassHint(display, win_game, &classhint); gc_game=XCreateGC(display,win_game,0,0); XSetForeground(display,gc_game,discolor[0].pixel); @@ -465,7 +499,7 @@ static int get_game_display(void) { XSetGraphicsExposures(display, gc_game, False); gc_copy=XCreateGC(display,win_game,0,0); - XSetGraphicsExposures(display, gc_game, True); + XSetGraphicsExposures(display, gc_copy, True); gc_floor = XCreateGC(display,win_game,0,0); XSetGraphicsExposures(display, gc_floor, False); gc_blank = XCreateGC(display,win_game,0,0); @@ -502,599 +536,300 @@ static int get_game_display(void) { static int get_info_display(void) { XSizeHints infohint; + XClassHint classhint; int i; - /* The following could happen if bad values are given. */ - if (infodata.maxlinesfid); + info.gc=XCreateGC(display,info.win,0,0); + XSetForeground(display,info.gc,foreground); + XSetBackground(display,info.gc,background); - XSelectInput(display,infodata.win_info, + XSetFont(display,info.gc,font->fid); + + XSelectInput(display,info.win, ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask| StructureNotifyMask); - XSetWMProtocols(display, infodata.win_info, &wm_delete_window, 1); - XMapRaised(display,infodata.win_info); - if (infodata.maxlines>infodata.maxdisp) infodata.has_scrollbar=1; - infodata.info_chars = (infohint.width/FONTWIDTH)-1; - if (infodata.has_scrollbar) infodata.info_chars -=3; - infodata.max_info_chars=infodata.info_chars; - infodata.data=(InfoLine *) malloc(sizeof(InfoLine) * infodata.maxlines); - infodata.bar_length=infodata.height - 8; - for (i=0; i INFO_CHARS) + info.cwidth = INFO_CHARS; + + if (info.lines < 4*info.cheight) + info.lines = 4*info.cheight; + info.line = xmalloc(sizeof(InfoLine) * info.lines); + for (i=0; i3) && - strlen(infodata.data[infodata.infopos].info)<3) { - int line=infodata.infopos-1; - if (line<0) line=infodata.numlines; - strcpy(infodata.data[infodata.infopos].info, - infodata.data[line].info); - infodata.data[infodata.infopos].info[ - strlen(infodata.data[infodata.infopos].info)-1]=0; - XDrawImageString(display,infodata.win_info,infodata.gc_info, - FONTWIDTH, (infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); - } else { - infodata.data[infodata.infopos].info[ - strlen(infodata.data[infodata.infopos].info)-1]=0; - XDrawImageString(display,infodata.win_info,infodata.gc_info, - (strlen(infodata.data[infodata.infopos].info)+1)*FONTWIDTH, - (infodata.infoline+1)*FONTHEIGHT," ",1); - } + if (l > info.cwidth) /* clip to avoid overwriting scroll bar */ + l = info.cwidth; + XDrawImageString(display, info.win, info.gc, + BW, BW + FONT_BASE + y*FONT_HEIGHT, str, l); + return l * FONT_WIDTH; } -/* Writes one character to the screen. Used when player is typing - * stuff we that we want to appear, or used to give prompts. - */ - -void write_ch(char key) +static void +DrawInput(void) { - char c2[2]; + int x = BW; + int y = info.height - BW - FONT_HEIGHT; + int width = (info.width - BW - BW) / FONT_WIDTH; + const char *str = cpl.input_text; + int l1 = strlen(info.prompt); + int l2 = strlen(str); + int o; - /* Sort of a gross hack, but this gets it so that we actually put - * the command into the buffer. - */ - if (key==13) { - /* We turn off command mode for the draw_info call, because - * it has special handling for normal output during command - * mode; but we do this manually now. - */ - Input_State old_state = cpl.input_state; - cpl.input_state = Playing; - draw_info(infodata.data[infodata.infopos].info,NDI_BLACK); - cpl.input_state = old_state; - return; - } - - if (infodata.lastcolor!=NDI_BLACK) { - XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel); - infodata.lastcolor=NDI_BLACK; - } - - if (key == 9) { /* Tab */ - const char *str = complete_command(infodata.data[infodata.infopos].info); - - /* +1 so that we keep our > at start of line. Don't - * recopy the data on top of ourself. - */ - if (str != (infodata.data[infodata.infopos].info+1)) { - strcpy(infodata.data[infodata.infopos].info+1, str); - strcpy(cpl.input_text,str); - } - } else { - - if ((key < 32 || (unsigned char) key > 127) && key != 8) - return; - c2[0] = key; - c2[1] ='\0'; + XSetForeground(display,info.gc,discolor[NDI_BLACK].pixel); + XDrawLine(display, info.win, info.gc, + x, y-BW-1, info.width-BW-1, y-BW-1); + if (cpl.input_state != Metaserver_Select && + cpl.input_state != Reply_One && + cpl.input_state != Reply_Many && + cpl.input_state != Command_Mode) + goto clear; - if(key==8||key==127) { - /* By backspacking enough, let them get out of command mode */ - if (cpl.input_text[0]=='\0' && cpl.input_state==Command_Mode) { - cpl.input_state=Playing; - /* Erase the prompt */ - XDrawImageString(display,infodata.win_info,infodata.gc_info, - FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT," ",1); - } - delete_ch(); - return; - } - /* Give some leeway here */ - if(strlen(cpl.input_text)>=(MAX_BUF-15)) - return; - - strcat(cpl.input_text,c2); + if (cpl.no_echo) { + static const char noecho[] = "????????????????????????????????????????" + "????????????????????????????????????????"; + if (l2 > sizeof(noecho)-1) + l2 = sizeof(noecho)-1; + str = noecho + sizeof(noecho)-1 - l2; } - - if(strlen(infodata.data[infodata.infopos].info)>=(infodata.info_chars-2)) { - /* Draw the currently line and scroll down one */ - /* We turn off command mode for the draw_info call, because - * it has special handling for normal output during command - * mode; but we do this manually now. - */ - cpl.input_state = Playing; - draw_info(infodata.data[infodata.infopos].info,NDI_BLACK); - cpl.input_state = Command_Mode; - infodata.data[infodata.infopos].info[0]=(((strlen(cpl.input_text)/ - infodata.info_chars))%10)+49; - infodata.data[infodata.infopos].info[1]='>'; - infodata.data[infodata.infopos].info[2]=0; - XDrawImageString(display,infodata.win_info,infodata.gc_info, - FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); + o = l1 + l2 + 1 - width; + if (o < 0) + o = 0; + if (o < l1) { + XSetForeground(display, info.gc, discolor[NDI_NAVY].pixel); + DrawText(info.win, info.gc, x, y, info.prompt + o); + x += (l1 - o) * FONT_WIDTH; + o = l1; } + o -= l1; + if (o < l2) { + XSetForeground(display, info.gc, discolor[NDI_BLACK].pixel); + DrawText(info.win, info.gc, x, y, str + o); + x += (l2 - o) * FONT_WIDTH; + } + /*cursor*/ + XSetForeground(display, info.gc, discolor[NDI_RED].pixel); + XFillRectangle(display, info.win, info.gc, x, y, 2, FONT_HEIGHT); + x += 2; - if (key != 9 ) strcat(infodata.data[infodata.infopos].info,(cpl.no_echo? "?": c2)); - - XDrawImageString(display,infodata.win_info,infodata.gc_info, - FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); + clear: + XClearArea(display, info.win, x, y, info.width-x, FONT_HEIGHT, False); } - - -/* This is similar to draw_info below, but doesn't advance to a new - * line. Generally, queries use this function to draw the prompt for - * the name, password, etc. - * This also starts from character position 0. Thus, only 1 call of this - * per a given line is useful - */ - -void draw_prompt(const char *str) +void +draw_prompt(const char *str) { - if (infodata.lastcolor!=NDI_BLACK) { - XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel); - infodata.lastcolor=NDI_BLACK; - } - - strncpy(infodata.data[infodata.infopos].info,str,infodata.info_chars); - infodata.data[infodata.infopos].info[infodata.info_chars] = '\0'; - infodata.data[infodata.infopos].color=NDI_BLACK; - XDrawImageString(display,infodata.win_info, - infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); + strncpy(info.prompt, str, INFO_CHARS); + info.prompt[INFO_CHARS] = 0; + history.pos = 0; + DrawInput(); } -/* If redarew is true, draw the scrollbar no matter what */ -static void draw_info_scrollbar(int redraw) +static void +draw_info_scrollbar(int redraw) { - static int last_length=0, last_y=0; + static int last_size = -1, last_y = -1; + int pos, size, y; - if (!infodata.has_scrollbar) return; + pos = info.bar_pos - info.pos - info.cheight; + pos = (pos + 2*info.lines) % info.lines; - if (infodata.numlines infodata.bar_length) { - infodata.bar_y=infodata.bar_length-infodata.bar_size; - } -*/ - if (!redraw && last_length==infodata.bar_size && last_y==infodata.bar_y) return; + size = (info.bar_length * info.cheight + info.lines-1) / info.lines; + y = info.bar_length * pos / info.lines; - last_y=infodata.bar_y; - last_length=infodata.bar_size; + if (size < 1) + size = 1; - /* Note - with the way this is set up, it wouldn't be too hard to make - * the scrollbar color customizable - */ - if (infodata.lastcolor!=NDI_BLACK) { - XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel); - infodata.lastcolor=NDI_BLACK; - } - - XDrawRectangle(display, infodata.win_info, - infodata.gc_info, infodata.width-SCROLLBAR_WIDTH-6, - 3, 20, - infodata.height -6); - XClearArea(display, infodata.win_info, - infodata.width-SCROLLBAR_WIDTH-4, 4, 16, - infodata.bar_length, False); - - XFillRectangle(display, infodata.win_info, infodata.gc_info, - infodata.width - SCROLLBAR_WIDTH-4,4+infodata.bar_y, - 16, infodata.bar_size); -} + if (!redraw && last_size == size && last_y == y) + return; -/* draw_info adds a line to the info window. */ + last_y = y; + last_size = size; -void draw_info(const char *str, int color) { - char *cp; - uint16 new_infopos = (infodata.infopos+1)% infodata.maxlines ; + XSetForeground(display, info.gc, discolor[NDI_BLACK].pixel); - if(str == (char *) NULL) { - draw_info("[NULL]",color); - return; - } + DrawRectangle(display, info.win, info.gc, + info.width-BW-SCROLLBAR_WIDTH, BW, + SCROLLBAR_WIDTH, info.bar_length+4); + XClearArea(display, info.win, + info.width-BW-SCROLLBAR_WIDTH+2, BW+2, + SCROLLBAR_WIDTH-4, info.bar_length, False); + + XFillRectangle(display, info.win, info.gc, + info.width-BW-SCROLLBAR_WIDTH+2, BW+2+y, + SCROLLBAR_WIDTH-4, size); +} - if((cp=strchr(str,'\n'))!=NULL) { - /* 4096 is probably way overkill, but 1024 could very well be too small. - * And I don't see the need to malloc and then free this either - - * this is a single user program. - */ - char obuf[4096],*buf = obuf; +/* draw_info adds a line to the info window. */ - strncpy(buf,str, 4095); - do { - if ((cp = strchr(buf, '\n'))) { - *cp='\0'; - draw_info(buf,color); - buf = cp +1; - } else - draw_info(buf,color); - } while (cp!=NULL); - return; - } +void +draw_info(const char *str, int color) +{ + char *p, buf[256]; + InfoLine *lp; + int l; - /* Lets do the word wrap for messages - MSW */ - if ((int)strlen(str) >= infodata.info_chars) { - int i=infodata.info_chars-1; - - /* i=last space (or ')' for armor. Wrap armor, because - otherwise, the two sets of ()() can be about half the line */ - while ((str[--i]!=' ') && (str[i]!=')') && (i!=0)) ; - /* if i==0, string has no space. Just let it be truncated */ - if (i!=0) { - char *buf = (char *)malloc(sizeof(char)*(i+2)); - int j; - - i++; /* want to keep the ')'. This also keeps - the space, but that really doesn't matter */ - strncpy(buf, str, i); - buf[i]='\0'; - draw_info(buf,color); - free(buf); - - for (j=i; j < (int)strlen(str); j++) /* if the wrap portion is */ - if (str[j]!=' ') break; /* only space, don't wrap it*/ - if ((((strlen(str)-i)!=1) || (str[i]!='.')) && (j!=strlen(str))) - draw_info((str+i),color); - return; + if (str == NULL) + str = "[NULL]"; + + /* split lines */ + while ((p = strchr(str,'\n'))) { + if (p - str < sizeof(buf)) { + memcpy(buf, str, p - str); + buf[p - str] = 0; + draw_info(buf, color); } - } - - /* This is the real code here - stuff above is just formating and making - * it look nice. This stuff here is actually drawing the code - */ - - /* clear the new last line in window */ - memset(infodata.data[new_infopos].info, 32, infodata.info_chars-1); - if(cpl.input_state == Command_Mode) - { - /* we copy the last command line to the new last line in window */ - strcpy(infodata.data[new_infopos].info, infodata.data[infodata.infopos].info); - } - infodata.data[new_infopos].info[infodata.info_chars] = '\0'; - - strncpy(infodata.data[infodata.infopos].info,str,infodata.info_chars); - infodata.data[infodata.infopos].info[infodata.info_chars] = '\0'; - infodata.data[infodata.infopos].color=color; - - /* This area is for scrollbar handling. The first check is to see if - * the scrollbar is at the very end, if it is, then we don't care about this. - * IF not at the end, then see if it is at the end of the window. If - * so, increase the bar position so that that view area keeps up with what - * is being drawn. If we are not at the end of the buffer, then decrease - * the bar position - in this way, we keep the same viewable area visible - * for redraws. - * - * A couple notes: If jump to end was desired on output, then this - * code just needs to be replaced with a line like infodata.bar_pos= - * infodata.numlines. - * If it is desired for the window to scroll up as new output is printed - * out, then the second case would need to be removed, and a draw_all_info - * call added instead. - */ - if (infodata.bar_pos=infodata.numlines) { - /* - * The XDrawImageString draws the line. - */ - if (infodata.lastcolor!=color) { - XSetForeground(display,infodata.gc_info,discolor[color].pixel); - infodata.lastcolor=color; + str = p + 1; } - - XDrawImageString(display,infodata.win_info, - infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); - /* Now it gets potentially more complicated - now we have to handle - * wrapping and stuff like that. - */ + /* word wrap */ + while (strlen(str) > info.cwidth) { + int i = info.cwidth; - if(++(infodata.infoline)>=infodata.maxdisp){ - if (infodata.scroll_info_window) { - XCopyArea(display,infodata.win_info,infodata.win_info, - infodata.gc_info,0,FONTHEIGHT,infodata.info_chars*FONTWIDTH, - infodata.maxdisp*FONTHEIGHT,0,0); - infodata.infoline--; - } - else - infodata.infoline=0; - } - } + /* split at last ' ' or ')' */ + while (i && str[i] != ' ' && str[i-1] != ')') + i--; - infodata.infopos = new_infopos; + if (i == 0) /* no split point -> hard break */ + i = info.cwidth; - if (!infodata.has_scrollbar || infodata.bar_pos>=infodata.numlines) { - if(cpl.input_state == Command_Mode) - { - uint8 endpos = strlen(infodata.data[infodata.infopos].info); - - infodata.data[infodata.infopos].info[endpos] = ' '; - XDrawImageString(display,infodata.win_info, - infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, infodata.info_chars-1); - infodata.data[infodata.infopos].info[endpos] = '\0'; - } - else - { - XDrawImageString(display,infodata.win_info, - infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, infodata.info_chars-1); - } - } - - /* If in a reply state, grab the input buffer and store it. - */ - if (cpl.input_state==Reply_Many) { - strncpy(infodata.data[infodata.infopos].info, cpl.input_text, - infodata.info_chars); - infodata.data[infodata.infopos].info[infodata.info_chars] = '\0'; - - XDrawImageString(display,infodata.win_info,infodata.gc_info, - FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT, - infodata.data[infodata.infopos].info, - strlen(infodata.data[infodata.infopos].info)); - } - /* We should have some intelligent checks so it is not drawn unnecessarily */ - draw_info_scrollbar(FALSE); -} + if (i < sizeof(buf)) { + memcpy(buf, str, i); + buf[i] = 0; + draw_info(buf, color); + } + str += i; + while (*str == ' ') + str++; -/* This is pretty much print_message, but the name is changed, and some - * unnecessary code has been removed. - */ + /* if the rest of the line is empty or only a single '.' abort */ + if (*str == 0 || (*str == '.' && str[1] == 0)) + return; + } -void draw_color_info(int colr, const char *buf){ - draw_info(buf,colr); -} + /* This is the real code here - stuff above is just formating and making + * it look nice. This stuff here is actually drawing the code + */ + /* insert new line */ + info.pos = (info.pos + 1) % info.lines; + strncpy(info.line[info.pos].text,str,INFO_CHARS); + info.line[info.pos].color=color; + + /* adjust scrollbar position */ + info.bar_pos = (info.bar_pos + 1) % info.lines; + + /* scroll up */ + XCopyArea(display, info.win, info.win, info.gc, + BW, BW+FONT_HEIGHT, + info.cwidth*FONT_WIDTH, (info.cheight - 1) * FONT_HEIGHT, + BW, BW); + + /* redraw the bottom line */ + lp = info.line + info.bar_pos; + l = strlen(lp->text); + if (l < info.cwidth) // have to redraw the whole line, fill it up + memset(lp->text + l, ' ', info.cwidth - l); + XSetForeground(display, info.gc, discolor[lp->color].pixel); + DrawInfoText(info.cheight - 1, lp->text); + if (l < info.cwidth) + lp->text[l] = 0; +} /* * draw_all_info is only needed for redraws, which includes scrollbar * movement */ +static void +draw_all_info(void) +{ + int i; -static void draw_all_info(void) { - int i; - - XClearWindow(display,infodata.win_info); - if (infodata.numlines>=infodata.maxdisp) { - int startline=infodata.infopos-infodata.maxdisp- - (infodata.numlines-infodata.bar_pos)+1,displine=0; - - if (startline<0) startline+=infodata.maxlines; - - /* If we are scrolling back (bar_pos=infodata.numlines) { - displine=(infodata.infoline+1) % infodata.maxdisp; - /* So that when we now that we have scrolled back */ - - } - else infodata.infoline=infodata.maxdisp-1; - } + XClearWindow(display,info.win); - for (i=0; icolor].pixel); + DrawInfoText(i, lp->text); + } + DrawInput(); + draw_info_scrollbar(TRUE); } -static void resize_win_message(int width, int height) { - messagehint.width = width; - messagehint.height = height; -} static void resize_win_info(int width, int height) { - int chars=(width/FONTWIDTH)-1; - int lines=(height/FONTHEIGHT)-1; - int i; - InfoLine *newlines; - - if (infodata.width==width && - infodata.height==height) return; - - if(chars<3 || lines<3) - return; - - infodata.width=width; - infodata.height=height; - infodata.bar_length=infodata.height - 8; - if (infodata.has_scrollbar) chars-=3; - + int chars, lines, i; - /* We have a scrollback buffer. All we need to change then is maxdisp */ - if (infodata.maxdisp != infodata.maxlines && lines= lines)) infodata.infoline = lines - 1; - infodata.maxdisp=lines; - } - /* The window has changed size, but the amount of data we can display - * has not. so just redraw the window and return. - */ - if (chars == infodata.info_chars && lines == infodata.maxdisp) { - draw_all_info(); - return; - } + if (width < BW + 3*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW) + width = BW + 3*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW; + if (height < BW + 2*FONT_HEIGHT + BW + INPUT_HEIGHT) + height = BW + 2*FONT_HEIGHT + BW + INPUT_HEIGHT; - /* Either we have a scrollbar (as above), or the window has not - * changed in height, so we just need to change the size of the - * buffers. - */ - if (lines == infodata.maxdisp) { - for (i=0; iinfodata.max_info_chars) { - infodata.data[i].info= realloc(infodata.data[i].info, sizeof(char) * (chars+1)); - } - /* Terminate buffer in both cases */ - infodata.data[i].info[chars]='\0'; - } - infodata.info_chars=chars; - draw_all_info(); + if (info.width == width && info.height == height) return; - } - /* IF we get here, the window has grown or shrunk, and we don't have - * a scrollbar. This code is a lot simpler than what was here before, - * but probably is not as efficient (But with the number of resize - * events likely, this should not be a big deal). - */ - /* First, allocate new storage */ - newlines = malloc(sizeof(InfoLine) * lines); - for (i=0; i INFO_CHARS) + chars = INFO_CHARS; + + info.width = width; + info.height = height; + info.bar_length = height - BW - BW - INPUT_HEIGHT - 4; + info.cwidth = chars; + info.cheight = lines; + + if (lines > info.lines) { /* grow scrollback buffer */ + lines *= 4; + info.line = realloc(info.line, sizeof(InfoLine) * lines); + for (i = info.lines; i < lines; ++i) { + info.line[i].text[0] = '\0'; + info.line[i].text[INFO_CHARS] = '\0'; + info.line[i].color = 0; } + info.lines = lines; } - else { - /* We have to lose data, so keep the most recent. */ - int start=infodata.infopos-lines,k; - - if (start<0) start += infodata.maxlines; - for (i=0; i0) - { - bar=(cpl.stats.hp*MAX_BARS_MESSAGE)/cpl.stats.maxhp; - if(bar<0) - bar=0; - is_alert=(cpl.stats.hp <= cpl.stats.maxhp/4); - } - else - { - bar=0; - is_alert=0; - } - if (redraw || scrollsize_hp!=bar || scrollhp_alert!=is_alert) - draw_stat_bar(20, bar, is_alert); - scrollsize_hp=bar; - scrollhp_alert=is_alert; - - /* draw sp bar. spellpoints can go above max - * spellpoints via supercharging with the transferrance spell, - * or taking off items that raise max spellpoints. - */ - if (cpl.stats.sp>cpl.stats.maxsp) - bar = MAX_BARS_MESSAGE; - else - bar=(cpl.stats.sp*MAX_BARS_MESSAGE)/cpl.stats.maxsp; - if(bar<0) - bar=0; - - is_alert=(cpl.stats.sp <= cpl.stats.maxsp/4); - - if (redraw || scrollsize_sp!=bar || scrollsp_alert!=is_alert) - draw_stat_bar(60, bar, is_alert); - - scrollsize_sp=bar; - scrollsp_alert=is_alert; - - /* draw sp bar. grace can go above max or below min */ - if (cpl.stats.grace>cpl.stats.maxgrace) - bar = MAX_BARS_MESSAGE; - else - bar=(cpl.stats.grace*MAX_BARS_MESSAGE)/cpl.stats.maxgrace; - if(bar<0) - bar=0; - - is_alert=(cpl.stats.grace <= cpl.stats.maxgrace/4); - - if (redraw || scrollsize_grace!=bar || scrollgrace_alert!=is_alert) - draw_stat_bar(100, bar, is_alert); - - scrollsize_grace=bar; - scrollgrace_alert=is_alert; - - /* draw food bar */ - bar=(cpl.stats.food*MAX_BARS_MESSAGE)/999; - if(bar<0) - bar=0; - is_alert=(cpl.stats.food <= 999/4); - - if (redraw || scrollsize_food!=bar || scrollfood_alert!=is_alert) - draw_stat_bar(140, bar, is_alert); - - scrollsize_food=bar; - scrollfood_alert=is_alert; + static int oldflags=0; + static int hp = -1, sp = -1, gr = -1, food = -1; + int flags; + int x = BW + 4 * BAR_TOTAL_WIDTH; + int y = BW; + char buf[64]; + + draw_stat_bar(0, cpl.stats.hp, cpl.stats.maxhp, &hp, redraw, "HP"); + draw_stat_bar(1, cpl.stats.sp, cpl.stats.maxsp, &sp, redraw, "Mana"); + draw_stat_bar(2, cpl.stats.grace, cpl.stats.maxgrace, &gr, redraw, "Grace"); + draw_stat_bar(3, cpl.stats.food, 999, &food, redraw, "Food"); flags = cpl.stats.flags; - if (cpl.fire_on) flags |= SF_FIREON; if (cpl.run_on) flags |= SF_RUNON; - - if ((flags & SF_FIREON ) != (oldflags & SF_FIREON)) { - if (flags & SF_FIREON) - XDrawImageString(display, win_message, - look_list.gc_text, 180, 15, "Fire On", 7); - else - XClearArea(display, win_message, - 180, 0, 60, 15, False); - } - if ((flags & SF_RUNON ) != (oldflags & SF_RUNON)) { - if (flags & SF_RUNON) - XDrawImageString(display, win_message, - look_list.gc_text, 180, 30, "Run On", 6); - else - XClearArea(display, win_message, - 180, 15, 60, 15, False); + if (redraw || flags != oldflags) { + DrawText(win_message, look_list.gc_text, + x + 12*FONT_WIDTH, y, + (flags & SF_FIREON) ? "Fire" : " "); + DrawText(win_message, look_list.gc_text, + x + 12*FONT_WIDTH, y + FONT_HEIGHT, + (flags & SF_RUNON) ? "Run" : " "); + oldflags = flags; } - oldflags = flags; + if (redraw || cpl.stats.resist_change) { - int x=180, y=45,i; - char buf[40]; + int i, j, map[NUM_RESISTS]; - cpl.stats.resist_change=0; - XClearArea(display, win_message, 180, 30, messagehint.width-180, messagehint.height-30, False); - for (i=0; imessagehint.height) break; - } /* If we have a resistance with value */ - } /* For loop of resistances */ - } /* If we need to draw the resistances */ + for (i = 0; i < NUM_RESISTS; ++i) + map[i] = i; + qsort(map, NUM_RESISTS, sizeof(int), sort_resists); + + for (i = 0; i < NUM_RESISTS && cpl.stats.resists[j = map[i]]; ++i) { + sprintf(buf, "%-5.5s%+4d", resists_name[j], + cpl.stats.resists[j]); + DrawText(win_message, look_list.gc_text, x, y, buf); + y += FONT_HEIGHT; + } + XClearArea(display, win_message, x, y, 10*FONT_WIDTH, 999, False); + cpl.stats.resist_change = 0; + } } -static void draw_all_message(void) { - +static void draw_all_message(void) +{ XClearWindow(display,win_message); - xwritedown("HP",06); - XDrawRectangle(display,win_message, - look_list.gc_text,18,2,14,MAX_BARS_MESSAGE+4); - xwritedown("Mana",46); - XDrawRectangle(display,win_message, - look_list.gc_text,58,2,14,MAX_BARS_MESSAGE+4); - xwritedown("Grace",86); - XDrawRectangle(display,win_message, - look_list.gc_text,98,2,14,MAX_BARS_MESSAGE+4); - xwritedown("Food",126); - XDrawRectangle(display,win_message, - look_list.gc_text,138,2,14,MAX_BARS_MESSAGE+4); draw_message_window(1); } @@ -1578,7 +1269,8 @@ static void create_status_icons(void) int x, y; GC tmpgc; - if (hasinit) return; + if (hasinit) + return; hasinit=1; #define CREATEPM(name,data) \ @@ -1619,139 +1311,142 @@ static void create_status_icons(void) * adjacent dark2 image. dark3 results in diagonal stripes. OTOH, these will * change depending on the image size. */ - if ((x+y) % 2) { + if ((x+y) % 2) XDrawPoint(display, dark1, tmpgc, x, y); - } - if ((x+y) %3) { + if ((x+y) % 3) XDrawPoint(display, dark2, tmpgc, x, y); - } - if ((x+y) % 4) { + if ((x+y) % 4) XDrawPoint(display, dark3, tmpgc, x, y); - } } } XFreeGC(display, tmpgc); } + /* * draw_list redraws changed item to the window and updates a scrollbar */ static void draw_list (itemlist *l) { - int i, items, size, pos; + int i, items, size; item *tmp; char buf[MAX_BUF], buf2[MAX_BUF]; + int y = BW; /* draw title */ strcpy(buf2, l->title); if (l->show_what & show_mask) { - strcat(buf2," ("); - if (l->show_what & show_applied) strcat(buf2,"applied, "); - if (l->show_what & show_unapplied) strcat(buf2,"unapplied, "); - if (l->show_what & show_unpaid) strcat(buf2,"unpaid, "); - if (l->show_what & show_cursed) strcat(buf2,"cursed, "); - if (l->show_what & show_magical) strcat(buf2,"magical, "); - if (l->show_what & show_nonmagical) strcat(buf2,"nonmagical, "); - if (l->show_what & show_locked) strcat(buf2,"locked, "); - if (l->show_what & show_unlocked) strcat(buf2,"unlocked, "); + strcpy(buf2,"("); + if (l->show_what & show_applied) strcat(buf2,"applied, "); + if (l->show_what & show_unapplied) strcat(buf2,"unapplied, "); + if (l->show_what & show_unpaid) strcat(buf2,"unpaid, "); + if (l->show_what & show_cursed) strcat(buf2,"cursed, "); + if (l->show_what & show_magical) strcat(buf2,"magical, "); + if (l->show_what & show_nonmagical) strcat(buf2,"nonmagical, "); + if (l->show_what & show_locked) strcat(buf2,"locked, "); + if (l->show_what & show_unlocked) strcat(buf2,"unlocked, "); /* want to kill the comma we put in above. Replace it with the paren */ buf2[strlen(buf2)-2]=')'; buf2[strlen(buf2)-1]='\0'; } - if(l->env->weight < 0 || l->show_weight == 0) - sprintf (buf, l->format_n, buf2); + if (l->env->weight < 0 || l->show_weight == 0) + sprintf(buf, l->format_n, buf2); else if (!l->weight_limit) - sprintf (buf, l->format_nw, buf2, l->env->weight); + sprintf(buf, l->format_nw, buf2, l->env->weight); else - sprintf(buf, l->format_nwl, buf2, l->env->weight, - l->weight_limit/1000); + sprintf(buf, l->format_nwl, buf2, l->env->weight, l->weight_limit); - if (strcmp (buf, l->old_title)) { - XCopyPlane(display, icons[l->env->open ? close_icon : no_icon], - l->win, l->gc_status, 0,0, image_size,13, 2,2, 1); + if (strcmp(buf, l->old_title)) { strcpy (l->old_title, buf); - XDrawImageString(display, l->win, l->gc_text, - (l->show_icon ? image_size+24+4 : image_size+4), - 13, buf, strlen(buf)); + XCopyPlane(display, icons[l->env->open ? close_icon : no_icon], + l->win, l->gc_status, 0,0, 24,13, + BW, y + (FONT_HEIGHT-13)/2, 1); + DrawText(l->win, l->gc_text, + BW + image_size + (l->show_icon ? 24 : 0), y, buf); } /* Find how many objects we should draw. */ - for(tmp = l->env->inv, items=0; tmp ;tmp=tmp->next) - if (show_object(tmp, l->show_what)) items++; + for (tmp = l->env->inv, items=0; tmp ;tmp=tmp->next) + if (show_object(tmp, l->show_what)) + items++; - if(l->item_pos > items - l->size) + if (l->item_pos > items - l->size) l->item_pos = items - l->size; - if(l->item_pos < 0) + if (l->item_pos < 0) l->item_pos = 0; /* Fast forward to the appropriate item location */ - for(tmp = l->env->inv, i=l->item_pos; tmp && i; tmp=tmp->next) - if (show_object(tmp, l->show_what)) i--; - - for(i=0; tmp && i < l->size; tmp=tmp->next) { - if (!show_object(tmp, l->show_what)) continue; + for (tmp = l->env->inv, i=l->item_pos; tmp && i; tmp=tmp->next) + if (show_object(tmp, l->show_what)) + i--; + + y += FONT_HEIGHT; + for (i=0; tmp && i < l->size; tmp=tmp->next) { + if (!show_object(tmp, l->show_what)) + continue; /* draw face */ - if(l->faces[i] != tmp->face) { + if (l->faces[i] != tmp->face) { l->faces[i] = tmp->face; - XClearArea(display, l->win, 4, 16 + image_size * i, - image_size, image_size, False); - gen_draw_face (l->win, tmp->face,4, 16 + image_size * i, 0, 0); + XClearArea(display, l->win, BW, y, image_size, image_size, False); + gen_draw_face(l->win, tmp->face, BW, y, 0, 0); } /* draw status icon */ if (l->show_icon) { - sint8 tmp_icon; + int tmp_icon; tmp_icon = tmp->locked ? locked_icon : no_icon; if (l->icon1[i] != tmp_icon) { l->icon1[i] = tmp_icon; - draw_status_icon (l, image_size+4, 16 + image_size * i, tmp_icon); + draw_status_icon(l, BW + image_size, y, tmp_icon); } tmp_icon = tmp->applied ? applied_icon : tmp->unpaid ? unpaid_icon : no_icon; if (l->icon2[i] != tmp_icon) { l->icon2[i] = tmp_icon; - draw_status_icon (l, image_size+4, 22 + image_size * i, tmp_icon); + draw_status_icon(l, BW + image_size, y + 6, tmp_icon); } tmp_icon = tmp->magical ? magic_icon : no_icon; if (l->icon3[i] != tmp_icon) { l->icon3[i] = tmp_icon; - draw_status_icon (l, image_size+4, 28 + image_size * i, tmp_icon); + draw_status_icon(l, BW + image_size, y + 12, tmp_icon); } tmp_icon = tmp->damned ? damned_icon : tmp->cursed ? cursed_icon : no_icon; if (l->icon4[i] != tmp_icon) { l->icon4[i] = tmp_icon; - draw_status_icon (l, image_size+4, 34 + image_size * i, tmp_icon); + draw_status_icon(l, BW + image_size, y + 18, tmp_icon); } } /* draw name */ - strcpy (buf2, tmp->d_name); + strcpy(buf2, tmp->d_name); if (l->show_icon == 0) - strcat (buf2, tmp->flags); + strcat(buf2, tmp->flags); - if(tmp->weight < 0 || l->show_weight == 0) + if (tmp->weight < 0 || l->show_weight == 0) sprintf(buf, l->format_n, buf2); else sprintf(buf, l->format_nw, buf2, tmp->nrof * tmp->weight); - if(!l->names[i] || strcmp(buf, l->names[i])) { + if (!l->names[i] || strcmp(buf, l->names[i])) { copy_name (l->names[i], buf); - XDrawImageString(display, l->win, l->gc_text, - (l->show_icon?image_size+24+4:image_size+4), - 34 + image_size * i, buf, strlen(buf)); + DrawText(l->win, l->gc_text, + BW + image_size + (l->show_icon ? 24 : 0), + y + (image_size - FONT_HEIGHT)/2, + buf); } i++; + y += image_size; } /* If there are not enough items to fill in the display area, * then set the unused ares to nothing. */ - if(items < l->item_used) { - XClearArea(display, l->win, 0, 16 + image_size * i, l->width - 23, - image_size * (l->size - i) , False); + if (items < l->item_used) { + XClearArea(display, l->win, 0, y, + l->width - BW - SCROLLBAR_WIDTH, l->height - y, False); while (i < l->item_used) { - copy_name (l->names[i], ""); + copy_name(l->names[i], ""); l->faces[i] = 0; l->icon1[i] = l->icon2[i] = l->icon3[i] = l->icon4[i] = 0; i++; @@ -1760,21 +1455,22 @@ static void draw_list (itemlist *l) l->item_used = items > l->size ? l->size : items; /* draw the scrollbar now */ - if(items < l->size) + if (items < l->size) items = l->size; size = (long) l->bar_length * l->size / items; - pos = (long) l->bar_length * l->item_pos / items; - - if(l->bar_size != size || pos != l->bar_pos) { + y = (long) l->bar_length * l->item_pos / items; - XClearArea(display, l->win, l->width-20, 17 + l->bar_pos, 16, - l->bar_size, False); + if (l->bar_size != size || y != l->bar_y) { + XClearArea(display, l->win, + l->width-BW-SCROLLBAR_WIDTH+2, BW+FONT_HEIGHT+2 + l->bar_y, + SCROLLBAR_WIDTH-4, l->bar_size, False); l->bar_size = size; - l->bar_pos = pos; + l->bar_y = y; - XFillRectangle(display, l->win, l->gc_text, l->width - 20, - 17 + l->bar_pos, 16, l->bar_size); + XFillRectangle(display, l->win, l->gc_text, + l->width-BW-SCROLLBAR_WIDTH+2, BW+FONT_HEIGHT+2 + l->bar_y, + SCROLLBAR_WIDTH-4, l->bar_size); } } @@ -1788,7 +1484,7 @@ static void draw_all_list(itemlist *l) strcpy (l->old_title, ""); - for(i=0; isize; i++) { + for (i=0; isize; i++) { copy_name(l->names[i], ""); l->faces[i] = 0; l->icon1[i] = 0; @@ -1798,8 +1494,9 @@ static void draw_all_list(itemlist *l) } XClearWindow(display, l->win); - XDrawRectangle(display, l->win, l->gc_text, l->width - 22, 15, 20, - l->bar_length + 4); + DrawRectangle(display, l->win, l->gc_text, + l->width - BW - SCROLLBAR_WIDTH, BW + FONT_HEIGHT, + SCROLLBAR_WIDTH, l->bar_length + 4); #if 0 /* Don't reset these - causes window position to reset too often */ @@ -1837,63 +1534,50 @@ void close_container (item *op) static void resize_list_info(itemlist *l, int w, int h) { - int i; + int i, len; - if (l->faces) - free(l->faces); - if (l->icon1) - free(l->icon1); - if (l->icon2) - free(l->icon2); - if (l->icon3) - free(l->icon3); - if (l->icon4) - free(l->icon4); + if (w < BW + image_size + 24 + 4*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW) + w = BW + image_size + 24 + 4*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW; + if (h < BW + FONT_HEIGHT + image_size + BW) + h = BW + FONT_HEIGHT + image_size + BW; + + free(l->faces); + free(l->icon1); + free(l->icon2); + free(l->icon3); + free(l->icon4); if (l->names) { for (i=0; i < l->size; i++) - if (l->names[i]) - free(l->names[i]); + free(l->names[i]); free(l->names); } l->width = w; l->height = h; - l->size = (l->height - FONTHEIGHT - 8) / image_size; - l->text_len = (l->width - (l->show_icon ? 84 : 60)) / FONTWIDTH; - l->bar_length = l->size * image_size; - sprintf (l->format_nw, "%%-%d.%ds%%6.1f", l->text_len-6, l->text_len-6); - sprintf (l->format_nwl, "%%-%d.%ds%%6.1f/%%4d", l->text_len-11, l->text_len-11); - sprintf (l->format_n, "%%-%d.%ds", l->text_len, l->text_len); + l->size = (l->height - BW - FONT_HEIGHT - BW) / image_size; + l->bar_length = l->size * image_size - 4; + + len = (l->width - BW - image_size - (l->show_icon ? 24 : 0) + - BW - SCROLLBAR_WIDTH - BW) / FONT_WIDTH; + sprintf(l->format_n, "%%-%d.%ds", len, len); + if (len > 6) + sprintf(l->format_nw, "%%-%d.%ds%%6.1f", len - 6, len - 6); + else + strcpy(l->format_nw, l->format_n); + if (len > 11) + sprintf(l->format_nwl, "%%-%d.%ds%%6.1f/%%4d", len - 11, len - 11); + else + strcpy(l->format_nwl, l->format_nw); + + l->faces = xmalloc(sizeof(*l->faces) * l->size); + l->icon1 = xmalloc(sizeof(*l->icon1) * l->size); + l->icon2 = xmalloc(sizeof(*l->icon2) * l->size); + l->icon3 = xmalloc(sizeof(*l->icon3) * l->size); + l->icon4 = xmalloc(sizeof(*l->icon4) * l->size); + l->names = xmalloc(sizeof(*l->names) * l->size); + + for (i=0; i < l->size; i++) + l->names[i] = xmalloc(NAME_LEN); - if ((l->faces = malloc (sizeof (*(l->faces)) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - if ((l->icon1 = malloc (sizeof (*(l->icon1)) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - if ((l->icon2 = malloc (sizeof (*(l->icon2)) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - if ((l->icon3 = malloc (sizeof (*(l->icon3)) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - if ((l->icon4 = malloc (sizeof (*(l->icon4)) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - if ((l->names = malloc (sizeof (char *) * l->size )) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - for (i=0; i < l->size; i++) { - if ((l->names[i] = malloc (NAME_LEN)) == NULL) { - printf ("Can't allocate memory.\n"); - exit (0); - } - } draw_all_list(l); /* this also initializes above allocated tables */ } @@ -1901,6 +1585,7 @@ static void get_list_display(itemlist *l const char *t, const char *s) { XSizeHints hint; + XClassHint classhint; l->faces=NULL; l->names=NULL; @@ -1908,17 +1593,19 @@ static void get_list_display(itemlist *l hint.y = y; hint.width = w; hint.height = h; - hint.min_width = 60 + 10 * FONTWIDTH; - hint.min_height = FONTHEIGHT + 8 + image_size * 2; hint.flags = PPosition | PSize; + l->win = XCreateSimpleWindow(display, win_root, hint.x, hint.y, hint.width, - hint.height, 2, foreground, background); + hint.height, 0, foreground, background); XSetWindowColormap(display, l->win, colormap); icon = XCreateBitmapFromData(display, l->win, (_Xconst char *) crossfire_bits, (unsigned int) crossfire_width, (unsigned int)crossfire_height); XSetStandardProperties(display, l->win, t, s, icon, gargv, gargc, &(hint)); + classhint.res_name = (char *)s; + classhint.res_class = X_CLASS; + XSetClassHint(display, l->win, &classhint); l->gc_text = XCreateGC (display, l->win, 0, 0); l->gc_icon = XCreateGC (display, l->win, 0, 0); l->gc_status = XCreateGC (display, l->win, 0, 0); @@ -1942,14 +1629,14 @@ static void get_list_display(itemlist *l static int get_inv_display(void) { inv_list.env = cpl.ob; - strcpy (inv_list.title, ""/*ET: too long: "Inventory:"*/); + strcpy (inv_list.title, "Inventory:"); inv_list.show_weight = 1; inv_list.show_what = show_all; inv_list.weight_limit=0; - get_list_display ( &inv_list, 0, 0, INV_WIDTH, - 2*(roothint.height - WINDOW_SPACING) / 3, - "Crossfire - inventory", - "crossinventory"); + get_list_display( &inv_list, 0, 0, + INV_WIDTH, + 2*(roothint.height - GAP) / 3, + "Crossfire - inventory", "crossinventory"); return 0; } @@ -1959,11 +1646,11 @@ static int get_look_display(void) strcpy (look_list.title, "You see:"); look_list.show_weight = 1; look_list.show_what = show_all; - inv_list.weight_limit = 0; - get_list_display ( &look_list, 0, - (2*(roothint.height - WINDOW_SPACING) / 3) + WINDOW_SPACING, + look_list.weight_limit = 0; + get_list_display( &look_list, 0, + (2*(roothint.height - GAP) / 3) + GAP, INV_WIDTH, - (roothint.height - WINDOW_SPACING) / 3, + (roothint.height - GAP) / 3, "Crossfire - look", "crosslook"); return 0; @@ -2009,23 +1696,12 @@ void set_show_weight (const char *s) void set_weight_limit (uint32 wlim) { - inv_list.weight_limit = wlim; + inv_list.weight_limit = wlim / 1000; } void set_scroll(const char *s) { - if (!infodata.scroll_info_window) { - infodata.scroll_info_window=1; - if (infodata.numlines>=infodata.maxdisp) { - infodata.infoline=infodata.maxdisp-1; - } - draw_all_info(); - draw_info("Scroll is enabled", NDI_BLACK); - } - else { - draw_info("Scroll is disabled", NDI_BLACK); - infodata.scroll_info_window=0; - } + draw_info("Scroll cannot be disabled", NDI_BLACK); } void set_autorepeat(const char *s) @@ -2037,7 +1713,7 @@ void set_autorepeat(const char *s) int get_info_width() { - return infodata.info_chars; + return info.cwidth; } void menu_clear(void) @@ -2072,7 +1748,9 @@ void item_event_item_changed(item * it) */ int sync_display = 0; -static int get_root_display(char *display_name) { +static int get_root_display(char *display_name) +{ + XClassHint classhint; char *cp; display=XOpenDisplay(display_name); @@ -2118,7 +1796,7 @@ static int get_root_display(char *displa use_config[CONFIG_ECHO] = FALSE; } if ((cp=XGetDefault(display,X_PROG_NAME, "scrollLines"))!=NULL) { - infodata.maxlines=atoi(cp); + info.lines=atoi(cp); } if ((cp=XGetDefault(display,X_PROG_NAME,"font")) != NULL) { font_name = strdup_local(cp); @@ -2129,29 +1807,24 @@ static int get_root_display(char *displa fprintf(stderr,"Could not load font %s\n", font_name); exit(1); } - FONTWIDTH=font->max_bounds.width; - FONTHEIGHT=font->max_bounds.ascent + font->max_bounds.descent; + FONT_WIDTH=font->max_bounds.width; + FONT_HEIGHT=font->max_bounds.ascent + font->max_bounds.descent; + FONT_BASE=font->max_bounds.ascent; background=WhitePixel(display,def_screen); foreground=BlackPixel(display,def_screen); + roothint.x=0; roothint.y=0; - roothint.width=582+6+INFOCHARS*FONTWIDTH; - roothint.height=ROOT_HEIGHT; - /* Make up for the extra size of the game window. 88 is - * 11 tiles * 8 pixels/tile bigger size. - */ - roothint.width += 88; - roothint.height+= 88; - init_pngx_loader(display); - - roothint.max_width=roothint.min_width=roothint.width; - roothint.max_height=roothint.min_height=roothint.height; + roothint.width = INV_WIDTH +GAP+ GAME_WIDTH +GAP+ INFO_WIDTH; + roothint.height = STAT_HEIGHT +GAP+ GAME_HEIGHT +GAP+ MSG_HEIGHT; roothint.flags=PSize; /*ET: no PPosition. let window manager handle that. */ - if(!want_config[CONFIG_SPLITWIN]) { + init_pngx_loader(display); + + if (!want_config[CONFIG_SPLITWIN]) { win_root=XCreateSimpleWindow(display,def_root, - roothint.x,roothint.y,roothint.width,roothint.height,2, + roothint.x,roothint.y,roothint.width,roothint.height,0, background,foreground); allocate_colors(display, win_root, def_screen, &colormap, discolor); @@ -2160,8 +1833,11 @@ static int get_root_display(char *displa icon=XCreateBitmapFromData(display,win_root, (_Xconst char *) crossfire_bits, (unsigned int) crossfire_width, (unsigned int)crossfire_height); - XSetStandardProperties(display,win_root,X_PROG_NAME,X_PROG_NAME, - icon,gargv,gargc,&(roothint)); + XSetStandardProperties(display,win_root,"Crossfire X11 Client V" + VERSION, "crossfire", icon,gargv,gargc,&roothint); + classhint.res_name = "root"; + classhint.res_class = X_CLASS; + XSetClassHint(display, win_root, &classhint); gc_root=XCreateGC(display,win_root,0,0); XSetForeground(display,gc_root,foreground); XSetBackground(display,gc_root,background); @@ -2169,64 +1845,67 @@ static int get_root_display(char *displa XSelectInput(display,win_root,KeyPressMask| KeyReleaseMask|ExposureMask|StructureNotifyMask); XMapRaised(display,win_root); - XNextEvent(display,&event); /*ET: this is bogus */ - XSetWMProtocols(display, win_root, &wm_delete_window, 1); + XSetWMProtocols(display, win_root, &wm_delete_window, 1); } else win_root = def_root; return 0; } -static void resize_win_root(XEvent *event) { - int width, inv_width, info_width; +static void resize_win_root(int width, int height) +{ + int info_width, inv_width, inv_height, stat_height, msg_height; + int x; if (want_config[CONFIG_SPLITWIN]) { fprintf(stderr,"Got a resize root window in split windows mode\n"); return; } - /* The middle 3 windows don't really benefit from the resize, so keep - * them the same size, and use the leftover equally between the left - * and right windows. - */ - width = (event->xconfigure.width - GAME_WIDTH -WINDOW_SPACING*2); - info_width = width * info_ratio; - inv_width = width - info_width; - - /* With png (and 32x32 images), the message window can get scrunched, - * so lets make it taller if we can - there is no reason not to, as otherwise - * that space is lost anyways. - */ - XMoveResizeWindow(display, win_message, inv_width + WINDOW_SPACING, - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2, GAME_WIDTH, - event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2); - messagehint.width=GAME_WIDTH; - messagehint.height=event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2; - - /* These windows just need to be relocated. The y constants are - * hardcoded - those windows don't really benefit from being resized - * (actually, no code in place to currently do it), so no reason - * to get trick with those just now. - */ - - XMoveWindow(display, win_game, inv_width + WINDOW_SPACING, STAT_HEIGHT + WINDOW_SPACING); - XMoveWindow(display, win_stats, inv_width + WINDOW_SPACING, 0); - - /* Resize the info window */ - XMoveResizeWindow(display, infodata.win_info, - inv_width + GAME_WIDTH + WINDOW_SPACING * 2, 0, - info_width, event->xconfigure.height); - - - /* Resize the inventory, message window */ - XResizeWindow(display, inv_list.win, inv_width, - 2 * (event->xconfigure.height - WINDOW_SPACING) / 3); - - - XMoveResizeWindow(display, look_list.win, 0, - (2*(event->xconfigure.height - WINDOW_SPACING) / 3) + WINDOW_SPACING, - inv_width, - (event->xconfigure.height - WINDOW_SPACING) / 3); + /* some sanity checks to make sure all sizes stay positive */ + if (width < 6*BW + 2*GAP + GAME_WIDTH + 20*FONT_WIDTH) + width = 6*BW + 2*GAP + GAME_WIDTH + 20*FONT_WIDTH; + if (height < 2*GAP + STAT_HEIGHT + GAME_HEIGHT) + height = 2*GAP + STAT_HEIGHT + GAME_HEIGHT; + + x = width - GAP - GAME_WIDTH - GAP; + info_width = x * info_ratio; + inv_width = x - info_width; + + x = height - BW - FONT_HEIGHT - BW - GAP - BW - FONT_HEIGHT - BW; + inv_height = BW + FONT_HEIGHT + x / image_size * 2/3 * image_size + BW; + + x = height - STAT_HEIGHT - GAP - GAME_HEIGHT - GAP - MSG_HEIGHT; + if (x < 0) + x = 0; + stat_height = STAT_HEIGHT + x / 2; + + msg_height = height - stat_height - GAP - GAME_HEIGHT - GAP; + if (msg_height < MSG_HEIGHT) + msg_height = MSG_HEIGHT; + + XResizeWindow(display, inv_list.win, + inv_width, inv_height); + + XMoveResizeWindow(display, look_list.win, + 0, inv_height + GAP, + inv_width, height - inv_height - GAP); + + XMoveResizeWindow(display, win_stats, + inv_width + GAP, 0, + GAME_WIDTH, stat_height); + + XMoveResizeWindow(display, win_game, + inv_width + GAP, stat_height + GAP, + GAME_WIDTH, GAME_HEIGHT); + + XMoveResizeWindow(display, win_message, + inv_width + GAP, GAME_HEIGHT + GAP + stat_height + GAP, + GAME_WIDTH, msg_height); + + XMoveResizeWindow(display, info.win, + inv_width + GAP + GAME_WIDTH + GAP, 0, + info_width, height); /* The Resize requests will generate events. As such, we don't call * the resize functions here - the event handler would get those anyways, @@ -2245,12 +1924,12 @@ static void parse_game_button_press(int { int dx, dy, i, xmidl, xmidh, ymidl, ymidh; - dx = (x-2)/image_size-use_config[CONFIG_MAPWIDTH]/2; - dy= (y-2)/image_size-use_config[CONFIG_MAPHEIGHT]/2; - xmidl=(use_config[CONFIG_MAPWIDTH]/2) * image_size; - xmidh=(use_config[CONFIG_MAPWIDTH]/2 + 1) * image_size; - ymidl=(use_config[CONFIG_MAPHEIGHT]/2) * image_size; - ymidh=(use_config[CONFIG_MAPHEIGHT]/2 + 1) * image_size; + dx = x/image_size - use_config[CONFIG_MAPWIDTH]/2; + dy = y/image_size - use_config[CONFIG_MAPHEIGHT]/2; + xmidl = (use_config[CONFIG_MAPWIDTH]/2) * image_size; + xmidh = (use_config[CONFIG_MAPWIDTH]/2 + 1) * image_size; + ymidl = (use_config[CONFIG_MAPHEIGHT]/2) * image_size; + ymidh = (use_config[CONFIG_MAPHEIGHT]/2 + 1) * image_size; switch (button) { case 1: @@ -2258,17 +1937,22 @@ static void parse_game_button_press(int /* Its unlikely this will happen, but if the window is * resized, its possible to be out of bounds. */ - if(dx<(-use_config[CONFIG_MAPWIDTH]/2)||dx>(use_config[CONFIG_MAPWIDTH]/2)||dy<(-use_config[CONFIG_MAPHEIGHT]/2)||dy>(use_config[CONFIG_MAPHEIGHT]/2)) return; + if (dx < -use_config[CONFIG_MAPWIDTH]/2 || + dx > use_config[CONFIG_MAPWIDTH]/2 || + dy < -use_config[CONFIG_MAPHEIGHT]/2 || + dy > use_config[CONFIG_MAPHEIGHT]/2) + return; look_at(dx,dy); + break; } - break; case 2: case 3: if (xxmidh) i = 6; - else i =3; + else + i = 3; if (y>ymidh) i += 2; @@ -2330,7 +2014,7 @@ static void do_key_press(int repeated) cpl.showmagic=0; display_map_doneupdate(TRUE, FALSE); } - if(!XLookupString(&event.xkey,text,10, &gkey,NULL)) { + if (!XLookupString(&event.xkey,text,10, &gkey,NULL)) { /* * This happens quite a bit - most modifier keys (shift, control, etc) * can not be mapped to a value. @@ -2343,12 +2027,10 @@ static void do_key_press(int repeated) } switch(cpl.input_state) { case Playing: - parse_key(text[0],event.xkey.keycode,gkey,repeated); + parse_key(text[0] & 0xff, event.xkey.keycode, gkey, repeated); break; case Reply_One: - /* Don't send modifier keys as reply to query. Tries to prevent - * from getting into the "...state is not ST_PLAYING" state. */ if (text[0]) { text[1]='\0'; send_reply(text); @@ -2363,31 +2045,71 @@ static void do_key_press(int repeated) case Reply_Many: case Command_Mode: case Metaserver_Select: - if (text[0]==13) { - enum Input_State old_state=cpl.input_state; - if (cpl.input_state==Metaserver_Select) { - cpl.input_state=Playing; - return; - } - if (cpl.input_state==Reply_Many) + if (text[0] == 13 || text[0] == 10) { + if (*cpl.input_text && !cpl.no_echo) /* add to history */ + if (!history.line[1] || /* but no dups */ + strcmp(history.line[1], cpl.input_text)) + { + free(history.line[HISTORY_SIZE-1]); + memmove(history.line+2, history.line+1, + (HISTORY_SIZE-2) * sizeof(char *)); + history.line[1] = strdup(cpl.input_text); + } + if (cpl.input_state == Metaserver_Select) { + cpl.input_state = Playing; + } else if (cpl.input_state == Reply_Many) { + cpl.input_state = Playing; send_reply(cpl.input_text); - else { - write_ch(13); + } else { + cpl.input_state = Playing; + draw_info(cpl.input_text, NDI_RED); extended_command(cpl.input_text); } - /* Only set state to playing if the state has otherwise - * not changed - this check is needed because 'bind - * changes the state, and we don't want to change to playing - * again. - */ - if (old_state==cpl.input_state) + cpl.no_echo = 0; /* By default, start echoing thing again */ + history.pos = 0; + } else if (text[0] == 8 || text[0] == 127) { + int l = strlen(cpl.input_text); + if (l) + cpl.input_text[l-1] = 0; + else if (cpl.input_state == Command_Mode) cpl.input_state = Playing; - cpl.input_text[0]='\0'; - cpl.no_echo=0; /* By default, start echoing thing again */ - } - else { - write_ch(text[0]); + else + XBell(display, 100); + } else if (text[0] == 9 && cpl.input_state == Command_Mode) { + const char *str = complete_command(cpl.input_text); + if (str != cpl.input_text) { + strcpy(cpl.input_text, str); + strcat(cpl.input_text, " "); + } else + XBell(display, 100); + } else if (text[0] == 27) { + cpl.input_text[0] = 0; + if (cpl.input_state == Command_Mode) + cpl.input_state = Playing; + } else if (gkey == XK_Up || text[0] == ('P' & 0x1f)) { + if (history.pos == 0) { // save current line + free(history.line[0]); + history.line[0] = strdup(cpl.input_text); + } + if (history.pos+1 < HISTORY_SIZE && history.line[history.pos+1]) + strcpy(cpl.input_text, history.line[++history.pos]); + else + XBell(display, 100); + } else if (gkey == XK_Down || text[0] == ('N' & 0x1f)) { + if (history.pos > 0) + strcpy(cpl.input_text, history.line[--history.pos]); + else + XBell(display, 100); + } else if (text[0] >= 32 && (text[0] & 0xff) <= 127) { + int l = strlen(cpl.input_text); + if (l < MAX_BUF - 15) { + cpl.input_text[l++] = text[0]; + cpl.input_text[l] = 0; + } + else + XBell(display, 100); } + DrawInput(); break; default: @@ -2398,47 +2120,47 @@ static void do_key_press(int repeated) static void buttonpress_in_info(XButtonEvent *xbutton) { - int y = xbutton->y-16, x=xbutton->x, button = xbutton->button,dy,pos=0; + int y = xbutton->y - BW - 2; + int x = xbutton->x; + int button = xbutton->button; + int dy, pos; - if (!infodata.has_scrollbar) + if (button < 4 && x < info.width-BW-SCROLLBAR_WIDTH) return; - if (button < 4 && x <= infodata.width-SCROLLBAR_WIDTH-4) - return; + dy = y / FONT_HEIGHT > 0 ? y / FONT_HEIGHT : 1; - dy = y / FONTHEIGHT > 0 ? y / FONTHEIGHT : 1; + pos = (info.pos - info.bar_pos + info.lines) % info.lines; switch(button) { case 1: - pos = infodata.bar_pos - dy; + pos += dy; break; case 2: - pos = y * infodata.numlines / infodata.bar_length; + pos = info.lines-info.cheight/2 - y * info.lines / info.bar_length; break; case 3: - pos = infodata.bar_pos + dy; + pos -= dy; break; case 4: - pos = infodata.bar_pos - 1; + pos++; break; case 5: - pos = infodata.bar_pos + 1; + pos--; break; } - if (posinfodata.numlines) pos=infodata.numlines; - if (pos != infodata.bar_pos) { - infodata.bar_pos = pos; + if (pos < 0) + pos = 0; + if (pos > info.lines - info.cheight) + pos = info.lines - info.cheight; + pos = (info.pos - pos + info.lines) % info.lines; + if (pos != info.bar_pos) { + info.bar_pos = pos; draw_all_info(); } } @@ -2454,11 +2176,13 @@ static void buttonpress_in_info(XButtonE static int buttonpress_in_list (itemlist *l, XButtonEvent *xbutton) { item *tmp; - int y = xbutton->y - 16, x=xbutton->x, button = xbutton->button; + int y = xbutton->y - BW - FONT_HEIGHT - 2; + int x = xbutton->x; + int button = xbutton->button; int items, pos=0, dy; if (y < 0 && l->env->open) /* close the sack */ - client_send_apply (l->env->tag); + client_send_apply(l->env->tag); if (y < 0 || y > image_size * l->size) return 1; @@ -2473,8 +2197,9 @@ static int buttonpress_in_list (itemlist return 1; } - if (x > l->width-23) { /* scrollbar */ + if (x >= l->width - BW - SCROLLBAR_WIDTH) { /* scrollbar */ + y -= 2; dy = y / image_size > 0 ? y / image_size : 1; switch(button) { @@ -2483,7 +2208,7 @@ static int buttonpress_in_list (itemlist break; case 2: - for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next) + for (tmp=l->env->inv, items=0; tmp; tmp=tmp->next) items++; pos = y * items / l->bar_length; break; @@ -2501,9 +2226,11 @@ static int buttonpress_in_list (itemlist } pos = l->item_pos + y / image_size; - for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next) { - if (show_object(tmp, l->show_what)) items++; - if (items>pos) break; + for (tmp=l->env->inv, items=0; tmp; tmp=tmp->next) { + if (show_object(tmp, l->show_what)) + items++; + if (items>pos) + break; } if (tmp) { switch(button) { @@ -2542,23 +2269,15 @@ static int buttonpress_in_list (itemlist */ char *get_metaserver() { - static char ret_buf[MAX_BUF]; - cpl.input_state = Metaserver_Select; + cpl.input_text[0] = 0; draw_prompt(":"); while (cpl.input_state == Metaserver_Select) { check_x_events(); usleep(50000); /* 1/20 sec */ } /* while input state is metaserver select. */ - /* We need to clear out cpl.input_text - otherwise the next - * long input (like player name) won't work right. - * so copy it to a private buffer and return. - */ - strncpy(ret_buf, cpl.input_text, MAX_BUF-1); - ret_buf[MAX_BUF-1]=0; - cpl.input_text[0]=0; - return ret_buf; + return cpl.input_text; } @@ -2592,7 +2311,8 @@ void check_x_events() { if (want_config[CONFIG_CACHE] && lastupdate>5 && newimages) { update_icons_list(&inv_list); update_icons_list(&look_list); - if (!cpl.showmagic) display_map_doneupdate(TRUE, FALSE); + if (!cpl.showmagic) + display_map_doneupdate(TRUE, FALSE); newimages=0; lastupdate=0; } @@ -2609,53 +2329,64 @@ void check_x_events() { XNextEvent(display,&event); switch(event.type) { - case ConfigureNotify: - if(event.xconfigure.window==infodata.win_info) - resize_win_info(event.xconfigure.width, event.xconfigure.height); - else if(event.xconfigure.window==inv_list.win) - resize_list_info(&inv_list, event.xconfigure.width, - event.xconfigure.height); - else if(event.xconfigure.window==look_list.win) - resize_list_info(&look_list, event.xconfigure.width, - event.xconfigure.height); - else if(event.xconfigure.window==win_root) - resize_win_root(&event); - else if(event.xconfigure.window==win_message) - resize_win_message(event.xconfigure.width, event.xconfigure.height); + case ConfigureNotify: { + int win = event.xconfigure.window; + int w = event.xconfigure.width; + int h = event.xconfigure.height; + + if (win == info.win) + resize_win_info(w, h); + else if (win == inv_list.win) + resize_list_info(&inv_list, w, h); + else if (win == look_list.win) + resize_list_info(&look_list, w, h); + else if (win == win_root) + resize_win_root(w, h); + else if (win == win_message) + resize_win_message(w, h); break; - - case Expose: - /* No point redrawing windows if there are more Expose's to - * come. - */ - if (event.xexpose.count!=0) continue; - if(event.xexpose.window==win_stats) { - XClearWindow(display,win_stats); - draw_stats(1); - } else if(event.xexpose.window==infodata.win_info) - draw_all_info(); - else if(event.xexpose.window==inv_list.win) - draw_all_list(&inv_list); - else if(event.xexpose.window==look_list.win) - draw_all_list(&look_list); - else if(event.xexpose.window==win_message) - draw_all_message(); - else if(event.xexpose.window==win_game) { - if (cpl.showmagic) draw_magic_map(); - else display_map_doneupdate(TRUE, FALSE); - } else if(want_config[CONFIG_SPLITWIN]==FALSE && event.xexpose.window==win_root) { - XClearWindow(display,win_root); } - break; + case Expose: + /* No point redrawing windows if there are more Expose's to + * come. + */ + if (event.xexpose.count!=0) + continue; + + if (event.xexpose.window==win_stats) { + XClearWindow(display,win_stats); + draw_stats(1); + } else if (event.xexpose.window==info.win) + draw_all_info(); + else if (event.xexpose.window==inv_list.win) + draw_all_list(&inv_list); + else if (event.xexpose.window==look_list.win) + draw_all_list(&look_list); + else if (event.xexpose.window==win_message) + draw_all_message(); + else if (event.xexpose.window==win_game) { + if (cpl.showmagic) + draw_magic_map(); + else + display_map_doneupdate(TRUE, FALSE); + } else if (want_config[CONFIG_SPLITWIN]==FALSE && + event.xexpose.window==win_root) { + XClearWindow(display,win_root); + } + break; case GraphicsExpose: /* No point redrawing windows if there are more GraphicExpose's * to come. */ - if (event.xgraphicsexpose.count!=0) continue; - if(event.xgraphicsexpose.drawable==win_game) { - if (cpl.showmagic) draw_magic_map(); - else display_map_doneupdate(TRUE, FALSE); + if (event.xgraphicsexpose.count!=0) + continue; + + if (event.xgraphicsexpose.drawable==win_game) { + if (cpl.showmagic) + draw_magic_map(); + else + display_map_doneupdate(TRUE, FALSE); } break; @@ -2665,25 +2396,23 @@ void check_x_events() { case ButtonPress: - /* Most of these will try to send requests to the server - since we - * are not connected, this will probably fail in some bad way. + /* + * Most of these will try to send requests to the server. + * Since we are not connected, this will probably fail in + * some bad way. */ - if (cpl.input_state != Metaserver_Select) { - - if(event.xbutton.window==win_game) { - parse_game_button_press(event.xbutton.button,event.xbutton.x, - event.xbutton.y); - } else if(event.xbutton.window==inv_list.win) { + if (event.xbutton.window==info.win) + buttonpress_in_info(&event.xbutton); + else if (cpl.input_state != Metaserver_Select) { + if (event.xbutton.window==win_game) + parse_game_button_press(event.xbutton.button, + event.xbutton.x, event.xbutton.y); + else if (event.xbutton.window==inv_list.win) buttonpress_in_list(&inv_list, &event.xbutton); - - } else if(event.xbutton.window==look_list.win) { + else if (event.xbutton.window==look_list.win) buttonpress_in_list(&look_list, &event.xbutton); - } - else if (event.xbutton.window==infodata.win_info) { - buttonpress_in_info(&event.xbutton); - } - break; } + break; case KeyRelease: parse_key_release(event.xkey.keycode, gkey); @@ -2699,12 +2428,13 @@ void check_x_events() { else do_key_press(0); /* regular key */ break; + case ClientMessage: - if(event.xclient.data.l[0] == wm_delete_window){ + if (event.xclient.data.l[0] == wm_delete_window) { LOG(LOG_INFO,"x11::check_x_events","Window closed. Exiting."); exit(0); } - break; + break; } } /* Below does not apply if we're not connected */ @@ -2718,7 +2448,8 @@ void check_x_events() { */ /* Need to do this to show the players position */ - if (cpl.showmagic) magic_map_flash_pos(); + if (cpl.showmagic) + magic_map_flash_pos(); clear_fire_run(); } /* a good place to check for childs */ @@ -2828,7 +2559,8 @@ int init_windows(int argc, char **argv) } x = atoi(argv[on_arg]); for (cp = argv[on_arg]; *cp!='\0'; cp++) - if (*cp == 'x' || *cp == 'X') break; + if (*cp == 'x' || *cp == 'X') + break; if (*cp==0) { fprintf(stderr,"-mapsize requires both and X and Y value (ie, XxY - note the\nx in between.\n"); @@ -2920,7 +2652,7 @@ int init_windows(int argc, char **argv) fprintf(stderr,"-scrolllines requires a number\n"); return 1; } - infodata.maxlines = atoi(argv[on_arg]); + info.lines = atoi(argv[on_arg]); continue; } else if (!strcmp(argv[on_arg],"-font")) { @@ -2953,6 +2685,13 @@ int init_windows(int argc, char **argv) return 1; } } + +#ifndef HAVE_LIBPNG + fprintf(stderr,"Client not configured with Png display mode enabled\n"); + fprintf(stderr,"Install the png library and try recompiling.\n"); + exit(1); +#endif + /* Moving processing and setting of display attributes down here. * This is because a default display mode may also require special * handling. @@ -2960,14 +2699,8 @@ int init_windows(int argc, char **argv) * we just fall back to pixmap mode. But I don't really want to get into * a big nest of #ifdefs checking/setting modes. */ -#ifndef HAVE_LIBPNG - fprintf(stderr,"Client not configured with Png display mode enabled\n"); - fprintf(stderr,"Install the png library and try recompiling.\n"); - exit(1); -#else - image_size=32; -#endif + image_size=32; mapdata_init(); /* Finished parsing all the command line options. Now start @@ -2988,7 +2721,8 @@ int init_windows(int argc, char **argv) init_keys(); init_cache_data(); set_window_pos(); - info_ratio=(float) infodata.width/ (float) (infodata.width + INV_WIDTH); + info_ratio = (float)info.width / (float)(info.width + INV_WIDTH); + XFlush(display); return 0; } @@ -3079,16 +2813,18 @@ void resize_map_window(int x, int y) * but does a reasonable job. Don't do shrinks */ - if (use_config[CONFIG_MAPWIDTH] > old_mapx) width = (use_config[CONFIG_MAPWIDTH] - old_mapx)* image_size; + if (use_config[CONFIG_MAPWIDTH] > old_mapx) + width = (use_config[CONFIG_MAPWIDTH] - old_mapx) * image_size; - if (use_config[CONFIG_MAPHEIGHT] > old_mapy) height = (use_config[CONFIG_MAPHEIGHT] - old_mapy)* image_size; + if (use_config[CONFIG_MAPHEIGHT] > old_mapy) + height = (use_config[CONFIG_MAPHEIGHT] - old_mapy) * image_size; /* if somethign to do */ - if (width>0 || height > 0) { + if (width > 0 || height > 0) { XGetWindowAttributes(display, win_root, &attrib); width += attrib.width; height += attrib.height; - XResizeWindow(display, win_game, x*image_size, y*image_size); + // resize other windows via configure root event XResizeWindow(display, win_root, width, height); } old_mapx=use_config[CONFIG_MAPWIDTH]; @@ -3112,9 +2848,8 @@ void display_map_doneupdate(int redraw, { int ax,ay, mx, my; - if(notice) { + if (notice) return; - } if (cpl.showmagic) { magic_map_flash_pos(); @@ -3122,8 +2857,8 @@ void display_map_doneupdate(int redraw, } XSetClipMask(display,gc_floor,None); - for(ax=0;axcpl.mapyres) cpl.mapxres=cpl.mapyres; - else cpl.mapyres=cpl.mapxres; + if (cpl.mapxres>cpl.mapyres) + cpl.mapxres=cpl.mapyres; + else + cpl.mapyres=cpl.mapxres; if (cpl.mapxres>24) { cpl.mapxres=24; @@ -3236,7 +2963,7 @@ void draw_magic_map() */ for (y = 0; y < cpl.mmapy; y++) { for (x = 0; x < cpl.mmapx; x++) { - uint8 val = cpl.magicmap[y*cpl.mmapx + x]; + int val = cpl.magicmap[y*cpl.mmapx + x]; XSetForeground(display,gc_game, discolor[val&FACE_COLOR_MASK].pixel); XFillRectangle(display,win_game, @@ -3248,7 +2975,8 @@ void draw_magic_map() /* Basically, this just flashes the player position on the magic map */ void magic_map_flash_pos() { - if (!cpl.showmagic) return; + if (!cpl.showmagic) + return; cpl.showmagic ^=2; if (cpl.showmagic & 2) { XSetForeground(display, gc_game, foreground); @@ -3332,7 +3060,7 @@ void save_winpos() fprintf(fp,"win_game: %d %d %d %d\n", wx,wy, w, h); get_window_coord(win_stats, &x,&y, &wx,&wy,&w,&h); fprintf(fp,"win_stats: %d %d %d %d\n", wx,wy, w, h); - get_window_coord(infodata.win_info, &x,&y, &wx,&wy,&w,&h); + get_window_coord(info.win, &x,&y, &wx,&wy,&w,&h); fprintf(fp,"win_info: %d %d %d %d\n", wx,wy, w, h); get_window_coord(inv_list.win, &x,&y, &wx,&wy,&w,&h); fprintf(fp,"win_inv: %d %d %d %d\n", wx,wy, w, h); @@ -3355,14 +3083,17 @@ void set_window_pos() char buf[MAX_BUF],*cp; FILE *fp; - if (!want_config[CONFIG_SPLITWIN]) return; + if (!want_config[CONFIG_SPLITWIN]) + return; sprintf(buf,"%s/.crossfire/winpos", getenv("HOME")); - if (!(fp=fopen(buf,"r"))) return; + if (!(fp=fopen(buf,"r"))) + return; while(fgets(buf,MAX_BUF-1, fp)!=NULL) { buf[MAX_BUF-1]='\0'; - if (!(cp=strchr(buf,' '))) continue; + if (!(cp=strchr(buf,' '))) + continue; *cp++='\0'; if (sscanf(cp,"%d %d %d %d",&xwc.x,&xwc.y,&xwc.width,&xwc.height)!=4) continue; @@ -3371,7 +3102,7 @@ void set_window_pos() if (!strcmp(buf,"win_stats:")) XConfigureWindow(display,win_stats,xwc_mask, &xwc); if (!strcmp(buf,"win_info:")) - XConfigureWindow(display,infodata.win_info,xwc_mask, &xwc); + XConfigureWindow(display,info.win,xwc_mask, &xwc); if (!strcmp(buf,"win_inv:")) XConfigureWindow(display,inv_list.win,xwc_mask, &xwc); if (!strcmp(buf,"win_look:")) @@ -3390,14 +3121,17 @@ void load_defaults() FILE *fp; sprintf(path,"%s/.crossfire/defaults", getenv("HOME")); - if ((fp=fopen(path,"r"))==NULL) return; + if ((fp=fopen(path,"r"))==NULL) + return; while (fgets(inbuf, MAX_BUF-1, fp)) { inbuf[MAX_BUF-1]='\0'; inbuf[strlen(inbuf)-1]='\0'; /* kill newline */ - if (inbuf[0]=='#') continue; + if (inbuf[0]=='#') + continue; /* IF no colon, then we certainly don't have a real value, so just skip */ - if (!(cp=strchr(inbuf,':'))) continue; + if (!(cp=strchr(inbuf,':'))) + continue; *cp='\0'; cp+=2; /* colon, space, then value */ @@ -3410,32 +3144,60 @@ void load_defaults() continue; } if (!strcmp(inbuf,"cacheimages")) { - if (!strcmp(cp,"True")) want_config[CONFIG_CACHE]=TRUE; - else want_config[CONFIG_CACHE]=FALSE; + if (!strcmp(cp,"True")) + want_config[CONFIG_CACHE]=TRUE; + else + want_config[CONFIG_CACHE]=FALSE; continue; } if (!strcmp(inbuf,"split")) { - if (!strcmp(cp,"True")) want_config[CONFIG_SPLITWIN]=TRUE; - else want_config[CONFIG_SPLITWIN]=FALSE; + if (!strcmp(cp,"True")) + want_config[CONFIG_SPLITWIN]=TRUE; + else + want_config[CONFIG_SPLITWIN]=FALSE; continue; } if (!strcmp(inbuf,"showicon")) { - if (!strcmp(cp,"True")) inv_list.show_icon=TRUE; - else inv_list.show_icon=FALSE; + if (!strcmp(cp,"True")) + inv_list.show_icon=TRUE; + else + inv_list.show_icon=FALSE; + continue; + } + if (!strcmp(inbuf,"showicon.look")) { + if (!strcmp(cp,"True")) + look_list.show_icon=TRUE; + else + look_list.show_icon=FALSE; + continue; + } + if (!strcmp(inbuf,"showweight")) { + if (!strcmp(cp,"True")) + inv_list.show_weight=TRUE; + else + inv_list.show_weight=FALSE; + continue; + } + if (!strcmp(inbuf,"showweight.look")) { + if (!strcmp(cp,"True")) + look_list.show_weight=TRUE; + else + look_list.show_weight=FALSE; continue; } if (!strcmp(inbuf,"scrolllines")) { - infodata.maxlines = atoi(cp); + info.lines = atoi(cp); continue; } if (!strcmp(inbuf,"scrollinfo")) { - if (!strcmp(cp,"True")) infodata.scroll_info_window=TRUE; - else infodata.scroll_info_window=FALSE; + /* silently ignored */ continue; } if (!strcmp(inbuf,"sound")) { - if (!strcmp(cp,"True")) want_config[CONFIG_SOUND]=TRUE; - else want_config[CONFIG_SOUND]=FALSE; + if (!strcmp(cp,"True")) + want_config[CONFIG_SOUND]=TRUE; + else + want_config[CONFIG_SOUND]=FALSE; continue; } if (!strcmp(inbuf,"command_window")) { @@ -3445,19 +3207,31 @@ void load_defaults() continue; } if (!strcmp(inbuf,"foodbeep")) { - if (!strcmp(cp,"True")) use_config[CONFIG_FOODBEEP]=TRUE; - else use_config[CONFIG_FOODBEEP]=FALSE; + if (!strcmp(cp,"True")) + use_config[CONFIG_FOODBEEP]=TRUE; + else + use_config[CONFIG_FOODBEEP]=FALSE; continue; } if (!strcmp(inbuf,"noautorepeat")) { - if (!strcmp(cp,"True")) noautorepeat=TRUE; - else noautorepeat=FALSE; + if (!strcmp(cp,"True")) + noautorepeat=TRUE; + else + noautorepeat=FALSE; continue; } if (!strcmp(inbuf,"font")) { font_name = strdup_local(cp); continue; } + if (!strcmp(inbuf,"mapsize")) { + int w,h; + if (sscanf(cp, "%dx%d", &w, &h) == 2) { + want_config[CONFIG_MAPWIDTH] = w; + want_config[CONFIG_MAPHEIGHT] = h; + } + continue; + } fprintf(stderr,"Got line we did not understand: %s: %s\n", inbuf, cp); } fclose(fp); @@ -3485,11 +3259,15 @@ void save_defaults() fprintf(fp,"port: %d\n", use_config[CONFIG_PORT]); fprintf(fp,"server: %s\n", server); fprintf(fp,"font: %s\n", font_name); + fprintf(fp,"mapsize: %dx%d\n", want_config[CONFIG_MAPWIDTH], + want_config[CONFIG_MAPHEIGHT]); fprintf(fp,"cacheimages: %s\n", want_config[CONFIG_CACHE]?"True":"False"); fprintf(fp,"split: %s\n", want_config[CONFIG_SPLITWIN]?"True":"False"); fprintf(fp,"showicon: %s\n", inv_list.show_icon?"True":"False"); - fprintf(fp,"scrolllines: %d\n", infodata.maxlines); - fprintf(fp,"scrollinfo: %s\n", infodata.scroll_info_window?"True":"False"); + fprintf(fp,"showicon.look: %s\n", look_list.show_icon?"True":"False"); + fprintf(fp,"showweight: %s\n", inv_list.show_weight?"True":"False"); + fprintf(fp,"showweight.look: %s\n", look_list.show_weight?"True":"False"); + fprintf(fp,"scrolllines: %d\n", info.lines); fprintf(fp,"sound: %s\n", want_config[CONFIG_SOUND]?"True":"False"); fprintf(fp,"command_window: %d\n", use_config[CONFIG_CWINDOW]); fprintf(fp,"foodbeep: %s\n", use_config[CONFIG_FOODBEEP]?"True":"False"); @@ -3510,8 +3288,9 @@ void save_defaults() void command_show (const char *params) { - if(!params) { - if (inv_list.show_what==show_all) inv_list.show_what = show_applied; + if (!params) { + if (inv_list.show_what==show_all) + inv_list.show_what = show_applied; else { /* rotate the bit. If no valid bits are set, start over */ inv_list.show_what = inv_list.show_what << 1; if (!(inv_list.show_what & show_mask)) @@ -3552,26 +3331,26 @@ void command_show (const char *params) int main(int argc, char *argv[]) { int sound,got_one=0; - int i; -#ifdef HAS_COMMON_RCSID - INIT_COMMON_RCSID; -#endif -#ifdef HAS_X11_RCSID - INIT_X11_RCSID; -#endif /* * output some version informations on LOG. * usefull when reporting a bug. */ - #ifdef HAS_COMMON_RCSID - for (i=0;common_rcsid[i];i++) - LOG(LOG_INFO,"Version::common","%s",common_rcsid[i]); + { + INIT_COMMON_RCSID; + int i; + for (i=0;common_rcsid[i];i++) + LOG(LOG_INFO,"Version::common","%s",common_rcsid[i]); + } #endif #ifdef HAS_X11_RCSID - for (i=0;x11_rcsid[i];i++) - LOG(LOG_INFO,"Version::x11 ","%s",x11_rcsid[i]); + { + INIT_X11_RCSID; + int i; + for (i=0;x11_rcsid[i];i++) + LOG(LOG_INFO,"Version::x11 ","%s",x11_rcsid[i]); + } #endif /* This needs to be done first. In addition to being quite quick, @@ -3592,13 +3371,7 @@ int main(int argc, char *argv[]) fprintf(stderr,"Failure to init windows.\n"); exit(1); } - csocket.inbuf.buf=malloc(MAXSOCKBUF); - -#ifdef HAVE_SYSCONF - maxfd = sysconf(_SC_OPEN_MAX); -#else - maxfd = getdtablesize(); -#endif + csocket.inbuf.buf = xmalloc(MAXSOCKBUF); sound = init_sounds(); From mikeeusaa at yahoo.com Sun Mar 12 18:43:11 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Sun, 12 Mar 2006 16:43:11 -0800 (PST) Subject: [crossfire] first bug discovered by unit test In-Reply-To: <441457C4.9090701@myrealbox.com> Message-ID: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> Yay. There should be added some security unit tests aswell. --- tchize wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > While am still preparing check framework for > crossfire, i found a bug > in common/shstr.c where query_refcount was returning > wrong value. > Fixed and commited. I hope unit testing will > discover more of those > still undetected bugs :) > > Tchize > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.1 (GNU/Linux) > Comment: Using GnuPG with Thunderbird - > http://enigmail.mozdev.org > > iD8DBQFEFFfEHHGOa1Q2wXwRAh24AKCAnbCQIhV7s8lHc/rWQWsiQ05DpwCg8a+l > j9lkYAgdM+qrmtGnFsNUsVM= > =/d7V > -----END PGP SIGNATURE----- > > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From mwedel at sonic.net Sun Mar 12 20:25:17 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 12 Mar 2006 18:25:17 -0800 Subject: [crossfire] map2 & animations Message-ID: <4414D80D.8090501@sonic.net> I've started work on the map2 command - preliminary documentation on that has been in the Protocol file for a while, but I have made a few minor changes. However, I was looking/thinking about letting the client handle the map animations. From a protocol perspective, this isn't really hard - we just need to send down some extra information. My initial thought here is to just set the high bit on what is normally the face num field to denote this is an animation (this limits us to 32767 faces, but I'm not that worried about that). Also, to make things work better, I was thinking a couple extra bytes are needed - 1 for the animation speed, and one for the current animation position (where we are in the sequence). The later may or may not be important depending on how we deal with things. My thought is that for things like monsters, if we animate them, we want to send that - otherwise all the monsters are in a lock step formation. However, as I think about it, there are really 4 cases for animations we care about: 1) Animations that should be lock step. Point in case would be the ocean spaces - it would look better if they were all in phase - right now, you can see the edges of the tiled maps because the phase between the two maps is different. 2) Cases where it should be randomized. Monsters come to mind in the case - the phase of animation for things like goblins isn't important, and it does look better if they are in different phases. Randomizing this on the client works better than sending current phase because of timing. Think creatures that have a speed of 0.20. Once every 5 ticks, they move and their animation change. If we only send current phase, that means the client will have all of them on 'phase 2' go to phase 3 at the same time, and then all of them don't change for the next 4 ticks. If the client randomizes this on its own, then 20% will change animation each tick. 3) Animations in which phase is important (or temporary). Example here would be things like gates/spikes. In this case, the client really needs to know what phase the gate is in when it shows up - it can't lockstep it or randomize it. In addition, timing here is important - if the server spends a second loading a map, the client has to be aware that those gates haven't done anything for a second. This isn't that hard to solve by adding something like a 'S-C> hearbeat' protocol command which the server sends each tick it processes. But here, we still get a timing case - suppose those gates move at speed 0.2. Just telling the client that it is on phase 2 really isn't enough - the gate could go to phase 3 the next tick, or to that phase 5 ticks from now. So to handle this, not only do we need to send the phase, but also how soon until the next phase. My personal thought is this: Add new flag(s) which says how to handle animations. My personal thought is leaving case #3 as a server side is probably the easiest (server side being that we don't send animation to clients, just send face for the space like we do now). This doesn't get us as much of a bandwidth savings as possible, but does keep things simpler - at some level, its a balance of how much complication do we add to save some bandwidth. So I'd suggest addition of two new flags - one to handle case 1 (FLAG_CLIENT_ANIMATE_SYNCHRONIZE) and case 2 (FLAG_CLIENT_ANIMATE_RANDOMIZE). These flags would be used to tell the server that we should like the client handle the animation (hence the CLIENT part) as well as to tell the client how it should handle the animation. My thought is the top bits could be used to convey this. So something like: : If set, this isn't a face, but animation id: : Convey animation type. Right now, there are only 2, but it is good to leave a little room for expansion (I could perhaps seeing something like a FLAG_CLIENT_ANIMATE_ONCE for things like burnouts to denote that that once the animation gets to the last step, it should stop animating and not cycle) This leaves 13 bits for animation id, which is 8191 animations. Given we only have 989 right now (and that could actually be brought down by merging some of the multipart images to big images), I'd think that should be plenty. Thoughts/comments? From lalo.martins at gmail.com Sun Mar 12 21:02:18 2006 From: lalo.martins at gmail.com (Lalo Martins) Date: Mon, 13 Mar 2006 11:02:18 +0800 Subject: [crossfire] map2 & animations In-Reply-To: <4414D80D.8090501@sonic.net> References: <4414D80D.8090501@sonic.net> Message-ID: And so says Mark Wedel on 13/03/06 10:25... > However, I was looking/thinking about letting the client handle the map > animations. Not knowing much about the protocol, the only comment I can contribute to this topic is: YES PLEASE! :-D Server admins and players with bandwidth limitation both appreciate it. best, Lalo Martins -- So many of our dreams at first seem impossible, then they seem improbable, and then, when we summon the will, they soon become inevitable. -- personal: http://www.laranja.org/ technical: http://lalo.revisioncontrol.net/ GNU: never give up freedom http://www.gnu.org/ From alex_sch at telus.net Sun Mar 12 23:20:57 2006 From: alex_sch at telus.net (Alex Schultz) Date: Sun, 12 Mar 2006 22:20:57 -0700 Subject: [crossfire] first bug discovered by unit test In-Reply-To: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> References: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> Message-ID: <44150139.90401@telus.net> That would be more functional testing than unit testing, however both are planned in the framework. security functional testing may be a good idea to include some of. Perhaps some thing like attempted buffer overflows over the protocol, or verifying that the password code isn't making any silly mistakes at any time in the future. That said, I'm not sure exactly what could be done for these sorts of tests, as not every circumstance could be tested, so the difficulty is planning what things are most important to test in order to catch potential future or current flaws in security. Miguel Ghobangieno wrote: >Yay. There should be added some security unit tests >aswell. > From mwedel at sonic.net Mon Mar 13 00:35:08 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 12 Mar 2006 22:35:08 -0800 Subject: [crossfire] mapcmd bye bye. Message-ID: <4415129C.1080306@sonic.net> Anyone have any issues for removing the original mapcmd protocol command? the map1/map1a commands will remain. Client version 1.1.0 introduced support for the Map1 command. So I can't really see it breaking anything. Due to changes needed for the map2 command, this will require some amount of updating for the map1 command. I just can't see much reason why the mapcmd is needed anymore, but thought I'd throw the question out there in case someone is aware of some issue. Probably the way to handle this is for the server to check after negotiation that at least the client has negotiated at least to the map1 command, and if not, print out an error and close the connection (error message along hte lines like your client is too old, update). The one issue where this could perhaps be an issue for any bots out there that just ignore the map data, and thus don't bother to negotiate a map version in the setup parameters. So maybe this message should be considered more a heads up to those people with bots to make sure it is at least negotiating a map1 protocol level? From tchize at myrealbox.com Mon Mar 13 02:28:50 2006 From: tchize at myrealbox.com (Tchize) Date: Mon, 13 Mar 2006 09:28:50 +0100 Subject: [crossfire] first bug discovered by unit test In-Reply-To: <44150139.90401@telus.net> References: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> <44150139.90401@telus.net> Message-ID: <44152D42.1010302@myrealbox.com> In fact buffer overflow will probably be reduced by unit testing because of unexpeted behaviour of some functions when called with long parameters. Alex Schultz a ?crit : >That would be more functional testing than unit testing, however both >are planned in the framework. security functional testing may be a good >idea to include some of. Perhaps some thing like attempted buffer >overflows over the protocol, or verifying that the password code isn't >making any silly mistakes at any time in the future. >That said, I'm not sure exactly what could be done for these sorts of >tests, as not every circumstance could be tested, so the difficulty is >planning what things are most important to test in order to catch >potential future or current flaws in security. > >Miguel Ghobangieno wrote: > > > >>Yay. There should be added some security unit tests >>aswell. >> >> >> > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From tchize at myrealbox.com Mon Mar 13 04:45:59 2006 From: tchize at myrealbox.com (Tchize) Date: Mon, 13 Mar 2006 11:45:59 +0100 Subject: [crossfire] map2 & animations In-Reply-To: <4414D80D.8090501@sonic.net> References: <4414D80D.8090501@sonic.net> Message-ID: <44154D67.7030800@myrealbox.com> Mark Wedel a ?crit : quick comment on one point. I agree on principle but about 3: The principle of leaving this case server side is ok, but maybe another suggestion is send it has a phased animation which doesn't repeat. Of course you can get a gap between server state and client state. I think it's not a real problem if we consider the 'phase' of an animation not based on current_face but based on time (like the animation is at phase 2,53 sec after startup), this is coherent with the idea to send the speed of an animation in terms time between changes. (like animation has 0.80 sec between changes). You could then resync any gap that may happen between client and server by 'replacing' anim by a picture when anim has ended. The point on 'server stops for 1 seconds' is a false problem, as the server after the 1 sec map loading freeze, will give lots of ticks at a time to the animated object. btw, it would be a good thing to store the phase as a float in maps too. Currently, if you desync lots of background on a map and the map get cached, at reload, all items do change phase at the same time (because it's current face which drive anim state at maploading) > >3) Animations in which phase is important (or temporary). Example here would be >things like gates/spikes. In this case, the client really needs to know what >phase the gate is in when it shows up - it can't lockstep it or randomize it. >In addition, timing here is important - if the server spends a second loading a >map, the client has to be aware that those gates haven't done anything for a >second. This isn't that hard to solve by adding something like a 'S-C> >hearbeat' protocol command which the server sends each tick it processes. > > But here, we still get a timing case - suppose those gates move at speed 0.2. > Just telling the client that it is on phase 2 really isn't enough - the gate >could go to phase 3 the next tick, or to that phase 5 ticks from now. So to >handle this, not only do we need to send the phase, but also how soon until the >next phase. > > My personal thought is this: >Add new flag(s) which says how to handle animations. My personal thought is >leaving case #3 as a server side is probably the easiest (server side being that >we don't send animation to clients, just send face for the space like we do >now). This doesn't get us as much of a bandwidth savings as possible, but does >keep things simpler - at some level, its a balance of how much complication do >we add to save some bandwidth. > > > From brenlally at gmail.com Mon Mar 13 16:47:21 2006 From: brenlally at gmail.com (Brendan Lally) Date: Mon, 13 Mar 2006 22:47:21 +0000 Subject: [crossfire] map2 & animations In-Reply-To: <4414D80D.8090501@sonic.net> References: <4414D80D.8090501@sonic.net> Message-ID: <7903f03c0603131447o73783ee7k5d9c8ab1a043be51@mail.gmail.com> On 3/13/06, Mark Wedel wrote: > > I've started work on the map2 command - preliminary documentation on that has > been in the Protocol file for a while, but I have made a few minor changes. > > My personal thought is this: > Add new flag(s) which says how to handle animations. My personal thought is > leaving case #3 as a server side is probably the easiest (server side being that > we don't send animation to clients, just send face for the space like we do > now). This doesn't get us as much of a bandwidth savings as possible, but does > keep things simpler - at some level, its a balance of how much complication do > we add to save some bandwidth. > > Thoughts/comments? One thing you haven't mentioned, so I'll do so now, is merging in map_scroll and newmap packets. Having these as two seperate packets would be fairly ugly if clients are handling animations. If static items are not sending map packets every tick, then a far greater proportion of map packets will be for scrolling or new maps. This would therefore suggest that a better approach would be to have 1 byte at the start of the map2 packet to act as a control byte, something like CDDDNSEW where C corresponds to the newmap packet, and tells the client to clear the fog of war data. D is the distance to scroll in any direction, (from 0 to 7 squares) NSEW are north, south, east, west, the bit being 1 if the map is scrolling in that direction. so, on entering a new map, 0x80 would be sent. on scrolling one square to the north west, 0x19 would be sent, etc. From mwedel at sonic.net Tue Mar 14 02:03:57 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 14 Mar 2006 00:03:57 -0800 Subject: [crossfire] map2 & animations In-Reply-To: <44154D67.7030800@myrealbox.com> References: <4414D80D.8090501@sonic.net> <44154D67.7030800@myrealbox.com> Message-ID: <441678ED.8050603@sonic.net> Tchize wrote: > Mark Wedel a ?crit : > quick comment on one point. I agree on principle but about 3: > > The principle of leaving this case server side is ok, but maybe another > suggestion is > send it has a phased animation which doesn't repeat. Of course you can > get a gap between server state and client state. I think it's not a real > problem if we consider the 'phase' of an animation not based on > current_face but based on time (like the animation is at phase 2,53 sec > after startup), this is coherent with the idea to send the speed of an > animation in terms time between changes. (like animation has 0.80 sec > between changes). You could then resync any gap that may happen between > client and server by 'replacing' anim by a picture when anim has ended. True - any of the problems I mention can be overcome with enough work. The question starts to come in is it really worth the work and complexity. If we get a case where we are saving 30 bytes/second but at the cost of a couple hundred lines of code in the server and client, is it worth it? My personal thought is no. Some of this goes back to the idea of code testing and cleanliness - one thing that helps out in all regards is less code (fewer test cases, less lines of code where something could go wrong, etc). So there is some balance between all these considerations. And at some point, it could be considered more valuable to work on some other piece of code rather that has more important and perfect some other piece of code. Now for the non repeating animations, my thought it would transpire like this: S->C: there is a burnout at 5,5, and it doesn't repeat. It is at phase 2. Client: On its own, it goes and does the animations. When it gets to the last phase and time to move to the next, it just stops, continuing to draw the last phase as a static image. S->C: there is no longer a burnout image/animation at 5,5 - delete it Client: goes and deletes it. So in this case, if the timing isn't perfect, not a terrible thing - the map will continue to show the puff of smoke. If we are only off a couple ticks, probably not very noticable. > > The point on 'server stops for 1 seconds' is a false problem, as the > server after the 1 sec map loading freeze, will give lots of ticks at a > time to the animated object. I'm actually not sure that is the case. If there is a network hiccup, that is certainly the case - the server has done all the work and sent the data, and you get it in a burst. I'd have to look, but I don't think there is any catchup mechanism for when the server does something costly. So in the case of a 1 second map load, that is basically 8 ticks. I'd say that not catching up is the right thing here. Otherwise, you could get the situation where you are fighting some monster, some costly map load happens, and the monster gets 8 ticks of action in the blink of an eye - too fast for a player to react with things like healing, running away, etc. > > btw, it would be a good thing to store the phase as a float in maps too. > Currently, if you desync lots of background on a map and the map get > cached, at reload, all items do change phase at the same time (because > it's current face which drive anim state at maploading) Fair point, but perhaps less and issue. As I think about this, having the client handle some animations in fact greatly frees up the server. Think in the case of ocean animations. Right now, every so many ticks, the server goes and processes all those ocean objects - changing the animation, and then calling update_position to change the map view approriately. If these animations are moved to the client, these objects can now become static on the server - the server tells the client to animate them, but the server doesn't have to do anything more like animate them itself. Some rework would be needed, as right now, objects are only animated if the object has speed (thus, held goblin will stop being animated). There would probably need to be some flag to denote that yes, animate this object, even though it has no speed. but FLAG_CLIENT_ANIMATE_SYNCHRONIZE could perhaps infer that, but perhaps another flag is still needed - I could see other terrain which you want animated with FLAG_CLIENT_ANIMATE_RANDOMIZE. From mwedel at sonic.net Tue Mar 14 02:18:30 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 14 Mar 2006 00:18:30 -0800 Subject: [crossfire] map2 & animations In-Reply-To: <7903f03c0603131447o73783ee7k5d9c8ab1a043be51@mail.gmail.com> References: <4414D80D.8090501@sonic.net> <7903f03c0603131447o73783ee7k5d9c8ab1a043be51@mail.gmail.com> Message-ID: <44167C56.7090400@sonic.net> Brendan Lally wrote: > This would therefore suggest that a better approach would be to have 1 > byte at the start of the map2 packet to act as a control byte, > something like > > CDDDNSEW > > where C corresponds to the newmap packet, and tells the client to > clear the fog of war data. > > D is the distance to scroll in any direction, (from 0 to 7 squares) > > NSEW are north, south, east, west, the bit being 1 if the map is > scrolling in that direction. > > so, on entering a new map, 0x80 would be sent. > > on scrolling one square to the north west, 0x19 would be sent, etc. That's a good idea - I'd probably do it a little different - rather than including the direction to scroll, I'd just do offsets. As things stand now, I have the coordinates for each space defined as 6 bits (0-63) with 4 bits in reserve. objects can be in position from 0 to 33 (33 is the head of a big object with an 8 space offset). I'm thinking that some form of negative coordinates is needed, so that perhaps the range goes from -20 to 43. The reason I think negative coordinates are needed is if/when we send the location of light sources to the client - if you have a light source at -1, 10 that is bright, that light is having some effect on the map spaces that is visible to the client, so we need to be able to convey the fact that there is a light source at -1,10. Where all this is leading is here - of those 4 reserved bits, we could hijack a couple for the purpose you describe. If 1 bit is set, take this not as the coordinate of a space, but rather the offset to scroll the map. OTOH, it could just be easier to say something like 'the first 2 bytes of the map2 packet are special - they describe scrolling or newmap behaviour'. The only problem here is that if there is not a newmap or scroll, we just wasted 2 bytes. Or for that matter, we could just 'hold' the newmap and scroll commands until we are ready to send a new map to the client. For newmap, it probably doesn't happen all that often, so keeping it as its own command is reasonable. Scrolls do happen fairly often, so perhaps more to gain putting that in with the map2 command. From mwedel at sonic.net Tue Mar 14 02:20:11 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 14 Mar 2006 00:20:11 -0800 Subject: [crossfire] first bug discovered by unit test In-Reply-To: <44152D42.1010302@myrealbox.com> References: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> <44150139.90401@telus.net> <44152D42.1010302@myrealbox.com> Message-ID: <44167CBB.1060300@sonic.net> Random question - is there any framework in place for external functional tests? I ask because to reproduce and confirm I fixed the setup buffer overflow bug, I do have an external perl script which would be nice to toss somewhere. From tchize at myrealbox.com Tue Mar 14 03:26:41 2006 From: tchize at myrealbox.com (Tchize) Date: Tue, 14 Mar 2006 10:26:41 +0100 Subject: [crossfire] first bug discovered by unit test In-Reply-To: <44167CBB.1060300@sonic.net> References: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> <44150139.90401@telus.net> <44152D42.1010302@myrealbox.com> <44167CBB.1060300@sonic.net> Message-ID: <44168C51.6060301@myrealbox.com> Mark Wedel a ?crit : > Random question - is there any framework in place for external functional tests? > > > no > I ask because to reproduce and confirm I fixed the setup buffer overflow bug, >I do have an external perl script which would be nice to toss somewhere. > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From alex_sch at telus.net Tue Mar 14 07:44:57 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 14 Mar 2006 06:44:57 -0700 Subject: [crossfire] first bug discovered by unit test In-Reply-To: <44168C51.6060301@myrealbox.com> References: <20060313004311.46869.qmail@web32701.mail.mud.yahoo.com> <44150139.90401@telus.net> <44152D42.1010302@myrealbox.com> <44167CBB.1060300@sonic.net> <44168C51.6060301@myrealbox.com> Message-ID: <4416C8D9.2030502@telus.net> This reminds me of one idea that I had for the functional tests. Since some tests would require some sort of client to connect, I was thinking about doing this: Fixing up the python client libs that I had a start on. In a functional test map that wants a 'player', make a script that uses crossfire's python plugin to load, and then split off into a separate thread so it doesn't block the server from running, and start a client using the python libs. This setup would allow tests that need a 'client' to get one with minimal effort, and only modifying the resource files. It also might be possible/better to instead of loading via a map, have the test framework directly start the python. Alex Schultz Tchize wrote: >Mark Wedel a ?crit : > > >> Random question - is there any framework in place for external functional tests? >> >no > > >> I ask because to reproduce and confirm I fixed the setup buffer overflow bug, >>I do have an external perl script which would be nice to toss somewhere. >> From nicolas.weeger at laposte.net Sat Mar 18 09:09:59 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Sat, 18 Mar 2006 16:09:59 +0100 Subject: [crossfire] Code cleanup In-Reply-To: <4407743E.4030400@laposte.net> References: <4407743E.4030400@laposte.net> Message-ID: <441C22C7.8060009@laposte.net> Hello. As promised I just cleaned a massive amount of code. I admit, there *are* things still in CamelCase. I just became lazy at the end :) I renamed functions, as to have some coherence - "command" functions (sent from client) now end with _cmd, thinks like that. I do think I didn't break anything. Nicolas From nicolas.weeger at laposte.net Sat Mar 18 10:39:07 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Sat, 18 Mar 2006 17:39:07 +0100 Subject: [crossfire] Player-owner shop proof of concept Message-ID: <441C37AB.3070903@laposte.net> Hello. I just made a small proof-of-concept of player-owned shop, attached to that mail. Just a map and 2 Python scripts. Basically: mark an item, go to the table, say "sell ", then drop the item anywhere. To buy, it behaves exactly like a regular shop (well, right now, if you don't have enough money to exit, you'll stay on the mat, but apart that it's ok...). Only use top mat to buy, as I didn't hook the script to the bottom one. Note that you can sell for any price, but when bought the price is reset to real price - don't ask me why I did that, I guess I don't want prices too strange. Things I'm thinking to improve: * concept of shop owner * put paid money in a pile owner only can pick (obvious) * regular fee for shop to be opened (equivalent to paying an employee to run the shop?) Not putting it on tracker, as I want comments and will improve/change in the next days/weeks at most (so it won't be lost :p) Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: player_shop.tar.gz Type: application/gzip Size: 1360 bytes Desc: not available Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060318/e919fe39/attachment.bin From elmex at ta-sa.org Sat Mar 18 13:33:11 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Sat, 18 Mar 2006 20:33:11 +0100 Subject: [crossfire] Player-owner shop proof of concept In-Reply-To: <441C37AB.3070903@laposte.net> References: <441C37AB.3070903@laposte.net> Message-ID: <20060318193311.GA4705@elmex> On Sat, Mar 18, 2006 at 05:39:07PM +0100, Nicolas Weeger wrote: > Hello. > > I just made a small proof-of-concept of player-owned shop, attached to > that mail. Just a map and 2 Python scripts. > > Basically: mark an item, go to the table, say "sell coins>", then drop the item anywhere. > Hi! I also played around with the idea of player owned shops. It's great others are also thinking about it! But i'm afraid what happens when high lvl players sell quest items for very few platinums, and so soon many low level players maybe run around with those stuff... Or high level players sell stat potions very cheap so low level players have full stats very soon. I don't know if this is okay or whether it maybe breaks the balancing a bit. I would not sell items for too few platinum, but i dont think all players who maybe own a shop do care about balancing or spoiling others players fun. Maybe items should have a minimal sell price that depends the item value. Or maybe it is enough to deny selling items for too low pp by server policy... but i doubt that. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From nicolas.weeger at laposte.net Sat Mar 18 13:40:09 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Sat, 18 Mar 2006 20:40:09 +0100 Subject: [crossfire] Player-owner shop proof of concept In-Reply-To: <20060318193311.GA4705@elmex> References: <441C37AB.3070903@laposte.net> <20060318193311.GA4705@elmex> Message-ID: <441C6219.8070608@laposte.net> > But i'm afraid what happens when high lvl players sell quest items > for very few platinums, and so soon many low level players maybe run > around with those stuff... Or high level players sell stat potions > very cheap so low level players have full stats very soon. Well, right now you can simply give a weapon to a player, so it's not that different :) Also, don't forget there is the item level, which should prevent low level players from using too powerful equipment. Nicolas From cerzeo at gmail.com Sun Mar 19 05:27:06 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Sun, 19 Mar 2006 12:27:06 +0100 Subject: [crossfire] [Re]Player Owned Shops Message-ID: <3fa509450603190327k55dc96c0y@mail.gmail.com> I think this is a good idea. The problem of hihg leveled items to be sold at low plat, can be solved relatively easy: I dont know how the source code does this, but the idea is this: all items have a value (or variable, i supose) that store the selling prize in normal shops. So, you can set the minimun selling prize for player's shops at 1/3 less than normal shops. A sample of this could be: We have a Bonecrusher, and we can sell it for 300 platinum at a normal shop in Scorn, then, the minimun prize of Bonecrusher in our shop will be: 3000 - 3000 * 1/3 = 2000. So, the formulae can be [ Real_Prize - Real_Prize * 1/3 ]. I have write 1/3, but it can be more or less, it was just a sample. -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060319/3aac94f8/attachment.htm From tchize at myrealbox.com Sun Mar 19 06:39:12 2006 From: tchize at myrealbox.com (tchize) Date: Sun, 19 Mar 2006 13:39:12 +0100 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <3fa509450603190327k55dc96c0y@mail.gmail.com> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> Message-ID: <441D50F0.8070809@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Price in real shops depends on charisma of buyer and a shop expensiveness factor set in shop maps. I suppose in player owned shop, you don't want a price to change depending on charisma, and so you can't check a minimum value easily. Alberto S?ez Lodeiros a ?crit : > I think this is a good idea. > > The problem of hihg leveled items to be sold at low plat, can be > solved relatively easy: I dont know how the source code does this, > but the idea is this: all items have a value (or variable, i > supose) that store the selling prize in normal shops. So, you can > set the minimun selling prize for player's shops at 1/3 less than > normal shops. A sample of this could be: We have a Bonecrusher, and > we can sell it for 300 platinum at a normal shop in Scorn, then, > the minimun prize of Bonecrusher in our shop will be: 3000 - 3000 * > 1/3 = 2000. So, the formulae can be [ Real_Prize - Real_Prize * 1/3 > ]. > > I have write 1/3, but it can be more or less, it was just a sample. > > > -- Powered By SuSE Linux 10.0 > > > ---------------------------------------------------------------------- > > > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEHVDwHHGOa1Q2wXwRAqs3AJ9QQUoKiUb2pdaYYweb/lvTCM4y2QCgiImO cFImYXHLgN2sF+b0RcSv8yA= =WzB9 -----END PGP SIGNATURE----- From mikeeusaa at yahoo.com Sat Mar 18 20:31:15 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Sat, 18 Mar 2006 18:31:15 -0800 (PST) Subject: [crossfire] Player-owner shop proof of concept In-Reply-To: <441C6219.8070608@laposte.net> Message-ID: <20060319023115.2451.qmail@web32706.mail.mud.yahoo.com> Player-owned, shortened form P-owned :) I think you should beable to set the buying price if you own the shop. --- Nicolas Weeger wrote: > > But i'm afraid what happens when high lvl players > sell quest items > > for very few platinums, and so soon many low level > players maybe run > > around with those stuff... Or high level players > sell stat potions > > very cheap so low level players have full stats > very soon. > > Well, right now you can simply give a weapon to a > player, so it's not > that different :) > Also, don't forget there is the item level, which > should prevent low > level players from using too powerful equipment. > > Nicolas > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From elmex at ta-sa.org Sun Mar 19 21:36:14 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Mon, 20 Mar 2006 04:36:14 +0100 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <441D50F0.8070809@myrealbox.com> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> Message-ID: <20060320033614.GA6767@elmex> On Sun, Mar 19, 2006 at 01:39:12PM +0100, tchize wrote: > Price in real shops depends on charisma of buyer and a shop > expensiveness factor set in shop maps. I suppose in player owned shop, > you don't want a price to change depending on charisma, and so you > can't check a minimum value easily. > I also wondered about that... Propably it's best if dungeon masters just keep an eye on that - if it's a policy of the server not to sell items for nothing... but as Nicolas said: today people can and do give away stuff for free... or some random price... Another idea that comes up in context of player shops: With player owned shops skills like jewelery, smithery and all make much more sense (selling other people your products). The problem is imho just, that jewelery for example isn't attractive enought. A simple ring of halvor requires level around 10 and a ring of free action requires around level 15 and ring of combat level 20. But when i'm level 10, 15 or 20 at jewelery i always have already found quite many of those rings... IMHO it's too difficult or too much hassle to make those. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From mwedel at sonic.net Sun Mar 19 22:12:58 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 19 Mar 2006 20:12:58 -0800 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <20060320033614.GA6767@elmex> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> Message-ID: <441E2BCA.6040904@sonic.net> Could a little more detail on this process be given? Looking over the patch to see how it works leaves me with a few questions. It seems to me that the patch in question lets the owner set whatever price, but doesn't actually pay the player who sold it anything? Is the correct? If so, it then seems like something is missing. Unless the idea is to somehow tie it some field in the map itself (store room with all the money in it)? But this does lead me to an interesting idea - consignment shop. Players go in and say how much they want to sell stuff for, just like the sample code provided. However, as part of that, we also record the player selling the item. Then if anyone does buy it, the player gets the money (I seem to recall that at some point, sending objects via the post office system was possible. However, another idea is to make a moneygram object - basically, just like a normal letter, but something like 'take this to any store to redeem for coins', and the code just sets the value for the moneygram (it should also perhaps be of type gem so charisma doesn't affect the price you get for it). The shop should of course take a percentage off the top for the transaction. Also, perhaps record when the object was sold, and objects that have been around too long get sent back to the player. This has the interesting effect that the player trying to sell the objects doesn't get anything until they are actually sold. So he has incentive to set a reasonable price. Also, because of that, less reason to put them in the shop vs taking the immediate price selling in a shop unless you are really getting shafted on prices - thus, not likely to see people selling junk. From nicolas.weeger at laposte.net Mon Mar 20 15:24:36 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Mon, 20 Mar 2006 22:24:36 +0100 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <20060320033614.GA6767@elmex> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> Message-ID: <441F1D94.1090901@laposte.net> > A simple ring of halvor requires level around 10 and a ring of free > action requires around level 15 and ring of combat level 20. > But when i'm level 10, 15 or 20 at jewelery i always have already found > quite many of those rings... IMHO it's too difficult or too much hassle > to make those. Don't forget the ingredients. Must (all?) are really rare, thus it's easier to buy a potion. Nicolas From nicolas.weeger at laposte.net Mon Mar 20 15:29:15 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Mon, 20 Mar 2006 22:29:15 +0100 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <441E2BCA.6040904@sonic.net> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> <441E2BCA.6040904@sonic.net> Message-ID: <441F1EAB.7020707@laposte.net> > Could a little more detail on this process be given? Looking over the patch > to see how it works leaves me with a few questions. Yeah, it's a pretty basic patch for now :) > It seems to me that the patch in question lets the owner set whatever price, > but doesn't actually pay the player who sold it anything? Is the correct? If > so, it then seems like something is missing. Unless the idea is to somehow tie > it some field in the map itself (store room with all the money in it)? Correct for price & no money. I need to tweak the "buy.py" script to transfer money to some place in the shop - thus money gets piled up, and owner will grab it simply. Remember the idea is to have only one player own the shop - thus it's easy to have an "owner" room where money is stored. > But this does lead me to an interesting idea - consignment shop. Players go > in and say how much they want to sell stuff for, just like the sample code > provided. However, as part of that, we also record the player selling the item. > Then if anyone does buy it, the player gets the money (I seem to recall that > at some point, sending objects via the post office system was possible. You can still send items through post office (unless it was broken, but i don't think so) > The shop should of course take a percentage off the top for the transaction. > Also, perhaps record when the object was sold, and objects that have been around > too long get sent back to the player. My idea is to have a fee you'd need to pay regularly to maintain the shop. Think of renting the space :) But of course you can stack the percentage. The think I have yet to decide is how to handle that fee - I think best way is to hook to the global time event, and trace stores' status, then claim money from player when shop has "negative" fees. > This has the interesting effect that the player trying to sell the objects > doesn't get anything until they are actually sold. So he has incentive to set a > reasonable price. Also, because of that, less reason to put them in the shop vs > taking the immediate price selling in a shop unless you are really getting > shafted on prices - thus, not likely to see people selling junk. At term, we could really have player economy, if we want. On my todo list is also letting a player sell in the shop, and the owner define what to accept & at what price - so globally player owner shops behave exactly like current shop. Nicolas From nicolas.weeger at laposte.net Mon Mar 20 15:31:53 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Mon, 20 Mar 2006 22:31:53 +0100 Subject: [crossfire] SVN? Message-ID: <441F1F49.1040600@laposte.net> Hello. Apparently Sourceforge now has SVN up, and you can import CVS repository directly. See http://sourceforge.net/docman/display_doc.php?docid=31070&group_id=1 for details Maybe we could think of moving Crossfire to SVN? Nicolas From elmex at ta-sa.org Mon Mar 20 19:28:20 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Tue, 21 Mar 2006 02:28:20 +0100 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <441F1D94.1090901@laposte.net> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> <441F1D94.1090901@laposte.net> Message-ID: <20060321012820.GA2944@elmex> On Mon, Mar 20, 2006 at 10:24:36PM +0100, Nicolas Weeger wrote: > > A simple ring of halvor requires level around 10 and a ring of free > > action requires around level 15 and ring of combat level 20. > > But when i'm level 10, 15 or 20 at jewelery i always have already found > > quite many of those rings... IMHO it's too difficult or too much hassle > > to make those. > > Don't forget the ingredients. Must (all?) are really rare, thus it's > easier to buy a potion. > Yes! Thats also what i meant. IMHO at the current state, all cauldron-skills except alchemistry (and alchemistry partially also) are only good for identifying. Maybe it would be enough to make the formulars easier and make it 'harder' in means of randomness to make something. For example: you put in 1 large gold nugget, 2 emeralds (yes, not exceptional emeralds) and only a success rate of 1/10 or something like this... but this is just a random idea. not sure if this is also senseless. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From lalo.martins at gmail.com Mon Mar 20 20:10:26 2006 From: lalo.martins at gmail.com (Lalo Martins) Date: Tue, 21 Mar 2006 10:10:26 +0800 Subject: [crossfire] SVN? In-Reply-To: <441F1F49.1040600@laposte.net> References: <441F1F49.1040600@laposte.net> Message-ID: And so says Nicolas Weeger on 21/03/06 05:31... > > Maybe we could think of moving Crossfire to SVN? -1 SVN has very few advantages over CVS (well, you can move/rename files and dirs, and... hmm... yeah), and a few disadvantages (branching and merging is much, much more usable in CVS). I don't really think it's worth the time to do it and the users' and developers' time to switch; I'm sure there are a few developers who will still have to learn it. If you want to move to bzr, darcs, monotone, git, mercurial, or something like that, then I'm all for it. SVN is a mistake, though. best, Lalo Martins -- So many of our dreams at first seem impossible, then they seem improbable, and then, when we summon the will, they soon become inevitable. -- personal: http://www.laranja.org/ technical: http://lalo.revisioncontrol.net/ GNU: never give up freedom http://www.gnu.org/ From elmex at ta-sa.org Mon Mar 20 23:13:15 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Tue, 21 Mar 2006 06:13:15 +0100 Subject: [crossfire] SVN? In-Reply-To: References: <441F1F49.1040600@laposte.net> Message-ID: <20060321051315.GA3192@elmex> On Tue, Mar 21, 2006 at 10:10:26AM +0800, Lalo Martins wrote: > And so says Nicolas Weeger on 21/03/06 05:31... > > > > Maybe we could think of moving Crossfire to SVN? > > -1 > > SVN has very few advantages over CVS (well, you can move/rename files > and dirs, and... hmm... yeah), and a few disadvantages (branching and -1 too (but i'm no cf devel at sf.net, so don't really count that :) I've had more bad experiences with svn than with cvs all the time before. IMHO svn is still not as stable as cvs. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From alex_sch at telus.net Tue Mar 21 01:03:32 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 21 Mar 2006 00:03:32 -0700 Subject: [crossfire] SVN? In-Reply-To: <441F1F49.1040600@laposte.net> References: <441F1F49.1040600@laposte.net> Message-ID: <441FA544.5020605@telus.net> Nicolas Weeger wrote: >Hello. > >Apparently Sourceforge now has SVN up, and you can import CVS repository >directly. >See http://sourceforge.net/docman/display_doc.php?docid=31070&group_id=1 >for details > >Maybe we could think of moving Crossfire to SVN? > >Nicolas > Under the assumption nothing breaks, I'm indifferent. I don't see it solving much, but I personally do not see the harm in it either. Alex Schultz From tchize at myrealbox.com Tue Mar 21 03:45:01 2006 From: tchize at myrealbox.com (Tchize) Date: Tue, 21 Mar 2006 10:45:01 +0100 Subject: [crossfire] SVN? In-Reply-To: <441F1F49.1040600@laposte.net> References: <441F1F49.1040600@laposte.net> Message-ID: <441FCB1D.2090106@myrealbox.com> +1 for switch to svn I have used svn here, i find it ways more usefull then CVS to manipulate. Getting a specific version of repository is easier, you have revision history not only on files but also on directory. You can attach metadatas on a document, leaving informations there for others. Also, revision history covers the whole repository, making it a complete set, while in cvs each file had his own version (to get a specific state of cvs you had to guess somehow a date you wanted to go, in svn you read the version number of offending commit and you checkoout version-1 of repository). On the point of merging / branching problem, may i point out we never branched / merged in crossfire history? But to me, the most importants assets of SVN are: - command line as easy as CVS one for checkouts/commit and very similar, only repository location changes (enough for most devels to easily use it) - tracking of rename / move / deletions (this is, i think what prevented us in the past various reorganisations of code) - svn commits are done in transaction (This is an important point with sf because due to load on sf, the cvs connections are regulary timed out, leaving the CVS in an undetermined stated where not all files get commited) - revisions, tags and branches are easily accessible from a webbrowser. (in viewCVS you needed to go to each file an select a specific version if you wanted to explore a previous state of CVS) Please also note the 'limitations' in sf page also apply to cvs (case sensitivity, restricted file names, permanent removal) As of speed of svn, it is due to transactionnal layer, it shouldn't affect us very much, we don't have hundreds of devel attempting concurrent commits :) I am gald to see sf finally decided to offer svn support, but i wonder since how long they do provide it, maybe it is worth waiting a bit for sf to fix any issue that can arise from their svn configurations. Regards, Tchize Nicolas Weeger a ?crit : >Hello. > >Apparently Sourceforge now has SVN up, and you can import CVS repository >directly. >See http://sourceforge.net/docman/display_doc.php?docid=31070&group_id=1 >for details > >Maybe we could think of moving Crossfire to SVN? > >Nicolas > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From bofh-lists-crossfire-dev at diegeekdie.com Tue Mar 21 04:39:36 2006 From: bofh-lists-crossfire-dev at diegeekdie.com (Sebastian Andersson) Date: Tue, 21 Mar 2006 11:39:36 +0100 Subject: [crossfire] SVN? In-Reply-To: <441FCB1D.2090106@myrealbox.com> References: <441F1F49.1040600@laposte.net> <441FCB1D.2090106@myrealbox.com> Message-ID: <20060321103936.GQ4204@hogia.net> Just adding my anectdotes: We've used SVN at work for almost two years now. I constantly miss it when using CVS, but once every couple of weeks the repository locks up and the admin (me) has to restart apache & recover the repositories (it takes just a few seconds). There are also a couple of ways to DOS attack the system that our testers have unintentionally done when commiting their testfiles... Nothing has been hard to fix, but I don't know how quick the SF admins are at noticing such things and fixing them. On the other hand, if the repository is down, one can still check what files has been modified, make diffs and revert them back to the original. Regards, /Sebastian -- .oooO o,o Oooo. Ad: http://dum.acc.umu.se/ ( ) \_/ ( ) (o_ "Life is not fair, but root \ ( /|\ ) / (o_ //\ password helps!" -- The BOFH \_) (_/ (/)_ V_/_ From cerzeo at gmail.com Tue Mar 21 10:51:50 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Tue, 21 Mar 2006 17:51:50 +0100 Subject: [crossfire] [Crossfire] [Idea] Spells inmediate effects Message-ID: <3fa509450603210851of0e31cdo@mail.gmail.com> I was playing CF and killing dreads while I realize that most common spells have no secondary effect. I think that a more realistic effect of cold spells can be, appart of damage, of course, to "slow" the player by the chill effect. More other spells can have other secondary effects, like "create bomb": if a player is hit by the explosion, he will move arround, like "fear" spell. Other example: If a fire dragon hits you with fire, he can burn a random cloth, scroll/book or woodmade items (arrows, bow, etc...). Not burn all items, just a random one. Maybe this is a very hard effect, but is only an example. This effects will made killing ranged magical monsters a bit harder, and the player will need a better strategy before stay in from of him, casting burning hands all the time. -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060321/7ee2c1fe/attachment.htm From lalo.martins at gmail.com Tue Mar 21 16:15:59 2006 From: lalo.martins at gmail.com (Lalo Martins) Date: Wed, 22 Mar 2006 06:15:59 +0800 Subject: [crossfire] SVN? In-Reply-To: <441FCB1D.2090106@myrealbox.com> References: <441F1F49.1040600@laposte.net> <441FCB1D.2090106@myrealbox.com> Message-ID: This is the 999th (ish) similar discussion I had in the last few months :-P so I figured it was about time to blog a summary: http://lalo.revisioncontrol.net/blog/lalo/#entry:24 Highlights: And so says Tchize on 21/03/06 17:45... > On the point of merging / branching problem, may i point > out we never branched / merged in crossfire history? Sure, because CVS makes it inconvenient. And with SVN, you will still not branch. However, crossfire *should* be branching much more often, and it would if it used a reasonable revision control system. Right now what happens instead is either: - developer writes complicated code on his machine, over the course of, from a few days to a few weeks. This requires constantly catching up with cvs, and there is no revision control for this "local branch" - if you make a mistake and kill some code you later decide you wanted after all, you have to write it again. Then developer commits it in a big batch. This happens specially to MWedel. - developer codes incrementally, using CVS, often leaving users with the incomplete feature. > - command line as easy as CVS one for checkouts/commit and very similar, > only repository location changes (enough for most devels to easily use it) Well, CVS is even more similar :-P Seriously, other, REAL revision control systems also have command lines similar to CVS. Bazaar-NG, which is my recommendation, is quite similar, in the commands that have a parallel in CVS at all. > - tracking of rename / move / deletions (this is, i think what prevented > us in the past various reorganisations of code) That's the only one where I agree. I just don't think it's worth the pain. > - svn commits are done in transaction (This is an important point with > sf because due to load on sf, the cvs connections are regulary timed > out, leaving the CVS in an undetermined stated where not all files get > commited) Non sequitur... there are others, different ways to get an inconsistent svn, and when you do, you mess up the whole repository. > - revisions, tags and branches are easily accessible from a webbrowser. > (in viewCVS you needed to go to each file an select a specific version > if you wanted to explore a previous state of CVS) Sounds cool, in practice it doesn't make a difference at all. best, Lalo Martins -- So many of our dreams at first seem impossible, then they seem improbable, and then, when we summon the will, they soon become inevitable. -- personal: http://www.laranja.org/ technical: http://lalo.revisioncontrol.net/ GNU: never give up freedom http://www.gnu.org/ From lalo.martins at gmail.com Tue Mar 21 16:21:10 2006 From: lalo.martins at gmail.com (Lalo Martins) Date: Wed, 22 Mar 2006 06:21:10 +0800 Subject: [crossfire] [Crossfire] [Idea] Spells inmediate effects In-Reply-To: <3fa509450603210851of0e31cdo@mail.gmail.com> References: <3fa509450603210851of0e31cdo@mail.gmail.com> Message-ID: And so says Alberto S?ez Lodeiros on 22/03/06 00:51... > I was playing CF and killing dreads while I realize that most common > spells have no secondary effect. I think that a more realistic effect of > cold spells can be, appart of damage, of course, to "slow" the player by > the chill effect. One idea that was explored a few years ago is that fire and cold spell should raise/lower the temperature around them, while electrical ones, if cast outdoors, increase the chance of rain. However, while (IIRC) most people agreed it would be cool, the outcome was basically: this would tie in to the weather code, but right now it's way too broken to be used, so this feature would end up not being visible anyway. If the weather eventually gets fixed, we could add this. And maybe some max/min checks... if characters are above/below some limits they lose HP, if items are above/below some limits they burn/melt/freeze. It would be interesting... 1: go outside in a snowstorm, 2: cast meteor storm, 3: ???, 4: profit best, Lalo Martins -- So many of our dreams at first seem impossible, then they seem improbable, and then, when we summon the will, they soon become inevitable. -- personal: http://www.laranja.org/ technical: http://lalo.revisioncontrol.net/ GNU: never give up freedom http://www.gnu.org/ From tchize at myrealbox.com Tue Mar 21 17:26:02 2006 From: tchize at myrealbox.com (tchize) Date: Wed, 22 Mar 2006 00:26:02 +0100 Subject: [crossfire] automated unit testing Message-ID: <44208B8A.7040004@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 The first shoot of unit test has been commited in cvs, along with a few very nice add-ons to configure script. The framework has been configured for test/unit/** other directories will be linked later, there is already plenty of file to work on :) to run unit tests, do a ./configure make make -k check the -k is important, it tells make to continue even if some tests fails. I have made empty testcase failing for all existing crossfire files. We now need lots of apes / monkeys, to write the test code to have them success. An example finished file is test/common/check_shstr.c all test logs go to test/logs as xml files (will be usefull for automated webpage generation with nightliy test result on sourceforge :p) screen ouput of test are driven by environment variable CK_VERBOSITY which can have the values "silent", "minimal", "normal, "verbose" first doc written in doc/Developers/testplans (this was the previous test docs, it as been replaced) Have fun, code well, let's get all those test filled :) Tchize David Delbecq -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEIIuKHHGOa1Q2wXwRArvDAJ4kbyoIeAdSBwJLWO7YbOwSzEsNeQCfXqeQ ggzpFaFzVizOkO6yP5OAQfI= =QIZc -----END PGP SIGNATURE----- From alex_sch at telus.net Tue Mar 21 17:31:58 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 21 Mar 2006 16:31:58 -0700 Subject: [crossfire] SVN? In-Reply-To: References: <441F1F49.1040600@laposte.net> <441FCB1D.2090106@myrealbox.com> Message-ID: <44208CEE.2090507@telus.net> Lalo Martins wrote: >Sure, because CVS makes it inconvenient. And with SVN, you will still >not branch. However, crossfire *should* be branching much more often, >and it would if it used a reasonable revision control system. > >Right now what happens instead is either: > >- developer writes complicated code on his machine, over the course of, >from a few days to a few weeks. This requires constantly catching up >with cvs, and there is no revision control for this "local branch" - if >you make a mistake and kill some code you later decide you wanted after >all, you have to write it again. Then developer commits it in a big >batch. This happens specially to MWedel. > >- developer codes incrementally, using CVS, often leaving users with the >incomplete feature. > Yes, this indeed a current revision control issue. Personally I try to keep to the former of those two and avoid the later like the plague. Then try to minimize the affect, instead of making monolithic changes, figuring out a way to split a large task into many subtasks, as many of the subtasks as possible being usable for purposes other than the larger task too (i.e. what I've been doing for land plots and required features). However that is not always possible to split like that and even then some sort of revision control on "local branches" would be good. Alex Schultz From alex_sch at telus.net Tue Mar 21 17:37:11 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 21 Mar 2006 16:37:11 -0700 Subject: [crossfire] automated unit testing In-Reply-To: <44208B8A.7040004@myrealbox.com> References: <44208B8A.7040004@myrealbox.com> Message-ID: <44208E27.4050709@telus.net> Ahh, good fun. Can't wait to start looking at making some, some of the functional tests could be fun to make. Alex Schultz tchize wrote: >The first shoot of unit test has been commited in cvs, along with a >few very nice add-ons to configure script. The framework has been >configured for test/unit/** > >other directories will be linked later, there is already plenty of >file to work on :) >to run unit tests, do a >./configure >make >make -k check > >the -k is important, it tells make to continue even if some tests fails. >I have made empty testcase failing for all existing crossfire files. >We now need lots of apes / monkeys, to write the test code to have >them success. An example finished file is test/common/check_shstr.c > >all test logs go to test/logs as xml files (will be usefull for >automated webpage generation with nightliy test result on sourceforge :p) > >screen ouput of test are driven by environment variable >CK_VERBOSITY > which can have the values "silent", "minimal", "normal, "verbose" > >first doc written in doc/Developers/testplans (this was the previous >test docs, it as been replaced) > >Have fun, code well, let's get all those test filled :) > >Tchize >David Delbecq > From mikeeusaa at yahoo.com Tue Mar 21 17:16:36 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Tue, 21 Mar 2006 15:16:36 -0800 (PST) Subject: [crossfire] [Crossfire] [Idea] Spells inmediate effects In-Reply-To: Message-ID: <20060321231636.7297.qmail@web32704.mail.mud.yahoo.com> Weather code is usable. I use it, albit on level 4 now. --- Lalo Martins wrote: > And so says Alberto S?ez Lodeiros on 22/03/06 > 00:51... > > I was playing CF and killing dreads while I > realize that most common > > spells have no secondary effect. I think that a > more realistic effect of > > cold spells can be, appart of damage, of course, > to "slow" the player by > > the chill effect. > > One idea that was explored a few years ago is that > fire and cold spell > should raise/lower the temperature around them, > while electrical ones, > if cast outdoors, increase the chance of rain. > However, while (IIRC) > most people agreed it would be cool, the outcome was > basically: this > would tie in to the weather code, but right now it's > way too broken to > be used, so this feature would end up not being > visible anyway. > > If the weather eventually gets fixed, we could add > this. And maybe some > max/min checks... if characters are above/below some > limits they lose > HP, if items are above/below some limits they > burn/melt/freeze. > > It would be interesting... 1: go outside in a > snowstorm, 2: cast meteor > storm, 3: ???, 4: profit > > best, > Lalo > Martins > -- > So many of our dreams at first seem > impossible, > then they seem improbable, and then, when we > summon the will, they soon become inevitable. > -- > personal: > http://www.laranja.org/ > technical: > http://lalo.revisioncontrol.net/ > GNU: never give up freedom > http://www.gnu.org/ > > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From mikeeusaa at yahoo.com Tue Mar 21 17:57:11 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Tue, 21 Mar 2006 15:57:11 -0800 (PST) Subject: [crossfire] Treasurelist idea In-Reply-To: <44208CEE.2090507@telus.net> Message-ID: <20060321235711.97145.qmail@web32701.mail.mud.yahoo.com> I was thinking (perhapse this is allready doable): treasure bla arch sword chance 20 magic 4 set damned 1 set wc -2 set msg set this is a great sword sed endmsg end If the code sees "set" then that which comes after it will be applied to the dropped thing __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From alex_sch at telus.net Tue Mar 21 18:24:24 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 21 Mar 2006 17:24:24 -0700 Subject: [crossfire] SVN? In-Reply-To: <44208CEE.2090507@telus.net> References: <441F1F49.1040600@laposte.net> <441FCB1D.2090106@myrealbox.com> <44208CEE.2090507@telus.net> Message-ID: <44209938.4070207@telus.net> Alex Schultz wrote: >Yes, this indeed a current revision control issue. Personally I try to >keep to the former of those two and avoid the later like the plague. >Then try to minimize the affect, instead of making monolithic changes, >figuring out a way to split a large task into many subtasks, as many of >the subtasks as possible being usable for purposes other than the larger >task too (i.e. what I've been doing for land plots and required >features). However that is not always possible to split like that and >even then some sort of revision control on "local branches" would be good. > Adding to what I just said, perhaps some developer usage of svk ( http://svk.elixus.org/ ) would be helpful for local branches. It is capable of syncing with both svn and cvs (not sure how good such syncing with cvs is for local branches, but apparently it's great for svn). Alex Schultz From alex_sch at telus.net Tue Mar 21 18:29:03 2006 From: alex_sch at telus.net (Alex Schultz) Date: Tue, 21 Mar 2006 17:29:03 -0700 Subject: [crossfire] Weather usability was: [Idea] Spells inmediate effects In-Reply-To: <20060321231636.7297.qmail@web32704.mail.mud.yahoo.com> References: <20060321231636.7297.qmail@web32704.mail.mud.yahoo.com> Message-ID: <44209A4F.9030202@telus.net> Miguel Ghobangieno wrote: >Weather code is usable. I use it, albit on level 4 >now. > However there are still some bugs such as disappearing things, and in many ways the results are too extreme and granular. I am not sure, but for this, I blame extreme elevation values (which happen to be a little corrupted across bigworld, but too extreme anyways). In addition, the weather code is not usable in anything other than bigworld, as in, not usable for temperature and such in smaller maps. Alex Schultz From mwedel at sonic.net Wed Mar 22 01:54:18 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 21 Mar 2006 23:54:18 -0800 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <20060321012820.GA2944@elmex> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> <441F1D94.1090901@laposte.net> <20060321012820.GA2944@elmex> Message-ID: <442102AA.7040709@sonic.net> Robin Redeker wrote: > On Mon, Mar 20, 2006 at 10:24:36PM +0100, Nicolas Weeger wrote: >>> A simple ring of halvor requires level around 10 and a ring of free >>> action requires around level 15 and ring of combat level 20. >>> But when i'm level 10, 15 or 20 at jewelery i always have already found >>> quite many of those rings... IMHO it's too difficult or too much hassle >>> to make those. >> Don't forget the ingredients. Must (all?) are really rare, thus it's >> easier to buy a potion. >> > > Yes! Thats also what i meant. IMHO at the current state, > all cauldron-skills except alchemistry (and alchemistry partially also) > are only good for identifying. One thought that was expressed, but I don't ever think developed, was to have these naturally occuring ingredients actually show up in the wild. Thus, on the world map, in the right places, you could find the various vegetation. Likewise, in dungeons, there would be some means of of digging for the raw elements. This doesn't completely fix the problem, but finding the basic ingredients should probably be a lot easier than it is now. > Maybe it would be enough to make the formulars easier and make > it 'harder' in means of randomness to make something. > For example: you put in 1 large gold nugget, 2 emeralds (yes, not > exceptional emeralds) and only a success rate of 1/10 or something like > this... but this is just a random idea. not sure if this is also > senseless. I think one problem is that if you play honestly, finding all the recipes within the game is pretty darn hard. Even finding basic recipes seems pretty hard. One fix might be to increase the amount of readable books that show up a bit (you can do 20 levels of a dungeon and only get a few recipe books). One other problem, which I think was discussed, is that the formulae file only has a basic 'diff' field to denote difficulty. These really should perhaps be broken out a bit, like: success_chance: base chances of success, in percentage success_increase: % increase/level above min_level your success goes up. min_level: minimum level you need to be to have any chance of success Thus, you could have formula set up that requires you to be at least 5th level, but once there, you can have a pretty good chance of success. Or you could set up formula that even at 20th level, your chance is pretty low, and it doesn't go up very fast. That could also make adjustment of the formula better. From mwedel at sonic.net Wed Mar 22 02:21:12 2006 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 22 Mar 2006 00:21:12 -0800 Subject: [crossfire] SVN? In-Reply-To: <441F1F49.1040600@laposte.net> References: <441F1F49.1040600@laposte.net> Message-ID: <442108F8.6070603@sonic.net> Nicolas Weeger wrote: > Hello. > > Apparently Sourceforge now has SVN up, and you can import CVS repository > directly. > See http://sourceforge.net/docman/display_doc.php?docid=31070&group_id=1 > for details > > Maybe we could think of moving Crossfire to SVN? Couple quick notes from my side on this discussion: I'd generally say that to make a switch, what we are switching to has to be clearly better. Making a near even trade may not be a good trade just because of the effort to make the switch (all developers need to install SVN software, I'd think also that if you have work in progress, you'll have to manually move that over to SVN environment, etc). There is also perhaps something to be said that CVS is probably more standard. To tell people to use cvs to checkout latest version (and provide them the cvs command), good chance they probably have cvs client installed. Not sure how wide spread SVN is either. In terms of specific features: Renames don't happen that often, but sometimes do happen. I think this mostly happens regarding stuff in the arch tree - being able to keep revision history on a move would be nice, but most files in the arch tree don't have much a history, or if they do, isn't very interesting. Where we do very infrequently run into problems is when a file/directory has been deleted and we want to re-add it as a different type (file->directory, or vice versa). CVS doesn't like that. You can resuscitate the file if it is of the same type, but not different types. I can't remember last time this came up - long time back, but does come it once in a very rare while. Getting specific versions as tchize describes is interesting, but not something I have used often. I do symbolic tag the official releases, so if you want to get release 1.4.0, just use the tag rel-1-4-0 with CVS. Once in a rare while, I'll also want to look at the state of things before some specific checkin, but doing a checkout based on date has been sufficient so far (cvs commits are automatically date stamped). I don't know how many people view the CVS tree through the web page, so not positive how much benefit we get by SVN making more useful information available. In terms of branching, as mentioned, I'm usually the one most hit by this. But to me, the real show stopper here is ability to have a nice merge functionality. CVS isn't that great - if the there are no conflicts, no problem, but if there are, CVS just brackets the code where there is an issue, leaving you to fix it in your favorite editor. I don't know if SVN is any better. Some other products I have seen do have a nice GUI, letting one select which line/block to take. I think there are graphical CVS tools, so maybe they do something similar. But the real problems with branches is that I don't think there are currently enough people using crossfire that a branch gets much usage. One idea tossed out was to put experimental code in the branch, but if no one uses the branch, doesn't do much good. One complaint I do have with CVS, and I don't know if SVN is better, is that CVS will bring back code I delete. Say for example I'm editing a file, and remove the function foo() as well as make some other changes. Someone else makes some change to the file and commits. I do a cvs update, and foo() is now back in my file - even though no where along the process were any changes made to foo() itself. So then I have to go and delete again. Branches may make that a little cleaner. One other note regarding SVN on sourceforge - with CVS, we can basically use whatever scripts we want for checkin (current e-mail notification being one). With SVN, only a few specific scripts are allowed, and it seems that only there versions are allowed. I don't know if that actually makes much difference or not - I suppose it depends on what the output of their commit script looks like. From cerzeo at gmail.com Wed Mar 22 03:01:11 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Wed, 22 Mar 2006 10:01:11 +0100 Subject: [crossfire] [Crossfire] CF promo video Message-ID: <3fa509450603220101h31c20ea8j@mail.gmail.com> Hi all Last days, I have returned to the world of CF after a problem with Motherboard, Processor and RAM Memory. As you know, when a game is well known by many many players aroud the world, it becomes more and more funny. OK, then, i was thinking ways to promo Crossfire, I say Crossfire "general", not a concrete server (cat2, Metalforge, schmorp...). And a cool idea can be a "Promotion Video". This is a In-Game video of Crossfire, with a presentation and so on, a player fighting with a Dread, and with a high level monster, a PvP duel and all exciting things who CF offers the player. I was looking for a program to record a video of the desktop, and I have found one, called "vnc2swf". It allows to save in swf format a vnc session. Can you tell me if you like the idea? Do you know any other program like "vnc2swf"? What kind of music do you like for the video (electronical or heavy metal/rock, classical)? What kind of promo video/s do you like before (WoW videos, UA videos, Lineage videos...)? etc... -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060322/ffbb9a84/attachment.htm From tchize at myrealbox.com Wed Mar 22 03:25:11 2006 From: tchize at myrealbox.com (Tchize) Date: Wed, 22 Mar 2006 10:25:11 +0100 Subject: [crossfire] [Crossfire] CF promo video In-Reply-To: <3fa509450603220101h31c20ea8j@mail.gmail.com> References: <3fa509450603220101h31c20ea8j@mail.gmail.com> Message-ID: <442117F7.6050704@myrealbox.com> Yeah, love the idea :) I have already tried in the past, the most difficult part is to make an ingame video which you can furter edit (is swf an 'editable' video format?) Most programs i tried were quite sensible to the cpu busy cycle when interresting things happened ingame, resulting in laggy video :( A good thing might be to have a 'hacked' client output each of it's map renders to a raw file along with timing information and then reorganize this afterward in something like 50png/seconds ? Alberto S?ez Lodeiros a ?crit : > Hi all > > Last days, I have returned to the world of CF after a problem with > Motherboard, Processor and RAM Memory. > > As you know, when a game is well known by many many players aroud the > world, it becomes more and more funny. OK, then, i was thinking ways > to promo Crossfire, I say Crossfire "general", not a concrete server > (cat2, Metalforge, schmorp...). And a cool idea can be a "Promotion > Video". > This is a In-Game video of Crossfire, with a presentation and so on, a > player fighting with a Dread, and with a high level monster, a PvP > duel and all exciting things who CF offers the player. > > I was looking for a program to record a video of the desktop, and I > have found one, called "vnc2swf". It allows to save in swf format a > vnc session. > > Can you tell me if you like the idea? Do you know any other program > like "vnc2swf"? What kind of music do you like for the video > (electronical or heavy metal/rock, classical)? What kind of promo > video/s do you like before (WoW videos, UA videos, Lineage videos...)? > etc... > > -- > Powered By SuSE Linux 10.0 > >------------------------------------------------------------------------ > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > From cerzeo at gmail.com Wed Mar 22 04:59:57 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Wed, 22 Mar 2006 11:59:57 +0100 Subject: [crossfire] [Re] [Crossfire] CF promo video Message-ID: <3fa509450603220259l30e33a1fk@mail.gmail.com> I dont know if SWF flash files are editable. i can tell you that it doesnt matter because I need them in avi format or any other editable video format. The conversion from swf to avi can be made with "Winmpg". This is a program for wind*ws to convert swf to avi, mpeg and many more, and when i had the avi file, i can edit it with "avidemux", "main actor" or any other video editor under Linux. See this page for more info: http://www.winmpg.com -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060322/637a730f/attachment-0001.htm From cerzeo at gmail.com Wed Mar 22 05:08:58 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Wed, 22 Mar 2006 12:08:58 +0100 Subject: [crossfire] [Re] [Crossfire] [Idea] Spells inmediate effects Message-ID: <3fa509450603220308p509991b1w@mail.gmail.com> I dont speak on spells effects in the world. I say effects in the player hitted by the spell. I dont know how to program this at Python, but it can be something like this (Visual Basic like code): if playerHitByExplosion(PlayerID) then castFear() castConfussion() doDamageToPlayer(10) endif Public Sub castFear() (here goes the general code for Fear effects) end sub Public Sub CastConfussion() (code for confussion) end sub -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060322/5d30975c/attachment.htm From alex_sch at telus.net Wed Mar 22 08:26:38 2006 From: alex_sch at telus.net (Alex Schultz) Date: Wed, 22 Mar 2006 07:26:38 -0700 Subject: [crossfire] SVN? In-Reply-To: <442108F8.6070603@sonic.net> References: <441F1F49.1040600@laposte.net> <442108F8.6070603@sonic.net> Message-ID: <44215E9E.2080803@telus.net> Mark Wedel wrote: > In terms of branching, as mentioned, I'm usually the one most hit by this. >But to me, the real show stopper here is ability to have a nice merge >functionality. CVS isn't that great - if the there are no conflicts, no >problem, but if there are, CVS just brackets the code where there is an issue, >leaving you to fix it in your favorite editor. I don't know if SVN is any >better. Some other products I have seen do have a nice GUI, letting one select >which line/block to take. I think there are graphical CVS tools, so maybe they >do something similar. > > From what I can see, SVN is on par with this. It does it slightly differently, but not really any easier looking or harder looking. > But the real problems with branches is that I don't think there are currently >enough people using crossfire that a branch gets much usage. One idea tossed >out was to put experimental code in the branch, but if no one uses the branch, >doesn't do much good. > > Well, SVN does have a significant advantage here. From what I can see, it is very easy, by either using SVN, or svn-mirror, to have a local mirror of the SVN tree on your computer, that you can use as a 'local branch'. That also has the advantage that within your local branch, you could revert little changes very easily if you were committing to your local branch step by step. The whole time you can have it sync with the main SVN server, and eventually merge your changes back to the main svn server (preserving the individual commits). IMHO, using SVK or svn-mirror, syncing with a sourceforge svn server, would solve such branching issues very nicely without cluttering the remote server. > One complaint I do have with CVS, and I don't know if SVN is better, is that >CVS will bring back code I delete. > > Say for example I'm editing a file, and remove the function foo() as well as >make some other changes. Someone else makes some change to the file and >commits. I do a cvs update, and foo() is now back in my file - even though no >where along the process were any changes made to foo() itself. So then I have >to go and delete again. Branches may make that a little cleaner. > > Not sure if SVN is any better either, though the branching as I was talking about above could possibly help. Alex Schultz From mikeeusaa at yahoo.com Tue Mar 21 20:21:51 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Tue, 21 Mar 2006 18:21:51 -0800 (PST) Subject: [crossfire] Treasurelist idea In-Reply-To: <4420989B.10104@telus.net> Message-ID: <20060322022151.19600.qmail@web32710.mail.mud.yahoo.com> Well using set as a prefix would allow you to put whatever in the arch, thus one wouldn't need to edit the code every time a new variable is created since set just passes it into the archtype in memory. --- Alex Schultz wrote: > Miguel Ghobangieno wrote: > > >I was thinking (perhapse this is allready doable): > > > >treasure bla > > arch sword > > chance 20 > > magic 4 > > set damned 1 > > set wc -2 > > set msg > > set this is a great sword > > sed endmsg > > end > > > >If the code sees "set" then that which comes after > it > >will be applied to the dropped thing > > > Hmm, not sure it's the best way to approach the > issue (i.e. do we even > need to prepend "set"?), but that would in some ways > be a good idea. > > Also, please don't use the reply button to start a > completely new topic, > it messes up those using thread view (I am anyways, > and that's how > people on the web archives often view it) > > Alex Schultz > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From mikeeusaa at yahoo.com Tue Mar 21 22:59:29 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Tue, 21 Mar 2006 20:59:29 -0800 (PST) Subject: [crossfire] Weather usability was: [Idea] Spells inmediate effects In-Reply-To: <44209A4F.9030202@telus.net> Message-ID: <20060322045929.29600.qmail@web32715.mail.mud.yahoo.com> It has some new bugs where things become blocking on reload too. Thus I flush my saved weather overlays every so often. This bug came after the new movement types. Oh I'd like to beable to set it so arrows, bolts, and shooting spells can traverse water. Could we have new movement types: arrow(or projectile) etc. projectile probably would be fine. I tried to do it my self hoping that the movement code used key value... :( --- Alex Schultz wrote: > Miguel Ghobangieno wrote: > > >Weather code is usable. I use it, albit on level 4 > >now. > > > However there are still some bugs such as > disappearing things, and in > many ways the results are too extreme and granular. > I am not sure, but > for this, I blame extreme elevation values (which > happen to be a little > corrupted across bigworld, but too extreme anyways). > In addition, the weather code is not usable in > anything other than > bigworld, as in, not usable for temperature and such > in smaller maps. > > Alex Schultz > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From mikeeusaa at yahoo.com Wed Mar 22 09:41:09 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Wed, 22 Mar 2006 07:41:09 -0800 (PST) Subject: [crossfire] Sock puppet xploit Message-ID: <20060322154109.27780.qmail@web32709.mail.mud.yahoo.com> Could that sockpuppet xploit please be fixed?. I like the idea of the force that makes it so that if the player (who's name is in the force's slaying field?) is killed on the spot where he died or the bed he ressurected on no xp goes to the attacker. Also there could be a 2nd force in the player that is active for 3 seconds or so that if present won't give xp to any attacking player. With both these inplace the sockpuppeting xploit should be mitigated. __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From tchize at myrealbox.com Wed Mar 22 17:08:42 2006 From: tchize at myrealbox.com (tchize) Date: Thu, 23 Mar 2006 00:08:42 +0100 Subject: [crossfire] configure -> crossedit Message-ID: <4421D8FA.4050601@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Commited some basic checks in configure to skip crossedit and crossedit unit test directories from make process if it appear not compilable. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEIdj6HHGOa1Q2wXwRAtGmAKCse858rXr3G7JcstiJRjIkorCBrACdEZzq K+M4Ay9mhb6Vy8nd5pZOxoE= =j3wa -----END PGP SIGNATURE----- From mwedel at sonic.net Thu Mar 23 00:43:59 2006 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 22 Mar 2006 22:43:59 -0800 Subject: [crossfire] Weather usability was: [Idea] Spells inmediate effects In-Reply-To: <20060322045929.29600.qmail@web32715.mail.mud.yahoo.com> References: <20060322045929.29600.qmail@web32715.mail.mud.yahoo.com> Message-ID: <442243AF.9060706@sonic.net> Miguel Ghobangieno wrote: > Oh I'd like to beable to set it so arrows, bolts, and > shooting spells can traverse water. Could we have new > movement types: arrow(or projectile) etc. projectile > probably would be fine. I tried to do it my self > hoping that the movement code used key value... :( It seems you are mixing two things here - the movement type, and what can move onto the space. Adding new movement types isn't hard, but the blocking for many arches would have to be updated. And I'm not sure that having a whole bunch of movement types is the correct approach (one problem that can still happen even in that model is someone creates an object that gives player the projectile movement). To me, the right approach would be to add some new flags - we already have things like no magic, so extend that with things like no_player and/or no_monster. From mwedel at sonic.net Thu Mar 23 00:48:23 2006 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 22 Mar 2006 22:48:23 -0800 Subject: [crossfire] [Re] [Crossfire] [Idea] Spells inmediate effects In-Reply-To: <3fa509450603220308p509991b1w@mail.gmail.com> References: <3fa509450603220308p509991b1w@mail.gmail.com> Message-ID: <442244B7.4020807@sonic.net> Alberto S?ez Lodeiros wrote: > I dont speak on spells effects in the world. I say effects in the player > hitted by the spell. > > I dont know how to program this at Python, but it can be something like > this (Visual Basic like code): > > if playerHitByExplosion(PlayerID) then > castFear() > castConfussion() > doDamageToPlayer(10) > endif > > Public Sub castFear() > (here goes the general code for Fear effects) > end sub > > Public Sub CastConfussion() > (code for confussion) > end sub Note that as far as I know, being both confused and fear do not stack - the code will either act as if the player is confused or the player is feared, not both (I'd have to look at the code, but it really comes down to what check is first in the player move function). However, I'd suggest that this really isn't the right approach. From what you described, the idea was that and explosion should knock you back. Confusion just creates random movement - it is unclear why an explosion would confuse the player. Fear also isn't quite what you want either - the reason is because as said above, the explosion should knock the player back when the explosion happens. If you fear the player, the player won't move back until the player would move next, and then it would use the player movement cycle to move the player back. That doesn't seem right to me. I do seem to recall that there is an existing spell or two (wave? windstorm?) that do knock monsters back, so that code does exist. From elmex at ta-sa.org Thu Mar 23 12:07:03 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Thu, 23 Mar 2006 19:07:03 +0100 Subject: [crossfire] New map editor Message-ID: <20060323180703.GA5861@elmex> Hi, i wanted to announce that we've written a new map editor: http://cf.schmorp.de/editor.shtml It's written in pure Perl with the Gtk2 perl module. There are one-binary-packages for windows and linux x86; Features (compared to CFJavaEditor): * supports current crossfire map format (in contrast to CFJavaEditor's deprecated format) * higher map editing comfort * intelligent placement, erase and connection tool * faster and smaller than the java editor * map normalizing (removal of old deprecated attributes) * exit navigation * world map navigation * easier installation (on windows) * it is not Java Currently missing features: * Autojoining * Treasurelists * Highlighting Author: The cf.schmorp.de Crossfire Develeopment Team Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From lordyoukai at gmail.com Thu Mar 23 23:45:56 2006 From: lordyoukai at gmail.com (Lord Youkai) Date: Thu, 23 Mar 2006 21:45:56 -0800 Subject: [crossfire] [Crossfire] CF promo video In-Reply-To: <442117F7.6050704@myrealbox.com> References: <3fa509450603220101h31c20ea8j@mail.gmail.com> <442117F7.6050704@myrealbox.com> Message-ID: <2501b33a0603232145m223a3d3eie664bd0ca31d74d2@mail.gmail.com> Try xvidcap. It records using ffmpeg a video of a full screen or specified area. =p On 3/22/06, Tchize wrote: > > Yeah, love the idea :) > > I have already tried in the past, the most difficult part is to make an > ingame video which you can furter edit (is swf an 'editable' video > format?) > Most programs i tried were quite sensible to the cpu busy cycle when > interresting things happened ingame, resulting in laggy video :( > > A good thing might be to have a 'hacked' client output each of it's map > renders to a raw file along with timing information and then reorganize > this afterward in something like 50png/seconds ? > > Alberto S?ez Lodeiros a ?crit : > > > Hi all > > > > Last days, I have returned to the world of CF after a problem with > > Motherboard, Processor and RAM Memory. > > > > As you know, when a game is well known by many many players aroud the > > world, it becomes more and more funny. OK, then, i was thinking ways > > to promo Crossfire, I say Crossfire "general", not a concrete server > > (cat2, Metalforge, schmorp...). And a cool idea can be a "Promotion > > Video". > > This is a In-Game video of Crossfire, with a presentation and so on, a > > player fighting with a Dread, and with a high level monster, a PvP > > duel and all exciting things who CF offers the player. > > > > I was looking for a program to record a video of the desktop, and I > > have found one, called "vnc2swf". It allows to save in swf format a > > vnc session. > > > > Can you tell me if you like the idea? Do you know any other program > > like "vnc2swf"? What kind of music do you like for the video > > (electronical or heavy metal/rock, classical)? What kind of promo > > video/s do you like before (WoW videos, UA videos, Lineage videos...)? > > etc... > > > > -- > > Powered By SuSE Linux 10.0 > > > >------------------------------------------------------------------------ > > > >_______________________________________________ > >crossfire mailing list > >crossfire at metalforge.org > >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > > > > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060323/8aabfb7a/attachment.htm From elmex at ta-sa.org Fri Mar 24 03:46:45 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 10:46:45 +0100 Subject: [crossfire] New map editor In-Reply-To: <20060323180703.GA5861@elmex> References: <20060323180703.GA5861@elmex> Message-ID: <20060324094645.GA7580@elmex> Hi! I've read about following message: http://mailman.metalforge.org/pipermail/crossfire/2005-August/009071.html We are very open to improvements. And maybe someone could discuss the problem with the order of map objects. The problem is, that if we load a map in GCE and save it again, we get many changes in the order of the objects. We have put efford in some normalizing code, that replaces some old attributes (eg. no_pass) with the new ones (eg. move_block, etc.). Propably someone could write down the real current map standard and how things _should_ be done, and how things _are_ done in the maps that exist. Writing some normalizer is easy once it is clear what to normalize and how. We already have some code, and will write some utility that normalizes all maps (we will do it anyways for the purpose of merging upstream maps from other server with our maps). Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From elmex at ta-sa.org Fri Mar 24 04:01:47 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 11:01:47 +0100 Subject: [crossfire] Jeweler skill Message-ID: <20060324100147.GB7580@elmex> Hi, today i've had some ideas about the jeweler skill: What if a jeweler could _change_ existing rings. For example he could improve a ring (resist acid+12) in to a ring (resist acid+30) or even acid+50? (not sure about this, does it break balancing?). These improvements could be done by assigning combinations of ingredients for example: potion of strenght + 1 emerald + 1 sapphire + [any ring] = ring [any attributes] (Str+1). or: potion of resist paralyze + N rubies + [any ring] => adds N resistnacy points to paralysation to the ring. I only need some ideas how to scale this ability to the level of the skill. IMHO improving a ring should work from level 1 on, so the player can gain experience. Maybe the item_power or the number of improvements of a ring could go into the calculation. (Like the scroll level in the inscription skill). I will propably write a perl plugin when i find some time for it and the question with the level is cleared. This would greatly improve the usability of the jeweler skill and could also help player shops to be a lot more useful... Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From tchize at myrealbox.com Fri Mar 24 04:15:02 2006 From: tchize at myrealbox.com (Tchize) Date: Fri, 24 Mar 2006 11:15:02 +0100 Subject: [crossfire] Jeweler skill In-Reply-To: <20060324100147.GB7580@elmex> References: <20060324100147.GB7580@elmex> Message-ID: <4423C6A6.3070709@myrealbox.com> Be carefull with this, you probably want to check the weapon improvement code. To increase from nothing to str+1, you not only need str potion (3*aimed level if i remember well?) but you have to prepare the weapon by sacrificing a good amount of diamonds. You can also make a difficulty roll on the skill based on skill level, with the risk to badly alter the ring if failed. I like the idea of creating ring, but your suggested costs if far too small considering the power you have when you create the ring! Also, rings amulets and improved weapons are a good way to ge over the race limitation on characteristic. If you make it too easy to create improved rings, like ring (str+3)(for+3)(wis+3)(resist paralysis +100)(resist fire +100)(resist cold +100) (resist electricity+100) creating ring bringing XP? That's discussable, that mean in the end, the xp can be bought :/ (buy rings, ingredients, modify some rings, you got XP without getting in danger...). But that could be ok, considering you can also do that reading books... Robin Redeker a ?crit : >Hi, > >today i've had some ideas about the jeweler skill: What if a jeweler >could _change_ existing rings. For example he could improve a ring >(resist acid+12) in to a ring (resist acid+30) or even acid+50? (not >sure about this, does it break balancing?). > >These improvements could be done by assigning combinations of >ingredients for example: > > potion of strenght + 1 emerald + 1 sapphire + [any ring] > = ring [any attributes] (Str+1). > > or: potion of resist paralyze + N rubies + [any ring] > => adds N resistnacy points to paralysation to the ring. > >I only need some ideas how to scale this ability to the level of the >skill. IMHO improving a ring should work from level 1 on, so the player >can gain experience. Maybe the item_power or the number of improvements >of a ring could go into the calculation. (Like the scroll level in the > inscription skill). > >I will propably write a perl plugin when i find some time for it and >the question with the level is cleared. > >This would greatly improve the usability of the jeweler skill and could >also help player shops to be a lot more useful... > >Robin > >-- >elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com >Robin Redeker > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From cerzeo at gmail.com Fri Mar 24 04:15:43 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Fri, 24 Mar 2006 11:15:43 +0100 Subject: [crossfire] [Re] [Crossfire] CF promo video Message-ID: <3fa509450603240215w59c97330t@mail.gmail.com> Ey, xvidcap sounds good. I have tryed vnc2swf, but the performance goes down, because the computer must support the vnc session, the crossfire game inside the vnc session, and the vnc2swf program, just getting his own part of processor threat. Thanks for this discover :P -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060324/618c2bba/attachment.htm From tchize at myrealbox.com Fri Mar 24 04:18:20 2006 From: tchize at myrealbox.com (Tchize) Date: Fri, 24 Mar 2006 11:18:20 +0100 Subject: [crossfire] New map editor In-Reply-To: <20060324094645.GA7580@elmex> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> Message-ID: <4423C76C.3090909@myrealbox.com> We could probably write such a 'standard' format by basing it on the way loader.c do save a map :D Robin Redeker a ?crit : >Hi! > >I've read about following message: >http://mailman.metalforge.org/pipermail/crossfire/2005-August/009071.html > >We are very open to improvements. And maybe someone could discuss the >problem with the order of map objects. The problem is, that if we load a >map in GCE and save it again, we get many changes in the order of the >objects. > >We have put efford in some normalizing code, that replaces some old >attributes (eg. no_pass) with the new ones (eg. move_block, etc.). > >Propably someone could write down the real current map standard and how >things _should_ be done, and how things _are_ done in the maps that >exist. Writing some normalizer is easy once it is clear what to >normalize and how. We already have some code, and will write some >utility that normalizes all maps (we will do it anyways for the purpose > of merging upstream maps from other server with our maps). > >Robin > >-- >elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com >Robin Redeker > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From cerzeo at gmail.com Fri Mar 24 05:04:42 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Fri, 24 Mar 2006 12:04:42 +0100 Subject: [crossfire] [Re] Jeweler skill Message-ID: <3fa509450603240304h4a677390x@mail.gmail.com> The jeweler skill can be use for some things like those: 1.- More Jeweler skill will allow the player to modify more powerfull rings/amulets 2.- The player can fail to apply the modification. With more Jeweler skill, the player will fail less. To fail a modification can destroy or make a cursed/bad ring/amulet 3.- If the player needs some "ingredients" to modify a ring, for example [Ring+30Acid] + [Scroll of Resist Fire] + [10 Saphires] = [Ring+30Acid+10Fire], then, with more skill at Jeweler, you will need less Sapphires 4.- Initially, you can only make simple rings. This is, you can only modify rings in one aspect, for example, only adding one ressitance, +1 STR, etc..., but if you level up, you will be allowed to make more complex modifications, for expample, adding more than one resistance plus two or more Stats or all you want. * And all this gives me a cool idea, but i dont know if its implementation is hard or not. The idea is based on wands/rods/staffs. There can be objects with spells imbued on them, for example, a ring with the "Holy Word" inside. Then, the player will be allowed to cast "Holy Word" and s/he dont need the praying skill, just need a determinated level of "Use Magic Object". Of course, the spell on the ring is infinite: The player will drain his/her mana or grace. Jewelers can make those rings. For example: [Ring(int+1)] +[ [Scroll of Imbuing] OR [Potion of Improvement] ] + [Scroll of Banishment (lvl 30)] + [160 diamonds] = Ring(int+1) of Banishment(lvl 30). I will explain how i tell 160 diamonds: If the ring has one or more skills [int+1; speed+2, resist slow +20, etc...), we will need 10 diamonds for each such "skill", in this example, we only need 10. Then, for each level of the imbued spell (in this case 30 levels of Banishment), we will need 5 aditional, so here, we will need 5*30 diamonds. Then, the total diamonds will be "10 + 5*30" diamonds. But the thing is not so easy. Not all jewelers will be able to do this. You will need some aditional skills, imbuing spells. You will need a literacy and transcription skill at half level that the inbued spell is. It is suposed that you have to READ and WRITE the magical runes from the scroll to the ring or amulet. In this case, you will need a certain level of yewelry and level 15 literacy and 15 transcription. This will made the item much balanced, because the jeweler will need many diamonds to make powerfull rings, an high literacy skill and transcription, maybe an high jeweler skill and a "Scroll of Imbuing", who can be a semi-rare object (or it costs much in shops). -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060324/cbba6329/attachment.htm From elmex at ta-sa.org Fri Mar 24 05:08:04 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 12:08:04 +0100 Subject: [crossfire] Jeweler skill In-Reply-To: <4423C6A6.3070709@myrealbox.com> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> Message-ID: <20060324110804.GA7903@elmex> On Fri, Mar 24, 2006 at 11:15:02AM +0100, Tchize wrote: > You can also make a difficulty roll on the skill based on skill level, > with the risk to badly alter the ring if failed. Yes, propably making the improvement the opposite... if you wanted to make a resist fire + 30 ring, you propably get a resist fire +10 or -20 ring... > I like the idea of creating ring, but your suggested costs if far too > small considering the power you have when you create the ring! Yes, the costs of many resistancies should propably some exp-function... Eg. 1 emerald for resist + 1, 2 emerald for +2, 4 for +4 ... The function propably could be x^1.5. > Also, rings amulets and improved weapons are a good way to ge over the > race limitation on characteristic. If you make it too easy to create > improved rings, like ring (str+3)(for+3)(wis+3)(resist paralysis > +100)(resist fire +100)(resist cold +100) (resist electricity+100) I thought about calculating the difficulty to make such a ring similar or by the item_power. Such a ring would have item_power +50 or something. So it should take level 25 or 50 jeweler to alter such a ring (at least). But it should be possible to do such a ring. One has to have a high enough level anyways to wear such an item (because of item_power). > creating ring bringing XP? That's discussable, that mean in the end, the > xp can be bought :/ (buy rings, ingredients, modify some rings, you got > XP without getting in danger...). But that could be ok, considering you > can also do that reading books... And identifying stuff with jeweler,smithery and all. But i don't see where exp should come from in skills like smithery or jeweler, when not from creating things (or identifying them). In context of experience-rings: I've even once thought of a ring that alters the amount of gained experience... eg. you get 10% more exp with a ring :) But such an item is propably not a very good in concern to balancing. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From wim-cf at villerius.nl Fri Mar 24 05:09:23 2006 From: wim-cf at villerius.nl (Wim Villerius) Date: Fri, 24 Mar 2006 12:09:23 +0100 Subject: [crossfire] Jeweler skill In-Reply-To: <4423C6A6.3070709@myrealbox.com> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> Message-ID: <1143198563.14079.38.camel@localhost.localdomain> On Fri, 2006-03-24 at 11:15 +0100, Tchize wrote: > Be carefull with this, you probably want to check the weapon > improvement code. To increase from nothing to str+1, you not only need > str potion (3*aimed level if i remember well?) but you have to prepare > the weapon by sacrificing a good amount of diamonds. > I like the idea of creating ring, but your suggested costs if far too > small considering the power you have when you create the ring! 2*number of stat enchantment, so to make a weapon str+3, one needs 2+4+6 = 12 potions of strength. Adding also a con requires 8 potions of constitution. These numbers of potions are easily found by any sufficient high lvl player, allowing him to create weapons much better than artifact weapons! The same will apply for rings, I fear. > Also, rings amulets and improved weapons are a good way to ge over the > race limitation on characteristic. If you make it too easy to create > improved rings, like ring (str+3)(for+3)(wis+3)(resist paralysis > +100)(resist fire +100)(resist cold +100) (resist electricity+100) Currently, this is also possible with weapons - except that resistances cannot be added to weapons. Having a method that allows one to create items that have +100 resistance against something would likely upset some others on this list, even if it would take 100 potions of resist something. > creating ring bringing XP? That's discussable, that mean in the end, > the xp can be bought :/ (buy rings, ingredients, modify some rings, > you got XP without getting in danger...). But that could be ok, > considering you can also do that reading books... And by buying alchemy ingredients and idetifying these. Or by summoning water and creating water of the wise or ... etc. There are many possibilities to gain XP (and even a huge lot of XP) without being in danger. It only requires money (and sometimes lots of money) to do so. > Robin Redeker wrote: > >today i've had some ideas about the jeweler skill: What if a jeweler > >could _change_ existing rings. For example he could improve a ring > >(resist acid+12) in to a ring (resist acid+30) or even acid+50? (not > >sure about this, does it break balancing?). You guys should read the messageboard ;) There have been many idea's about enhancing alchemy. The general consensus (there) is that alchemy currently is pretty boring. Perhaps it is worth considering if it is better to redo alchemy in general. That would include jewelery, but smithery, ... as well. If there is a general solution, it perhaps is less time consuming to revise alchemy in general and not only one skill. In the past (over a year ago) I've been writing a message containing a proposal - but this has never been sent. In fact, it is still in my draft box. I might even send it when requested (or even when not requested) Wim Villerius From elmex at ta-sa.org Fri Mar 24 05:30:10 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 12:30:10 +0100 Subject: [crossfire] Jeweler skill In-Reply-To: <1143198563.14079.38.camel@localhost.localdomain> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <1143198563.14079.38.camel@localhost.localdomain> Message-ID: <20060324113010.GA7999@elmex> On Fri, Mar 24, 2006 at 12:09:23PM +0100, Wim Villerius wrote: > 2*number of stat enchantment, so to make a weapon str+3, one needs 2+4+6 > = 12 potions of strength. Adding also a con requires 8 potions of > constitution. > These numbers of potions are easily found by any sufficient high lvl > player, allowing him to create weapons much better than artifact > weapons! > The same will apply for rings, I fear. Yes, indeed. But i don't think thats a bad thing? If one invested a lot of time into such a weapon, then that would be okay IMHO. > > Also, rings amulets and improved weapons are a good way to ge over the > > race limitation on characteristic. If you make it too easy to create > > improved rings, like ring (str+3)(for+3)(wis+3)(resist paralysis > > +100)(resist fire +100)(resist cold +100) (resist electricity+100) > Currently, this is also possible with weapons - except that resistances > cannot be added to weapons. > Having a method that allows one to create items that have +100 > resistance against something would likely upset some others on this > list, even if it would take 100 potions of resist something. One could agree on +90 is enough. And i was thinking of not so many potions to make a nice ring. Making it too hard to make nice things would reduce the usability of the skill to the level it is now... (which is a very unusable state IMHO). If it upsets people on this list, i would be happy to hear their arguments about it! > > Robin Redeker wrote: > > >today i've had some ideas about the jeweler skill: What if a jeweler > > >could _change_ existing rings. For example he could improve a ring > > >(resist acid+12) in to a ring (resist acid+30) or even acid+50? (not > > >sure about this, does it break balancing?). > You guys should read the messageboard ;) There have been many idea's > about enhancing alchemy. The general consensus (there) is that alchemy > currently is pretty boring. Yes! Imho the approach with static formular-lists doesn't scale very well. > In the past (over a year ago) I've been writing a message containing a > proposal - but this has never been sent. In fact, it is still in my > draft box. I might even send it when requested (or even when not > requested) Please do it :) Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From elmex at ta-sa.org Fri Mar 24 05:38:55 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 12:38:55 +0100 Subject: [crossfire] [Re] Jeweler skill In-Reply-To: <3fa509450603240304h4a677390x@mail.gmail.com> References: <3fa509450603240304h4a677390x@mail.gmail.com> Message-ID: <20060324113855.GB7999@elmex> On Fri, Mar 24, 2006 at 12:04:42PM +0100, Alberto S?ez Lodeiros wrote: > The jeweler skill can be use for some things like those: > > 1.- More Jeweler skill will allow the player to modify more powerfull > rings/amulets How should the 'power' be calculated? item_power? (if item_power, i would recommend item_power/2 or something similar fair) > 2.- The player can fail to apply the modification. With more Jeweler skill, > the player will fail less. To fail a modification can destroy or make a > cursed/bad ring/amulet > > 3.- If the player needs some "ingredients" to modify a ring, for example > [Ring+30Acid] + [Scroll of Resist Fire] + [10 Saphires] = > [Ring+30Acid+10Fire], then, with more skill at Jeweler, you will need less > Sapphires > Yes! Exactly my ideas! Scrolls are an even better idea, as some resistancies aren't aviable as potions... propably potions and scrolls... > 4.- Initially, you can only make simple rings. This is, you can only modify > rings in one aspect, for example, only adding one ressitance, +1 STR, > etc..., but if you level up, you will be allowed to make more complex > modifications, for expample, adding more than one resistance plus two or > more Stats or all you want. > * > And all this gives me a cool idea, but i dont know if its implementation is > hard or not. [...] Thats an good idea! But that requires more changes than i want to do at the moment. Propably after i implemented a plugin with points 1-3. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From cerzeo at gmail.com Fri Mar 24 06:41:36 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Fri, 24 Mar 2006 13:41:36 +0100 Subject: [crossfire] [Re] Jeweler skill In-Reply-To: <20060324113855.GB7999@elmex> References: <3fa509450603240304h4a677390x@mail.gmail.com> <20060324113855.GB7999@elmex> Message-ID: <3fa509450603240441j1d2acb9ch@mail.gmail.com> > > > 4.- Initially, you can only make simple rings. This is, you can only > modify > > rings in one aspect, for example, only adding one ressitance, +1 STR, > > etc..., but if you level up, you will be allowed to make more complex > > modifications, for expample, adding more than one resistance plus two or > > more Stats or all you want. > > * > > And all this gives me a cool idea, but i dont know if its implementation > is > > hard or not. > [...] > > Thats an good idea! But that requires more changes than i want to do at > the moment. Propably after i implemented a plugin with points 1-3. > > Robin If this is hard to implement, you can set this not for the amount of modifications at the same time. Low level jewelers can add only modifications to rings with less than 2 "enchantments" on it. If you level up jewelry, you will be allowed to add one modification to rings with more that one "enchantments" An example of this: I am level 1 jewelry and i have a "Ring(resist Acid +10)" then, i can only apply ONE modification, then i can add to that ring "resist Fire +10". When i reach level 4, i can add 2 modifications. I supose that we can add a number of modifications equals to our jewelry level divided per 2, and then, i can add another modification to my new "Ring(resist Acid +10)(resist Fire +10)" I think that 1 more modification for each 2 level is good enought. Maybe much good. Or you can set a maximun modifications to a fixed number, for example 10. Or you can also use the item power skill of the jeweler. I have to think about... -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060324/f56219a2/attachment-0001.htm From kaol at iki.fi Fri Mar 24 07:04:52 2006 From: kaol at iki.fi (Kari Pahula) Date: Fri, 24 Mar 2006 15:04:52 +0200 Subject: [crossfire] Changing maps from under a running server Message-ID: <20060324130452.GA10561@sammakko.yok.utu.fi> I tried replacing maps while the server was running, with less than spectacular results. I ended up with having all the exits leading to areas that were not in the server's memory to be closed. YMMV and you might end up with a less broken server state, but basically there are no guarantees currently about what will happen. One possibility to handle this is to open everything under maps/ on server startup and just give file descriptors from that pool to the server whenever it wants to read maps from there. The inodes will remain open until the file descriptors are closed and it'll be possible to replace or even remove altogether the maps while the server is running and the server won't notice a thing. This would make changing the mapsets happen smoothly. Still, there is a need to make the server use the new maps without restarting. As far as I can see there isn't really any way to transparently, reliably and automatically transfer players to the new mapset from the old one. The simplest thing to do would be to immediately teleport all the players to Scorn (or some other known place) and purge the old maps from memory and close the file handles. But that hardly would go well with players. An idea I got was to have a DM command (or something like that) which would insert an undroppable portal in all player's inventories. Activating that would remove the portal and teleport the player to the new mapset. The file descriptors of the old maps would be closed when the last player had used the portal. Perhaps the players could be made to gain no exp while on the expired maps to add an incentive to vacate them... But that's details. Any comments about this before I start writing a patch? Does this sound like a viable plan? It doesn't sound like the most trivial thing to implement... From alex_sch at telus.net Fri Mar 24 07:24:26 2006 From: alex_sch at telus.net (Alex Schultz) Date: Fri, 24 Mar 2006 06:24:26 -0700 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <20060324130452.GA10561@sammakko.yok.utu.fi> References: <20060324130452.GA10561@sammakko.yok.utu.fi> Message-ID: <4423F30A.1040606@telus.net> Kari Pahula wrote: >I tried replacing maps while the server was running, with less than >spectacular results. I ended up with having all the exits leading to >areas that were not in the server's memory to be closed. YMMV and you >might end up with a less broken server state, but basically there are >no guarantees currently about what will happen. > Note, you need to unload the maps before changing them, which can be done with the dm command, "reset". The reset command may sound like it reloads the map, but really it just unloads the maps, and it will be loaded at next attempt to use it. Alex Schultz From alex_sch at telus.net Fri Mar 24 07:50:57 2006 From: alex_sch at telus.net (Alex Schultz) Date: Fri, 24 Mar 2006 06:50:57 -0700 Subject: [crossfire] New map editor In-Reply-To: <20060324094645.GA7580@elmex> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> Message-ID: <4423F941.4070207@telus.net> Robin Redeker wrote: >Hi! > >I've read about following message: >http://mailman.metalforge.org/pipermail/crossfire/2005-August/009071.html > > Ahh, that SWIG bindings thing? Well, I was once looking at that, and eventually got it to build and was operating it (I was using python, but lava should have worked just as easily). However it seemed like and ugly hack, and I didn't see how it could be fixed to work a a clean manner off hand. >We are very open to improvements. And maybe someone could discuss the >problem with the order of map objects. The problem is, that if we load a >map in GCE and save it again, we get many changes in the order of the >objects. > Well, with GCE, there are a few main improvements that come to mind after looking at it. First of all, the pink color where you haven't placed tiles is IMHO a bit ugly, something like a pattern (lowish contrast) or a less vibrant color would work nicer. Secondly, there appears to be no way of listing archtypes by name, which in my opinion is an important feature. Also, I think it looks a bit weird in the 'stack view'. In my opinion, the "del" buttons should just be icon based buttons, and the items themself would look better without the 3d widgetness (listbox as opposed to series of buttons) Also, the toolbox looks a little ugly to me. In my opinion the item name should again not be in a button there. Also, the way you title the section "Pick" looks a little odd to me, and the grid for the actions above, seems to have a bit too much whitespace in the buttons to appeal to the eye. In addition, one thing that would in my opinion be a big bonus, is instead of hardcoding how it deals with different object types, reading it out of the same xml files that CFJavaEditor uses for that. That would make it much easier to deal with new item types in the future, and would also make effort to improve that, apply to both editors, causing less effort on both sides to be wasted. Alex Schultz Secondly From elmex at ta-sa.org Fri Mar 24 08:19:19 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 15:19:19 +0100 Subject: [crossfire] New map editor In-Reply-To: <4423F941.4070207@telus.net> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> <4423F941.4070207@telus.net> Message-ID: <20060324141919.GA8405@elmex> On Fri, Mar 24, 2006 at 06:50:57AM -0700, Alex Schultz wrote: > Robin Redeker wrote: > >We are very open to improvements. And maybe someone could discuss the > >problem with the order of map objects. The problem is, that if we load a > >map in GCE and save it again, we get many changes in the order of the > >objects. > > > Well, with GCE, there are a few main improvements that come to mind > after looking at it. > Secondly, there appears to be no way of listing archtypes by name, which > in my opinion is an important feature. Yes, this is already on the todo list. > [suggestions about theme] Well, Gtk2 is themable. It should be possible with a rc-file to change such things. But until the main _functionality_ is implemented and stable i won't put much efford in these aspects. > In addition, one thing that would in my opinion be a big bonus, is > instead of hardcoding how it deals with different object types, reading > it out of the same xml files that CFJavaEditor uses for that. That would > make it much easier to deal with new item types in the future, and would > also make effort to improve that, apply to both editors, causing less > effort on both sides to be wasted. We already use the XML file of the editor. We only added some attributes and stuff to it. And fixed some aspects. Our version of the xml file can be found in the CVS of the Crossfire module. Also for the different object types (in the placement tool) i use the data from the XML file to decide whether an object is a floor. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From tchize at myrealbox.com Fri Mar 24 08:36:22 2006 From: tchize at myrealbox.com (Tchize) Date: Fri, 24 Mar 2006 15:36:22 +0100 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <20060324130452.GA10561@sammakko.yok.utu.fi> References: <20060324130452.GA10561@sammakko.yok.utu.fi> Message-ID: <442403E6.4050809@myrealbox.com> Kari Pahula a ?crit : >I tried replacing maps while the server was running, with less than >spectacular results. I ended up with having all the exits leading to >areas that were not in the server's memory to be closed. YMMV and you >might end up with a less broken server state, but basically there are >no guarantees currently about what will happen. > > exit are marked closed if corresponding map is not loadable. If you removed some maps from server, the server would obviously not be able to load them. >One possibility to handle this is to open everything under maps/ on >server startup and just give file descriptors from that pool to the >server whenever it wants to read maps from there. The inodes will >remain open until the file descriptors are closed and it'll be >possible to replace or even remove altogether the maps while the >server is running and the server won't notice a thing. > > What's the point? If you load all maps inode at server startup you'll risk seriously to hit the maximum file decriptor / process limit of the os (there are lots of map files), not to mention the waste of memory (each file descriptor has quite a good amount of various os datas associated to it). >This would make changing the mapsets happen smoothly. Still, there is >a need to make the server use the new maps without restarting. > > If you keep inodes open, here is what will happen - on unix filesystems, you won't see the new versions of the files until the server is restarted (no gain compared to stop server, copy files, start server) - on windows filesystem you'll get error messages telling the files are in use. >As far as I can see there isn't really any way to transparently, >reliably and automatically transfer players to the new mapset from the >old one. The simplest thing to do would be to immediately teleport >all the players to Scorn (or some other known place) and purge the old >maps from memory and close the file handles. But that hardly would go >well with players. > > Even if it was possible to change all existing server maps in memory / cache with a new set, you'll race in other problems when map structures are changed, mainly of the type player's way back to surface closed. >An idea I got was to have a DM command (or something like that) which >would insert an undroppable portal in all player's inventories. >Activating that would remove the portal and teleport the player to the >new mapset. The file descriptors of the old maps would be closed when >the last player had used the portal. Perhaps the players could be >made to gain no exp while on the expired maps to add an incentive to >vacate them... But that's details. > > Player having to manually 'upgrade' their player? That's not something i would call 'transparent for player' >Any comments about this before I start writing a patch? Does this >sound like a viable plan? It doesn't sound like the most trivial >thing to implement... > > Not trivial, waste of time, prone to bugs, need and active action of player, os dependant, memory hungry If you implement this patch, take all necessary step to make it an activable option, considering the nightmare it can bring to a server owner. Other suggestion: just change the maploading process. Currently it does if (map in cache and not reset) load from cache else load from original file try this if (map in cache and map date >= original file dates and not reset) load from cache else load original file Ho and btw, i have always wanted to be able to define 'reset block' that is a set of map that reset together (to prevent entrance reset in quest, leading to 'help am stuck, i need a dm'), that might be usefull. >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > From alex_sch at telus.net Fri Mar 24 08:50:26 2006 From: alex_sch at telus.net (Alex Schultz) Date: Fri, 24 Mar 2006 07:50:26 -0700 Subject: [crossfire] New map editor In-Reply-To: <20060324141919.GA8405@elmex> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> <4423F941.4070207@telus.net> <20060324141919.GA8405@elmex> Message-ID: <44240732.6080501@telus.net> Robin Redeker wrote: >>[suggestions about theme] >> >> >Well, Gtk2 is themable. It should be possible with a rc-file to change >such things. But until the main _functionality_ is implemented and >stable i won't put much efford in these aspects. > > Well, much/most of that is choice of widgets, and can't really be fixed by an rc-file unless it's designed specifically for it (which imho is a bit of an ugly hack), and some parts (pink backing), likely can't be changed by that at all. Some time I might look at making some patches for some of these elements. Agreed, main functionality is more important than visuals. >>In addition, one thing that would in my opinion be a big bonus, is >>instead of hardcoding how it deals with different object types, reading >>it out of the same xml files that CFJavaEditor uses for that. That would >>make it much easier to deal with new item types in the future, and would >>also make effort to improve that, apply to both editors, causing less >>effort on both sides to be wasted. >> >> > >We already use the XML file of the editor. We only added some attributes >and stuff to it. And fixed some aspects. Our version of the xml file can >be found in the CVS of the Crossfire module. > >Also for the different object types (in the placement tool) i use the >data from the XML file to decide whether an object is a floor. > Ah, I was briefly looking through the cvs browser of your editor, and didn't notice this so I assumed it didn't use such xml files. Hmm, one thing I'm wondering is how CFJavaEditor would handle that modified xml file, if it would throw out extra data that it didn't need and still operate as normal. I might test that some time. Another thing I was thinking, is if there isn't already one, some sort of plugin system would be nice. Alex Schultz From elmex at ta-sa.org Fri Mar 24 09:58:14 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 16:58:14 +0100 Subject: [crossfire] New map editor In-Reply-To: <44240732.6080501@telus.net> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> <4423F941.4070207@telus.net> <20060324141919.GA8405@elmex> <44240732.6080501@telus.net> Message-ID: <20060324155814.GA8611@elmex> On Fri, Mar 24, 2006 at 07:50:26AM -0700, Alex Schultz wrote: > Robin Redeker wrote: > >We already use the XML file of the editor. We only added some attributes > >and stuff to it. And fixed some aspects. Our version of the xml file can > >be found in the CVS of the Crossfire module. > > > >Also for the different object types (in the placement tool) i use the > >data from the XML file to decide whether an object is a floor. > > > Ah, I was briefly looking through the cvs browser of your editor, and > didn't notice this so I assumed it didn't use such xml files. Hmm, one > thing I'm wondering is how CFJavaEditor would handle that modified xml > file, if it would throw out extra data that it didn't need and still > operate as normal. I might test that some time. I doubt that, we made pseudo-fields for attack_movement. Our map parser handles that attribute in a way that it splits that attribute into two attributes for displaying. And later merges them at saving. And as the Java editor doesn't handle move_type/move_block correct (not at all afaik) that wouldn't work either. > Another thing I was thinking, is if there isn't already one, some sort > of plugin system would be nice. Yes, something like this has been considered and is on the TODO. But it's more a version >=2.0 feature. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From elmex at ta-sa.org Fri Mar 24 10:00:20 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Fri, 24 Mar 2006 17:00:20 +0100 Subject: [crossfire] New map editor In-Reply-To: <44240732.6080501@telus.net> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> <4423F941.4070207@telus.net> <20060324141919.GA8405@elmex> <44240732.6080501@telus.net> Message-ID: <20060324160020.GB8611@elmex> On Fri, Mar 24, 2006 at 07:50:26AM -0700, Alex Schultz wrote: > Robin Redeker wrote: [...] > Ah, I was briefly looking through the cvs browser of your editor, and > didn't notice this so I assumed it didn't use such xml files. Hmm, one > thing I'm wondering is how CFJavaEditor would handle that modified xml > file, if it would throw out extra data that it didn't need and still > operate as normal. I might test that some time. > > Another thing I was thinking, is if there isn't already one, some sort > of plugin system would be nice. > Also the event connectors work a little bit different in crossfire+ (with the perl plugin). So this might not work too. But we will support reading old crossfire maps with events. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From kaol at iki.fi Fri Mar 24 11:09:54 2006 From: kaol at iki.fi (Kari Pahula) Date: Fri, 24 Mar 2006 19:09:54 +0200 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <442403E6.4050809@myrealbox.com> References: <20060324130452.GA10561@sammakko.yok.utu.fi> <442403E6.4050809@myrealbox.com> Message-ID: <20060324170954.GA12429@sammakko.yok.utu.fi> On Fri, Mar 24, 2006 at 03:36:22PM +0100, Tchize wrote: > Kari Pahula a ?crit : > >One possibility to handle this is to open everything under maps/ on > >server startup and just give file descriptors from that pool to the > >server whenever it wants to read maps from there. The inodes will > >remain open until the file descriptors are closed and it'll be > >possible to replace or even remove altogether the maps while the > >server is running and the server won't notice a thing. > > > > > What's the point? If you load all maps inode at server startup you'll > risk seriously to hit the maximum file decriptor / process limit of the > os (there are lots of map files), not to mention the waste of memory > (each file descriptor has quite a good amount of various os datas > associated to it). The point is to be able to install new maps while the server is running. But I can see that just opening everything is not that viable an option. A less intrusive alternative would be to install the maps to a maps/$versionnumber/ directory. That way two versions of the maps could coexist on disk and the server could take whatever steps necessary to get players on to the other mapsets. The debian-mentors mailing list was the first place I asked about how to handle map installs[1]. They thought that upgrading maps should be doable while the server was running. They went as far as to suggest to make upgrading the server possible without disconnecting players. Not a patch that I'd like to try to make. But I would be content to just put a large warning on the map packages in Debian that installing them will trigger a server restart. The current way of silently copying over the old maps with the new ones just seems too hazardous to me. Players may end up stranded who knows where with maps' pathnames changing and whatelse. [1] http://lists.debian.org/debian-mentors/2006/03/msg00319.html From mikeeusaa at yahoo.com Fri Mar 24 02:21:45 2006 From: mikeeusaa at yahoo.com (Miguel Ghobangieno) Date: Fri, 24 Mar 2006 00:21:45 -0800 (PST) Subject: [crossfire] Weather usability was: [Idea] Spells inmediate effects In-Reply-To: <442243AF.9060706@sonic.net> Message-ID: <20060324082145.97058.qmail@web32701.mail.mud.yahoo.com> Well eventually there will be a swim abillity IIRC. allow projectile would be better to be set. Would only need to set it on the water arches. --- Mark Wedel wrote: > Miguel Ghobangieno wrote: > > > Oh I'd like to beable to set it so arrows, bolts, > and > > shooting spells can traverse water. Could we have > new > > movement types: arrow(or projectile) etc. > projectile > > probably would be fine. I tried to do it my self > > hoping that the movement code used key value... :( > > It seems you are mixing two things here - the > movement type, and what can move > onto the space. > > Adding new movement types isn't hard, but the > blocking for many arches would > have to be updated. And I'm not sure that having > a whole bunch of movement > types is the correct approach (one problem that can > still happen even in that > model is someone creates an object that gives player > the projectile movement). > > To me, the right approach would be to add some new > flags - we already have > things like no magic, so extend that with things > like no_player and/or no_monster. > > > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com From fuchs.andy at gmail.com Fri Mar 24 14:27:55 2006 From: fuchs.andy at gmail.com (Andrew Fuchs) Date: Fri, 24 Mar 2006 15:27:55 -0500 Subject: [crossfire] [Re]Player Owned Shops In-Reply-To: <442102AA.7040709@sonic.net> References: <3fa509450603190327k55dc96c0y@mail.gmail.com> <441D50F0.8070809@myrealbox.com> <20060320033614.GA6767@elmex> <441F1D94.1090901@laposte.net> <20060321012820.GA2944@elmex> <442102AA.7040709@sonic.net> Message-ID: On 3/22/06, Mark Wedel wrote: > One thought that was expressed, but I don't ever think developed, was to have > these naturally occuring ingredients actually show up in the wild. > > Thus, on the world map, in the right places, you could find the various > vegetation. > > Likewise, in dungeons, there would be some means of of digging for the raw > elements. > > This doesn't completely fix the problem, but finding the basic ingredients > should probably be a lot easier than it is now. There is something like this in the weather code i think. (yet an other reason to fix it) As for in dungeons, new code will be needed, or maps would have to be modified, so some walls can be destroyed by a mining tool of some sort. > I think one problem is that if you play honestly, finding all the recipes > within the game is pretty darn hard. Even finding basic recipes seems pretty > hard. One fix might be to increase the amount of readable books that show up a > bit (you can do 20 levels of a dungeon and only get a few recipe books). > > One other problem, which I think was discussed, is that the formulae file only > has a basic 'diff' field to denote difficulty. These really should perhaps be > broken out a bit, like: > > success_chance: base chances of success, in percentage > success_increase: % increase/level above min_level your success goes up. > min_level: minimum level you need to be to have any chance of success > > Thus, you could have formula set up that requires you to be at least 5th > level, but once there, you can have a pretty good chance of success. Or you > could set up formula that even at 20th level, your chance is pretty low, and it > doesn't go up very fast. > > That could also make adjustment of the formula better. Two words: Dynamic Alchemy... If a quest should be required to create an object, the quest should probably include a rare ingredient or tool that is required to make the formulae. For example; a extremely rare metal ore, a spoon that doesn't melt or disolve when used to make some type of potion, or posibly a rare metal that is used to make a special tool used for a few recipies. -- Andrew Fuchs From alex_sch at telus.net Fri Mar 24 16:04:05 2006 From: alex_sch at telus.net (Alex Schultz) Date: Fri, 24 Mar 2006 15:04:05 -0700 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <20060324170954.GA12429@sammakko.yok.utu.fi> References: <20060324130452.GA10561@sammakko.yok.utu.fi> <442403E6.4050809@myrealbox.com> <20060324170954.GA12429@sammakko.yok.utu.fi> Message-ID: <44246CD5.4060301@telus.net> Kari Pahula wrote: >The debian-mentors mailing list was the first place I asked about how >to handle map installs[1]. They thought that upgrading maps should be >doable while the server was running. They went as far as to suggest >to make upgrading the server possible without disconnecting players. >Not a patch that I'd like to try to make. > Well, so long as the map gets unloaded first (i.e. the dm "reset" command), then upgrading the maps while the server is running, is perfectly possible. Though upgrading the server without disconnecting players seems a little far fetched. Perhaps they meant updating the server package, without loading the new one yet, wouldn't interrupt the existing running server (and indeed they should be right if that is what they meant) Alex Schultz From mwedel at sonic.net Sat Mar 25 00:51:23 2006 From: mwedel at sonic.net (Mark Wedel) Date: Fri, 24 Mar 2006 22:51:23 -0800 Subject: [crossfire] New map editor In-Reply-To: <20060324094645.GA7580@elmex> References: <20060323180703.GA5861@elmex> <20060324094645.GA7580@elmex> Message-ID: <4424E86B.80702@sonic.net> Robin Redeker wrote: > We are very open to improvements. And maybe someone could discuss the > problem with the order of map objects. The problem is, that if we load a > map in GCE and save it again, we get many changes in the order of the > objects. The only requirement is that the order the objects appear in is there stacking. Thus, if aboves (on the same space) show up as 'a, b, c', then a is at the bottom, c is at the top. When things are saved out, that order needs to be preserved - if you save as 'c, b, a', then objects c & b are going to disappear beneath the floor Now for fields within the object itself, there really isn't any required order. You can save 'sp xx, hp xx' or 'hp xx, sp xx', and it won't care. One thing it may care about is that the max_... values be before the values they refer. This is simply because there is some code that checks the sanity (OTOH, IIRC, that code isn't run until the object is fully loaded, so that order doesn't make a difference). So in this case, the only real importance in ordering the fields is trying to keep it the same to minimize the number of changes (so that only stuff that really changed shows up). The other standard behaviour is only fields that differ from the archetype are written out. So there is no reason to write out the hp values for all the monsters unless they are the same, for example. From mwedel at sonic.net Sat Mar 25 01:06:27 2006 From: mwedel at sonic.net (Mark Wedel) Date: Fri, 24 Mar 2006 23:06:27 -0800 Subject: [crossfire] Jeweler skill In-Reply-To: <20060324110804.GA7903@elmex> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <20060324110804.GA7903@elmex> Message-ID: <4424EBF3.9000602@sonic.net> My personal thoughts would be something like this: Some combination of ingredients allows you to attempt to improve a ring. Some of the ingredients should be rare, as otherwise you'll just have pile of powerful rings. You can only increase on step at a time (+1 stat, +3% resistance, etc). You can't go from a ring fire res +10 to ring fire rest +30 in one step - it would take many. this also increases cost a bit. IMO, just require 1 potion with many rubies (or other gems) with the gems being how much it is improved is way too weak. Even moderate level (~15) players have hundreds, perhaps thousands, of gems, or can get them easily. IF gems are going to be the increase factor, they probably need to be the extraordinary value/flawless beauty type. Each time you increase the object, the item_power goes up (maybe give 5% resistance improvement, with a cap at 50% or 75%?) Success chance should probably be based on current item power, or what you are enchanting it to. I know as a player, I often find those resistance potions and don't have much use for them. Being able to use one to increase an items protection by 5% would be cool in terms of having some use. It may make sense to unify all the improvement code, so the same rules apply to weapons as it does for rings, armor, etc. That said, only certainly things could be done to weapons, only certain things to armor, etc another random thought - could be interesting to have something (100 gems of flawless beauty or other really high price) that would let a player decrease item power by 1 for an object? Expensive enough that it would actually be cause for players to spend gobs of money. Thus, long term, really rich players, could really have the best objects in the game (I have my +75 fire/cold/electricity/etc ring). From mwedel at sonic.net Sat Mar 25 01:18:31 2006 From: mwedel at sonic.net (Mark Wedel) Date: Fri, 24 Mar 2006 23:18:31 -0800 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <20060324130452.GA10561@sammakko.yok.utu.fi> References: <20060324130452.GA10561@sammakko.yok.utu.fi> Message-ID: <4424EEC7.1050802@sonic.net> A lot of this depends on the changes to the maps in questions. In lots of cases, updating the maps won't cause any problem - the new maps might have new exits, but those not being available until reloaded isn't a problem. The only time I can see it being a problem when map files are renamed, such that the exit of a map currently in memory doesn't go to the right destination. That doesn't happen that frequently. However, even in that case, a simple solution would be to load a copy of the new map, see if there is an exit at/near the exit we are trying to use, and use the destination for that. IF there are major changes to maps, there really isn't a very good solution, other than the idea of mapsets as tchize mentions. But in that case, the server would have to load all the maps of a mapset (or at least make a copy of them), as otherwise you could still get the case that player enters map A, explores around, map is changed such that exit to map B now puts him in solid rock, etc The idea of a secondary (new maps) directory would work, but also has the same issues as above, and you can't necessarily copy over new maps just one one resets locally because there may be dependencies. Note also there are other issues. New maps may have new archetypes, which exist in the latest server, but perhaps not in memory of the running server. So you now get the case of needing a mechanism to read in new archetypes, images, treasurelists, etc. All in all, seems a lot simpler to just restart the server than try to sort all of this out. From mwedel at sonic.net Sat Mar 25 03:00:59 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sat, 25 Mar 2006 01:00:59 -0800 Subject: [crossfire] Protocol & compression. Message-ID: <442506CB.6020701@sonic.net> On the mailing list, irc, and elsewhere discussion came up about rather than trying to be too clever about minimize bandwidth with things like animations to just compress the data itself, as that keeps things simpler. Alex ran some quick tests, getting ~40% compression rate on big map payloads. However, that was client side, so I quickly hacked the server to do some compression on map packets (map1a). This way, I could also time how long it takes to do the compression (running on an athlon mp 2000 here). General notes - small map packets are not worth compressing. The cut off to be worth while is probably around 200 bytes. For a big map transfer, in this case, leaving the scorn apartment building with a 25x25 map in dm mode (so everything is visible), zlib compressed 3034 bytes to 1637 (47%) in 952 ?sec. bz2 didn't do quite so good (1818) in 2113 ?sec The other case I quickly tested was standing at the far north end of scorn (still in DM mode) to get a lot of ocean spaces. In this case, zlib compressed 806 bytes to 270 bytes (67%) in 505 ?sec. bz2 compressed it to 245 in 408 ?sec. Note that 1000 ?sec = 1 ms, and by default, there is 120 ms/game tick. So spending a few milliseconds on compression doesn't seem to likely add much to the load (get enough players it adds up, but then so does the overall bandwidth compression). I'm personally think zlib is better in this case, as it is faster, and for big data, is smaller, and the interface is simpler. For other reasons, I still think I'll add animation support to the map2 command. However, I think it also worthwhile to add something like: S->C: compress Where data is the block of compressed data. The length of data can be determined from the packet header (a shorter command, like comp or something could be done). would get uncompressed on the client, and just contain normal protocol commands that the client then processes. By abstracting at a higher level, it allows us to compress any other protocol commands (think itemcmd for a large inventory. Or it would involve more work, but a long list of drawinfos, like from a shop listing). Thoughts/comments? On the server, this is pretty simple to do (simplest would be to add another parameter to send_with_handling on whether to compress the data) (some data, like png images, aren't worth trying to compress). For the client, it is more complicated, because you could have something like 'command; compressed data; command;' - right now, it justs uses a larger ring buffer IIRC. We don't want to have to move all the data beyond our compressed ata back - I suppose that since it is a ring buffer, we could backtrack the buffer to insert the uncompressed data. Or use a few buffers. From bofh-lists-crossfire-dev at diegeekdie.com Sat Mar 25 03:51:55 2006 From: bofh-lists-crossfire-dev at diegeekdie.com (Sebastian Andersson) Date: Sat, 25 Mar 2006 10:51:55 +0100 Subject: [crossfire] Protocol & compression. In-Reply-To: <442506CB.6020701@sonic.net> References: <442506CB.6020701@sonic.net> Message-ID: <20060325095155.GA11407@hogia.net> On Sat, Mar 25, 2006 at 01:00:59AM -0800, Mark Wedel wrote: > For other reasons, I still think I'll add animation support to the map2 > command. However, I think it also worthwhile to add something like: > > S->C: compress I've got some experience in this, having implemented it in a mud (DUMII) and I suggest a different approach. Have the zlib stream as a layer between the socket and the server/client when it is turned on and start it like this: C->S: start_compression S->C: compression_started The server now starts to compress everything sent to the client in a layer below the output writing and the socket and after the client has read "compression_started", it starts to decompress everything via zlib, it becomes a layer below the normal send(2) on the server and below the normal read(2) on the client. To get things actually out of the zlib stream, one of course has to call it with Z_SYNC_FLUSH. Doing that too often (like after every single command) makes the compression rate much lower than it can be. In DUMII we had already solved it when we added compression, since we had previously added support for linux' TCP_CORK flag and later the MSG_MORE flag (to avoid sending out tiny TCP packets). We did it by adding a flag to each connection, let's call it NeedsFlush. Every time something is sent to a client, the NeedsFlush flag is set. Every time the expired timers or a player command has been processed, we scan all connections to see which connections has that flag and those that have are flushed (calling deflate with Z_SYNC_FLUSH and the final send(2) is called without the MSG_MORE flag set) and the NeedsFlush flag is reset. For really tiny packets (the mud's 4 octet prompt for example), they become somewhat larger, but that doesn't matter much since the TCP packet header is so large and it is really rare that a single, short packet has to be flushed (the player just pressing return without supplying a command is one use-case, but that doesn't happen often), often many tiny packets are compressed together and the resulting packet is much smaller. I guess this could be done with the crossfire server too, without too much difficulty. The suggested compresion of selected packets and doing them packet by packet, sounds like a bad solution to me since then common combinations can't be compressed (and of course more overhead is added by the "compress" prefix). If the connection seems more laggy, one can add some counters, so a flush is also performed after X compressed bytes, but I doubt it is needed, since zlib can uncompress bytes even without comming to a synchronisation point. It is probably better to use a smaller MTU in those cases (either by using ioctls on the sockets on those OSes where that is possible, or by simulating it by sending smaller packets and not using Nagle's algorithm). But I doubt that will matter much and it will not make things worse than they are without compression anyway. Regards, /Sebastian -- .oooO o,o Oooo. Ad: http://dum.acc.umu.se/ ( ) \_/ ( ) (o_ "Life is not fair, but root \ ( /|\ ) / (o_ //\ password helps!" -- The BOFH \_) (_/ (/)_ V_/_ From elmex at ta-sa.org Sat Mar 25 07:13:34 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Sat, 25 Mar 2006 14:13:34 +0100 Subject: [crossfire] Jeweler skill In-Reply-To: <4424EBF3.9000602@sonic.net> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <20060324110804.GA7903@elmex> <4424EBF3.9000602@sonic.net> Message-ID: <20060325131334.GA1587@elmex> On Fri, Mar 24, 2006 at 11:06:27PM -0800, Mark Wedel wrote: > > My personal thoughts would be something like this: > > Some combination of ingredients allows you to attempt to improve a ring. Some > of the ingredients should be rare, as otherwise you'll just have pile of > powerful rings. Yes, that should really not be the case... But that should also be prevented with the code that checks the success chance (with item_power). Also: Low level chars shouldn't have enough money to make _really_ powerful rings. Eg. rings like Elrond should only be able to make with a success chance of 100% around level 80 of jewelery and really really a lot of money. I don't like the idea with _rare_ ingredients, as this makes the current jeweler skill completly unused. How hard it is to make a ring should IMHO only limited by the jeweler level. That the jeweler doesn't only gain exp by his skill should be limited by the fact that he needs lots of money to work. And thus he has to go out and search money. And money isn't that easy to gather (or at least is shoud not be very easy). One other thing i want to take care of, is that stuff a jeweler produces propably shouldn't be more worth than the ingredients (i guess this is obvious). So that the jeweler can't make money only with jewelery. I want to make the jeweler skill also usable by low level chars, who aren't able to get for example a gaelotroll's liver to for example raise the acid resistancy. He should be able to go with the potion he found and some big gems. > > You can only increase on step at a time (+1 stat, +3% resistance, etc). You > can't go from a ring fire res +10 to ring fire rest +30 in one step - it would > take many. this also increases cost a bit. Yes, thats a good idea, it would slow down creation of really strong stuff. > IMO, just require 1 potion with > many rubies (or other gems) with the gems being how much it is improved is way > too weak. Even moderate level (~15) players have hundreds, perhaps thousands, > of gems, or can get them easily. IF gems are going to be the increase factor, > they probably need to be the extraordinary value/flawless beauty type. Yes! I also thought about that. Propably only the _big_ gems of a certain quality can increase the power of the ring. Eg. 1 ruby of great value can raise a resistance by 1%, exceptional bauty by 2% and flawless beauty by 5%. (all with combination of a potion). > > Each time you increase the object, the item_power goes up (maybe give 5% > resistance improvement, with a cap at 50% or 75%?) > > Success chance should probably be based on current item power, or what you are > enchanting it to. Yes, i wanted to use the calc_item_power function in common/item.c to recalc the item_power of the resulting ring. And then something like item_power * x == jeweler level gives 50% chance of success. (Either i use calc_item_power or some self craftet function to calc the improvement 'level' of the ring) Also setting a cap is maybe really better... but i want to be able to make a ring of halvor with +100 resistancy. Makeing a ring with one resistancy +100 with sucess chance of 100% should at least take level 12 jeweler skill and really a lot of big gems, something around 1000 flawless beauty gems, and at least 100 potion (or similar). Making a ring with 2 or 3 resistancies +100 would require at least something like level 30-50 jewelery. And this should be quite hard to become... and even if a char has such a jewelery level: thats completly find IMHO he put lots of efford in it and should be rewarded for that. Also: I haven't found so many flawless beauty gems while playing yet. Propably 1000 is even too much to be reachable anyhow. > > I know as a player, I often find those resistance potions and don't have much > use for them. Being able to use one to increase an items protection by 5% would > be cool in terms of having some use. Yes! > > It may make sense to unify all the improvement code, so the same rules apply > to weapons as it does for rings, armor, etc. That said, only certainly things > could be done to weapons, only certain things to armor, etc I thought about combining skills. Eg. smithery and jewelery to raise armours resistancies... but well... first i want to get jewelery right. > > another random thought - could be interesting to have something (100 gems of > flawless beauty or other really high price) that would let a player decrease > item power by 1 for an object? Expensive enough that it would actually be cause > for players to spend gobs of money. Thus, long term, really rich players, could > really have the best objects in the game (I have my +75 > fire/cold/electricity/etc ring). Hm, lowering the item power of an object would some kind of disable the item power checking code. IMHO the item power shouldn't be something that can be lowered. Then we have people running around with ruggillys whisker whielded and giving them to low level chars propably... The game will quickly reach a level where everyone wears 2 rings of elrond. And after that, they propably give low level chars these rings... But ok, 100 flawless beauty diamonds are really hard to get, it will really take lots of time... Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From alex_sch at telus.net Sat Mar 25 22:33:30 2006 From: alex_sch at telus.net (Alex Schultz) Date: Sat, 25 Mar 2006 21:33:30 -0700 Subject: [crossfire] Protocol & compression. In-Reply-To: <442506CB.6020701@sonic.net> References: <442506CB.6020701@sonic.net> Message-ID: <4426199A.5020106@telus.net> Mark Wedel wrote: > General notes - small map packets are not worth compressing. The cut off to >be worth while is probably around 200 bytes. > > One note, usually, map packets are larger than that unless they are animation ones. > > Note that 1000 ?sec = 1 ms, and by default, there is 120 ms/game tick. So >spending a few milliseconds on compression doesn't seem to likely add much to >the load (get enough players it adds up, but then so does the overall bandwidth >compression). > > Perhaps system load could be measured in determining what threshold of what packet size should be before it is compressed, with a hard minimum size set as well (so, if the system load gets high, only compress the REALLY big packets, which should be rarer). This isn't the simplest to implement, but perhaps if reading the system load directly doesn't work well, perhaps measuring how close the ticks are to actually hitting 120 ms/game tick, and if they start taking too long, then scale the compression to back to be used on fewer packets. Neither of these methods is the easiest ways to do it, but IMHO it would be the 'smartest' way to do it. > I'm personally think zlib is better in this case, as it is faster, and for big >data, is smaller, and the interface is simpler. > > Agreed. > For other reasons, I still think I'll add animation support to the map2 >command. > Also note, one thing that would be interesting, would be how much the map2 command differs, in terms of how well it will compress. >However, I think it also worthwhile to add something like: > >S->C: compress > > Where data is the block of compressed data. The length of data can be >determined from the packet header (a shorter command, like comp or something >could be done). > > would get uncompressed on the client, and just contain normal protocol >commands that the client then processes. By abstracting at a higher level, it >allows us to compress any other protocol commands (think itemcmd for a large >inventory. Or it would involve more work, but a long list of drawinfos, like >from a shop listing). > > This makes sense to me. Perhaps the server should compress automatically for ALL packet types where the packet is big enough unless: 1) Otherwise flagged (png data) 2) Server load is becoming too high (perhaps measure by measuring the actual number of ms between ticks). Alex Schultz From mwedel at sonic.net Sat Mar 25 23:42:48 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sat, 25 Mar 2006 21:42:48 -0800 Subject: [crossfire] Jeweler skill In-Reply-To: <20060325131334.GA1587@elmex> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <20060324110804.GA7903@elmex> <4424EBF3.9000602@sonic.net> <20060325131334.GA1587@elmex> Message-ID: <442629D8.20906@sonic.net> Robin Redeker wrote: > On Fri, Mar 24, 2006 at 11:06:27PM -0800, Mark Wedel wrote: >> My personal thoughts would be something like this: >> >> Some combination of ingredients allows you to attempt to improve a ring. Some >> of the ingredients should be rare, as otherwise you'll just have pile of >> powerful rings. > > Yes, that should really not be the case... But that should also be > prevented with the code that checks the success chance (with > item_power). Also: Low level chars shouldn't have enough money to > make _really_ powerful rings. Eg. rings like Elrond should only be able > to make with a success chance of 100% around level 80 of jewelery and > really really a lot of money. Yes - powerful rings should require high level of the skill. > > I don't like the idea with _rare_ ingredients, as this makes the current > jeweler skill completly unused. How hard it is to make a ring should > IMHO only limited by the jeweler level. I don't know if I really agree with that we are talking magical objects here. If all the player wants to do is make ring of adornments, sure, normal items should be all that needed. One thought is sort of a hybrid approach - for lower power rings, don't need very rare objects (just like scrolls up to 15%). However, if you want to make rings of a certain power, then rare and hard to find items are required. > > That the jeweler doesn't only gain exp by his skill should be limited by > the fact that he needs lots of money to work. And thus he has to go out > and search money. And money isn't that easy to gather (or at least is > shoud not be very easy). From what I've gathered on the mailing list, large amounts of money isn't that hard to get at some point. But more important here is really balance. If jeweler and the related skills are the best way to make powerful objects, what will happen is players will have multiple characters - their adventurer, and their jeweler who never leaves town - the adventurer provides all the money that the jeweler needs (granted, you could do this is in one character, but if the jeweler never leaves town, don't have to worry about him dying). But the real point is figure that in not too long a time, there will be high level jewelers, armorers, etc, about. And if they can make suprerior items than what is out there, they will do so. > > One other thing i want to take care of, is that stuff a jeweler produces > propably shouldn't be more worth than the ingredients (i guess this is > obvious). So that the jeweler can't make money only with jewelery. that wouldn't be hard to do. > > I want to make the jeweler skill also usable by low level chars, who > aren't able to get for example a gaelotroll's liver to for example raise > the acid resistancy. He should be able to go with the potion he found > and some big gems. the idea of different combinations for different powers I mention above might work. Low level jewelers can make low power rings with easy to find ingredients, high level objects require hard to find stuff. My real point here is don't really on scarcity of money as a controller factor, as that won't work - right now, at a relatively low level, you just start accumulating huge piles of money because there is nothing to spend it on. >> Each time you increase the object, the item_power goes up (maybe give 5% >> resistance improvement, with a cap at 50% or 75%?) >> >> Success chance should probably be based on current item power, or what you are >> enchanting it to. > > Yes, i wanted to use the calc_item_power function in common/item.c to > recalc the item_power of the resulting ring. And then something like > item_power * x == jeweler level gives 50% chance of success. Note that calc_item_power() isn't a great function - certain objects have too low or too high item power value from the formula it uses. It was put in place to update items that didn't have anything. It could probably be refined, but one issue is that not all resistances are equal. Protection fire +50 is a lot more useful than protection slow +50 as a simple example. You are likely to get cases wher calc_item_power() may return a value lower than that which the ring has right now, or return something way higher, depending on the object the player is trying to improve. While increasing item power by 1 for each enchanment may not match up with the formula, it does at least mean you start from the proper baseline. > Also setting a cap is maybe really better... but i want to be able > to make a ring of halvor with +100 resistancy. > Makeing a ring with one resistancy +100 with sucess chance of 100% > should at least take level 12 jeweler skill and really a lot of > big gems, something around 1000 flawless beauty gems, and at least 100 > potion (or similar). Simply put, it should not be possible to make a ring that gives 100% protection to damage attacktypes (effect attacktypes like confusion, slow, paralyze is OK). When the resistance code was redone, it was decided that 100% protection would no longer be allowed to attacktypes - before, it was possible to kill things like big dragons without taking any damage). Even the potions, which only give a temporary resitance and IIRC are the best way to get resistance from attacktypes, I think at best give you 95%. I'd argue it should take at least a level 50 jeweler to make an item with a single 90% resistance > Making a ring with 2 or 3 resistancies +100 would require at least > something like level 30-50 jewelery. And this should be quite hard to > become... and even if a char has such a jewelery level: thats completly > find IMHO he put lots of efford in it and should be rewarded for that. As said, 100% resistance should not be allowed. > > Also: I haven't found so many flawless beauty gems while playing yet. > Propably 1000 is even too much to be reachable anyhow. It may depend - if they had more use, other than money, people might also look for them more. From mwedel at sonic.net Sun Mar 26 00:02:56 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sat, 25 Mar 2006 22:02:56 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <20060325095155.GA11407@hogia.net> References: <442506CB.6020701@sonic.net> <20060325095155.GA11407@hogia.net> Message-ID: <44262E90.9080507@sonic.net> Sebastian Andersson wrote: > On Sat, Mar 25, 2006 at 01:00:59AM -0800, Mark Wedel wrote: >> For other reasons, I still think I'll add animation support to the map2 >> command. However, I think it also worthwhile to add something like: >> >> S->C: compress > > I've got some experience in this, having implemented it in a mud > (DUMII) and I suggest a different approach. Have the zlib stream as a > layer between the socket and the server/client when it is turned on > and start it like this: There are a few likely differences which may or may not effect crossfire in different ways: 1) Some data crossfire sends is just not compressible. The PNG data comes to mind - trying to compress it is at best a waste of time, and at worse, increases amount of data being transmitted. The other problem related to this is you'll often need to send a bunch of image data at one time (player changes to new map), and now there is lots of data you are trying to compress - the time it takes to compress that much data could become significant. 2) Latency is a big concern in crossfire, so we really can't add any. This means that for each and every tick, we need to make sure we send all the data we have - in lots of cases, this is going to be small data that doesn't compress well, so once again, a waste of cpu time (while this may seem trivial, there are certainly times when the server does become cpu bound) 3) The fact that crossfire does queue up data would allow for compressing at a higher level (basically, not have send_with_handling actually send data, but queue it up, and then at the end of the tick, compress the data). In that way, we can combine several small commands into a larger packet, but still not spend time compressing non compressible data. But doing that adds a fair amount of complication - a complete re-write of the socket code would probably be needed to reasonable support that. while adding a 'compress' prefix (it could be shortened to just gz, so now only adding a few bytes), by selectively compressing the big payloads is a very easy mechanism to do right now without any real downsides. From mwedel at sonic.net Sun Mar 26 00:21:58 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sat, 25 Mar 2006 22:21:58 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <4426199A.5020106@telus.net> References: <442506CB.6020701@sonic.net> <4426199A.5020106@telus.net> Message-ID: <44263306.8030708@sonic.net> Alex Schultz wrote: > Mark Wedel wrote: > >> General notes - small map packets are not worth compressing. The cut off to >> be worth while is probably around 200 bytes. >> >> > One note, usually, map packets are larger than that unless they are > animation ones. Depends - I see lots of small packets. If your just standing around in one place, the only thing being sent are the animations, which can be pretty small. I'd also imagine that if you are moving around on a dark map with only a few spaces visible, you'll get pretty small packets. > Perhaps system load could be measured in determining what threshold of > what packet size should be before it is compressed, with a hard minimum > size set as well (so, if the system load gets high, only compress the > REALLY big packets, which should be rarer). This isn't the simplest to > implement, but perhaps if reading the system load directly doesn't work > well, perhaps measuring how close the ticks are to actually hitting 120 > ms/game tick, and if they start taking too long, then scale the > compression to back to be used on fewer packets. > Neither of these methods is the easiest ways to do it, but IMHO it would > be the 'smartest' way to do it. measuring ms would be the way to go. System load is meaningless on multi processor systems (and with dual core cpus, those are becoming more an more common). does a 1.0 load average mean that the crossfire server is using all the cpu time, or does it mean some other program is just caught in an infinite loop and crossfire in fact isn't spending much time at all. However, if we were going to go down the idea of adapting what the server does base on available time, there are lots of other things. Don't swap out maps if busy. Put off for a few ticks the routine stuff (in do_specials()). But that also starts getting more complicated - some players may not care much about compression but don't mind using it to help reduce server bandwidth, etc. Yet others on low bandwidth connections really want that compression - this could lead to things like clients saying how badly they want compression. Not sure if that complication is worth it. The other problem I think with that approach is that the bigger the packet, the longer it takes to compress. but the biggest issue is this scenario - player changes maps - loading this new map takes time, so server is now short on time. Yet because player is changing maps, a lot of map data is changing, so that is the packet you want to compress. >> S->C: compress >> >> Where data is the block of compressed data. The length of data can be >> determined from the packet header (a shorter command, like comp or something >> could be done). >> >> would get uncompressed on the client, and just contain normal protocol >> commands that the client then processes. By abstracting at a higher level, it >> allows us to compress any other protocol commands (think itemcmd for a large >> inventory. Or it would involve more work, but a long list of drawinfos, like >>from a shop listing). >> >> > This makes sense to me. Perhaps the server should compress automatically > for ALL packet types where the packet is big enough unless: > 1) Otherwise flagged (png data) Well, my thinking was the send_with_handling() will be passed a flag on whether to compress or not. Note that compression also has to be negotiated by the client, so the flag would really be 'if this is set, this is compressible data'. send_with_handling() would still see if it meets minimum size, if the client supports compression, etc. > 2) Server load is becoming too high (perhaps measure by measuring the > actual number of ms between ticks). Maybe, but as mentioned above, if we're going to do that, there is probably lots of code to look at within the server for 'should we do this, should we do that' type of logic which doesn't currently exist. From bofh-lists-crossfire-dev at diegeekdie.com Sun Mar 26 05:08:55 2006 From: bofh-lists-crossfire-dev at diegeekdie.com (Sebastian Andersson) Date: Sun, 26 Mar 2006 13:08:55 +0200 Subject: [crossfire] Protocol & compression. In-Reply-To: <44262E90.9080507@sonic.net> References: <442506CB.6020701@sonic.net> <20060325095155.GA11407@hogia.net> <44262E90.9080507@sonic.net> Message-ID: <20060326110855.GA25148@hogia.net> On Sat, Mar 25, 2006 at 10:02:56PM -0800, Mark Wedel wrote: > There are a few likely differences which may or may not effect crossfire in > different ways: > > 1) Some data crossfire sends is just not compressible. The PNG data comes to > mind - trying to compress it is at best a waste of time, and at worse, increases > amount of data being transmitted. The other problem related to this is you'll I've found PNG data to be compressable with zlib. At least if many images are sent one after another. Perhaps there is a bug in the 1.6 server, but many of the image2 commands sent contained hundreds of identical octets in a row, clearly compressable on their own. I hacked together a test program, which is included, that analyses strace output from the client. Please don't look at the code ;-). Compile it with: g++ -Wall -O3 -lz comptest.c -o comptest (only tested on linux with g++-4.0, might work elsewhere too with other compilers :-). I played a short while against a 1.6 server (running to the slave mines and throwing some comets around me, then word of recalled me back home, prayed and quit), while running the gcfclient with strace: strace -o log -s 4096 -esocket,read gcfclient -nocache (I used gcfclient 1.9.0, from the debian distribution). I then postprecessed the log file, by removing everything before the read(6, "\0#") and everything after read(6, ...) = 0 and removing all the lines that doesn't contain "read(6,". (the comptest program should really do that, but currently it doesn't). The comptest program will read that file, reconstruct the data from the read statements and send them through zlib. Each time the client didn't get anything to read (read returned EAGAIN), the test program flushes the zlib stream. This is to simulate my suggestion of trying to pack more than one command together into a "chunk". The program will output a file like this: READING: 107 WRITING: 786 CHUNK_TIME: 2.393000ms CHUNK IN: 2637 CHUNK OUT: 786 CHUNK RATIO: 3.354962 CHUNK SAVED: 1851 where READING is for every time it reads something from the log file (the number is the number of bytes). WRITING when the zstream has some output to write. CHUNK TIME, how long clock time that chunk took to process, not really reliable. CHUNK IN, number of bytes to write before compression. CHUNK OUT, number of bytes after compressiom. CHUNK RATIO, in/out CHUNK SAVED, in-out At the end the totals are given: ./comptest < log | tail -4 Total in: 795KB Total out: 310KB Ratio: 2.561391 Saved: 485KB This was with all default values, they are described later. Changing the code to call: setvbuf(stdout, NULL, _IONBF, 0); and running it with ltrace -T -e deflate seems like a better way to get a feeling for the overhead of zlib, but I've not done that more than to visualy see some values: 0.065ms for compresing 2 bytes, became 8 bytes. 0.324 + 0.091 bytes for compressing 555 bytes, they became became 318 bytes. Around 0.4ms to compress 29763 bytes into 10000 bytes. The program takes three optional arguments: * compression output buffer size, default 1024, its a tradeoff between per packet lag and TCP header overhead of course. * compression level 1..9, default 5, higher compresses more. * overhead per compression write, default 0 If overhead is given, then the system will add that overhead to each compressed writing and it will not compress data that is less than 16 bytes long. This is not totaly correct of course, the real compression overhead (both in bytes and in CPU time) would be larger if one would flush after each command. Anyway, the result was that with an overhead of just 4 bytes (ie two length bytes + "gz"), the result was that 447KB was saved, instead of the 485KB when everything was compressed (8% less). On the other hand, 15% less CPU was used for the whole program, measured with time and just counting the "user time" (~170ms vs ~200ms). (The CPU used was an AMD Athlon(TM) XP 2400+; 2GHz, 256KB cache, ~4k bogomips on linux-2.6.15) I did some other quick measurements with time over the whole file. With compression level 9, the run time was twice as long, but it only saved 5KB more. With compression level 1, the run time was 10% less and the output was 27KB larger (6% more) than at level 5. > often need to send a bunch of image data at one time (player changes to new > map), and now there is lots of data you are trying to compress - the time it > takes to compress that much data could become significant. So is receiving uncompressed data if you've got a slow link and need compression. When measuring lag to modem users, they usualy have less lag when compression is turned on because of the increased bandwidth. With crossfire, the same might be experienced for 64-128kbps connections. /Sebastian -- .oooO o,o Oooo. Ad: http://dum.acc.umu.se/ ( ) \_/ ( ) (o_ "Life is not fair, but root \ ( /|\ ) / (o_ //\ password helps!" -- The BOFH \_) (_/ (/)_ V_/_ -------------- next part -------------- A non-text attachment was scrubbed... Name: comptest.c Type: text/x-csrc Size: 7503 bytes Desc: not available Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060326/2fd4c895/attachment-0001.c From elmex at ta-sa.org Sun Mar 26 09:35:40 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Sun, 26 Mar 2006 17:35:40 +0200 Subject: [crossfire] Jeweler skill In-Reply-To: <442629D8.20906@sonic.net> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <20060324110804.GA7903@elmex> <4424EBF3.9000602@sonic.net> <20060325131334.GA1587@elmex> <442629D8.20906@sonic.net> Message-ID: <20060326153540.GA1833@elmex> On Sat, Mar 25, 2006 at 09:42:48PM -0800, Mark Wedel wrote: > Robin Redeker wrote: > > On Fri, Mar 24, 2006 at 11:06:27PM -0800, Mark Wedel wrote: > > > > I don't like the idea with _rare_ ingredients, as this makes the current > > jeweler skill completly unused. How hard it is to make a ring should > > IMHO only limited by the jeweler level. > > I don't know if I really agree with that we are talking magical objects here. > If all the player wants to do is make ring of adornments, sure, normal items > should be all that needed. > > One thought is sort of a hybrid approach - for lower power rings, don't need > very rare objects (just like scrolls up to 15%). However, if you want to make > rings of a certain power, then rare and hard to find items are required. I've discussed now a different approach. First, i think you were right with 95% max resistancy. Thats indeed reasonable. But what about resistancies like paralyze, slow, drain, depletion? Couldn't there be +100 allowed? But another idea came in discussion with someone else: As the problem with these creating-skills is, that items in crossfire stay until the player enters quit and his appartment and his inventory is deleted, or he drops the item on a map which gets resetted. So with the jeweler skill in place the flood of god-like-rings has to be prevented. (Also smithery has similar problem propably? What about weapon improvement?) What if rings would wear off with time. Then one has to use the jeweler skill to fix their rings. And then no rare items are needed to prevent the game from overflowing of powerful rings. This would also put the piles of money in the player appartments to more use. The advantage of rings vs. potions, which would be both temporary with wearoff on rings, is that rings last longer... Propably rings would only loose 1% resistancy at some fixed interval (an hour?). It would maybe be okay that only self-made rings would wear off... Then the artifact rings would still have some reason to exist. > > But the real point is figure that in not too long a time, there will be high > level jewelers, armorers, etc, about. And if they can make suprerior items than > what is out there, they will do so. Out there are rings with +100. > Note that calc_item_power() isn't a great function - certain objects have too > low or too high item power value from the formula it uses. It was put in place > to update items that didn't have anything. > I've written my own function now. That takes into account that resistnacies like slow+50 are less useful than fire+50. It's much better for calculating the level the jeweler needs to produce a ring, and it works similar to calc_item_power in some places. Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker From tchize at myrealbox.com Sun Mar 26 12:16:34 2006 From: tchize at myrealbox.com (tchize) Date: Sun, 26 Mar 2006 20:16:34 +0200 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <4424EEC7.1050802@sonic.net> References: <20060324130452.GA10561@sammakko.yok.utu.fi> <4424EEC7.1050802@sonic.net> Message-ID: <4426DA82.1090000@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Mark Wedel a ?crit : > > > All in all, seems a lot simpler to just restart the server than try > to sort all of this out. > Agree. However, if i understand well, the problem of kari Pahula is to handle it all from command line in case of package upgrade. That mean players get kicked out from a local command. May be we should have server react to specific signal so it give all players something like 2 minutes delay to log off, warn them, and refuses new connections with an explanatory message. Then server will then be shutdown, install script will replace maps / archetypes / whatever is new and restart the server. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEJtqCHHGOa1Q2wXwRAs/PAKDTavMT9+scqw1ljML223viWTwnTQCeMac4 Ub1dBunJ8rXTvpG+0nTczNo= =bzB+ -----END PGP SIGNATURE----- From tchize at myrealbox.com Sun Mar 26 12:30:05 2006 From: tchize at myrealbox.com (tchize) Date: Sun, 26 Mar 2006 20:30:05 +0200 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <20060324170954.GA12429@sammakko.yok.utu.fi> References: <20060324130452.GA10561@sammakko.yok.utu.fi> <442403E6.4050809@myrealbox.com> <20060324170954.GA12429@sammakko.yok.utu.fi> Message-ID: <4426DDAD.4020104@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Kari Pahula a ?crit : > > > The debian-mentors mailing list was the first place I asked about > how to handle map installs[1]. They thought that upgrading maps > should be doable while the server was running. They went as far as > to suggest to make upgrading the server possible without > disconnecting players. Not a patch that I'd like to try to make. As they say it's a cool, security design issue feature. No way we implement something like that :) > > But I would be content to just put a large warning on the map > packages in Debian that installing them will trigger a server > restart. The current way of silently copying over the old maps > with the new ones just seems too hazardous to me. Players may end > up stranded who knows where with maps' pathnames changing and > whatelse. > > [1] http://lists.debian.org/debian-mentors/2006/03/msg00319.html > > > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > > -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEJt2tHHGOa1Q2wXwRAs6LAJ0Wr9X6hyd+zKGPudGK0BLLpqRvbgCgvCs3 XQxvs35EihyclP/ffpzWqoI= =CtdV -----END PGP SIGNATURE----- From alex_sch at telus.net Sun Mar 26 12:42:52 2006 From: alex_sch at telus.net (Alex Schultz) Date: Sun, 26 Mar 2006 11:42:52 -0700 Subject: [crossfire] Protocol & compression. In-Reply-To: <44263306.8030708@sonic.net> References: <442506CB.6020701@sonic.net> <4426199A.5020106@telus.net> <44263306.8030708@sonic.net> Message-ID: <4426E0AC.7050901@telus.net> Mark Wedel wrote: >Alex Schultz wrote: > > >>Perhaps system load could be measured in determining what threshold of >>what packet size should be before it is compressed, with a hard minimum >>size set as well (so, if the system load gets high, only compress the >>REALLY big packets, which should be rarer). This isn't the simplest to >>implement, but perhaps if reading the system load directly doesn't work >>well, perhaps measuring how close the ticks are to actually hitting 120 >>ms/game tick, and if they start taking too long, then scale the >>compression to back to be used on fewer packets. >>Neither of these methods is the easiest ways to do it, but IMHO it would >>be the 'smartest' way to do it. >> >> > > > However, if we were going to go down the idea of adapting what the server does >base on available time, there are lots of other things. Don't swap out maps if >busy. Put off for a few ticks the routine stuff (in do_specials()). But that >also starts getting more complicated - some players may not care much about >compression but don't mind using it to help reduce server bandwidth, etc. Yet >others on low bandwidth connections really want that compression - this could >lead to things like clients saying how badly they want compression. Not sure if >that complication is worth it. > > Hmm, this is true. However in my opinion, it shouldn't really be that difficult to make a few things like that adaptive to server conditions. > The other problem I think with that approach is that the bigger the packet, >the longer it takes to compress. > > True, but the bigger packets are more important/worthwhile to compress, and if threshold is moved up, there are fewer packets that will be compressed, causing somewhat of a reduction in compression time. Perhaps if the server is really lagging behind, the threshold would become high enough that it wouldn't compress at all. > but the biggest issue is this scenario - player changes maps - loading this >new map takes time, so server is now short on time. Yet because player is >changing maps, a lot of map data is changing, so that is the packet you want to >compress. > Hmm, that is also quite true, however I don't think that problem is unsolvable. For example, if the average time/tick of the most recent 10 ticks is used instead of just the most recent tick, it might not cause that to happen so much, and things that cause a more constant system load would still make fewer things get compressed. Also, because such a packet would be rather large, if it is just the threshold of what to compress changing, it could still very well compress if it's a rather large one. It might also be possible to measure time used by I/O operations and exempt it, however I believe that is overcomplicated. Yes, some of the 'best' ways of doing this plan are a bit overcomplicated, but I do believe that a simple form could still be effective. Alex Schultz From mwedel at sonic.net Sun Mar 26 19:16:39 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 26 Mar 2006 17:16:39 -0800 Subject: [crossfire] Jeweler skill In-Reply-To: <20060326153540.GA1833@elmex> References: <20060324100147.GB7580@elmex> <4423C6A6.3070709@myrealbox.com> <20060324110804.GA7903@elmex> <4424EBF3.9000602@sonic.net> <20060325131334.GA1587@elmex> <442629D8.20906@sonic.net> <20060326153540.GA1833@elmex> Message-ID: <44273CF7.2010501@sonic.net> Robin Redeker wrote: > I've discussed now a different approach. First, i think you were right > with 95% max resistancy. Thats indeed reasonable. But what about > resistancies like paralyze, slow, drain, depletion? Couldn't there be > +100 allowed? Yes, 100% could be allowed for those. > > But another idea came in discussion with someone else: > > As the problem with these creating-skills is, that items in crossfire > stay until the player enters quit and his appartment and his inventory > is deleted, or he drops the item on a map which gets resetted. > > So with the jeweler skill in place the flood of god-like-rings has to be > prevented. (Also smithery has similar problem propably? What about > weapon improvement?) Weapon improvement doesn't really have this same problem, because the weapon is tied to the person that improves it (it is renamed). So yes, a high level player could have 20 really cool weapons, but he couldn't give them to others to use, as they would be unable to use them. > > What if rings would wear off with time. Then one has to use the jeweler > skill to fix their rings. And then no rare items are needed to prevent > the game from overflowing of powerful rings. > > This would also put the piles of money in the player appartments to > more use. This idea has in general been discussed in the past for just normal objects (objects get damaged over time, needing repair). IIRC, while it seems like a good way to use money, there was some concern that this would just make things bothersome to maintain. However, if players are making the rings, I suppose it is reasonable that they could break down over time. > >> But the real point is figure that in not too long a time, there will be high >> level jewelers, armorers, etc, about. And if they can make suprerior items than >> what is out there, they will do so. > > Out there are rings with +100. But there shouldn't be rings that reduce the effects of damage, only the effect type rings. From mwedel at sonic.net Sun Mar 26 19:27:11 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 26 Mar 2006 17:27:11 -0800 Subject: [crossfire] Changing maps from under a running server In-Reply-To: <4426DA82.1090000@myrealbox.com> References: <20060324130452.GA10561@sammakko.yok.utu.fi> <4424EEC7.1050802@sonic.net> <4426DA82.1090000@myrealbox.com> Message-ID: <44273F6F.1060009@sonic.net> tchize wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Mark Wedel a ?crit : > >> >> All in all, seems a lot simpler to just restart the server than try >> to sort all of this out. >> > Agree. However, if i understand well, the problem of kari Pahula is to > handle it all from command line in case of package upgrade. That mean > players get kicked out from a local command. May be we should have > server react to specific signal so it give all players something like > 2 minutes delay to log off, warn them, and refuses new connections > with an explanatory message. Then server will then be shutdown, > install script will replace maps / archetypes / whatever is new and > restart the server. IIRC, this could be sort of possible by using the forbid file. I'm not sure that the timing is fine enough right now to get it down to the minute, but that could be done. That said, having the server take sigusr1 or something to do that action wouldn't be that hard. It probably just need a few lines of code. It is probably also easier if the assumption that an outside process will restart it. > > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.1 (GNU/Linux) > Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org > > iD8DBQFEJtqCHHGOa1Q2wXwRAs/PAKDTavMT9+scqw1ljML223viWTwnTQCeMac4 > Ub1dBunJ8rXTvpG+0nTczNo= > =bzB+ > -----END PGP SIGNATURE----- > > > _______________________________________________ > crossfire mailing list > crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire From mwedel at sonic.net Sun Mar 26 20:00:41 2006 From: mwedel at sonic.net (Mark Wedel) Date: Sun, 26 Mar 2006 18:00:41 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <20060326110855.GA25148@hogia.net> References: <442506CB.6020701@sonic.net> <20060325095155.GA11407@hogia.net> <44262E90.9080507@sonic.net> <20060326110855.GA25148@hogia.net> Message-ID: <44274749.2030204@sonic.net> Sebastian Andersson wrote: > On Sat, Mar 25, 2006 at 10:02:56PM -0800, Mark Wedel wrote: >> There are a few likely differences which may or may not effect crossfire in >> different ways: >> >> 1) Some data crossfire sends is just not compressible. The PNG data comes to >> mind - trying to compress it is at best a waste of time, and at worse, increases >> amount of data being transmitted. The other problem related to this is you'll > I've found PNG data to be compressable with zlib. At least if many > images are sent one after another. > > Perhaps there is a bug in the 1.6 server, but many of the image2 > commands sent contained hundreds of identical octets in a row, > clearly compressable on their own. I just ran a quick test (find . -name "*.png" -exec gzip -vc {} > /dev/null \;) , and this is a somewhat typical result of the entire arch tree: ./light/light_bulb_2.base.111.png: -0.6% ./light/flint_and_steel.base.111.png: 1.5% ./light/torch_unlit.base.111.png: 73.0% ./light/lantern.base.111.png: 4.2% ./light/torch_lit2.base.111.png: 61.9% ./light/light_bulb_1.base.111.png: -0.9% ./light/lantern2.base.111.png: 4.2% ./light/torch_lit1.base.111.png: 61.2% ./light/light_bulb_4.base.111.png: -0.6% ./light/light_bulb_3.base.111.png: -1.5% ./light/lantern_off.base.111.png: 6.7% ./light/lantern2_off.base.111.png: 5.5% Some files not compressible, some marginally compressible, and some very compressible. It seems that one that is compressible, at least doing a single quick test on torch_unlit.base.111.png, is that they are indexed images instead of RGB images. I don't know why the difference or if there is even any reason there is one (should we convert all the indexed images to RGB?) AFAIK, none of the code in the clients care what the format is, as they just use the png library routines to get the image in RGBA format > If overhead is given, then the system will add that overhead to each > compressed writing and it will not compress data that is less than > 16 bytes long. This is not totaly correct of course, the real > compression overhead (both in bytes and in CPU time) would be larger > if one would flush after each command. Anyway, the result was that > with an overhead of just 4 bytes (ie two length bytes + "gz"), > the result was that 447KB was saved, instead of the 485KB when > everything was compressed (8% less). On the other hand, 15% less CPU > was used for the whole program, measured with time and just counting > the "user time" (~170ms vs ~200ms). Thanks for the data. One note - if we use a 'gz' prefix, it would have to be 3 bytes, as we would need a space after the gz for proper client handling. However, the length bytes may or may note be needed, if we only compress one protocol command at a time. For example, right now, it would be 'map2 ....'. If we do compression, it would be 'gz > (The CPU used was an AMD Athlon(TM) XP 2400+; 2GHz, 256KB cache, > ~4k bogomips on linux-2.6.15) > > I did some other quick measurements with time over the whole file. > > With compression level 9, the run time was twice as long, > but it only saved 5KB more. > > With compression level 1, the run time was 10% less and the output > was 27KB larger (6% more) than at level 5. Which is once again interesting - may be worthwhile to compress only at level 1. > >> often need to send a bunch of image data at one time (player changes to new >> map), and now there is lots of data you are trying to compress - the time it >> takes to compress that much data could become significant. > > So is receiving uncompressed data if you've got a slow link and need > compression. When measuring lag to modem users, they usualy have > less lag when compression is turned on because of the increased > bandwidth. With crossfire, the same might be experienced for 64-128kbps > connections. My point was really that player changes maps, get sent 40 images which don't compress any smaller (well, maybe they do), but we spent the time trying to compress that uncompressable data. All that said, this is my thoughts: Adding a 'gz' compress prefix is an easy thing to do right now, and can get us pretty good results. Adding a compresstart/compressend command and then compressing might be worthwhile to do, but is harder to do given the multiple layers of buffers currently used in the server. I need to actually think about that one more - because of those different levels of buffers, we can actually combine those small packets together - if the OS buffer to the client is full, there is nothing preventing us from compressing all the data we have pending before putting it to the OS buffer. But I suppose the real question is whether the bandwidth saved by compressing everything is worth the extra CPU time we spend compressing everything. Not 100% sure what the answer is there (and with the other message in the thread about compressing/not compressing based on server load, to do that would require nocompress transitions, which then once again, can hurt performance numbers. From cerzeo at gmail.com Mon Mar 27 09:59:58 2006 From: cerzeo at gmail.com (=?ISO-8859-1?Q?Alberto_S=E1ez_Lodeiros?=) Date: Mon, 27 Mar 2006 17:59:58 +0200 Subject: [crossfire] JCrossfire and Web playing Message-ID: <3fa509450603270759w608a03di2d12365a50df811f@mail.gmail.com> Hi all :D Some months ago, I have discovered a source-port for Quake2 in JAVA. This is called Jake2. You can see the web page here: http://www.bytonic.de/html/jake2.html Then, you will ask...Quake2 on JAVA, maybe cool...but what is matter? The cool thing is that you can play Quake2 using your web browser, if it has JWS (Java Web Start) installed and supported. Also needed JRE 1.4. I have see also a port of crossfire, using JAVA, then, a cool idea, can be to play CF over the web browser, usin also JWS. This can allow to play CF without any installation, compilation or so on, or maybe, players who can't download software fron the web, to play Crossfire. For example, from a University, from the job, and more. I have tested the Jake2, and he goes at same speed than normal Quake2 (using Linux). Also, JCrossfire is more playable over windows than the GTK version (i have tested gcfclient on windows, and it is really slow) But the very best of JCrossfire over the browser is that the user will be playing the last version released of JCrossfire. -- Powered By SuSE Linux 10.0 -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060327/71cb053c/attachment.htm From brenlally at gmail.com Mon Mar 27 10:12:17 2006 From: brenlally at gmail.com (Brendan Lally) Date: Mon, 27 Mar 2006 17:12:17 +0100 Subject: [crossfire] Protocol & compression. In-Reply-To: <44274749.2030204@sonic.net> References: <442506CB.6020701@sonic.net> <20060325095155.GA11407@hogia.net> <44262E90.9080507@sonic.net> <20060326110855.GA25148@hogia.net> <44274749.2030204@sonic.net> Message-ID: <7903f03c0603270812r54f89fcdo34e13fe08a282a8e@mail.gmail.com> On 3/27/06, Mark Wedel wrote: > I just ran a quick test (find . -name "*.png" -exec gzip -vc {} > /dev/null > \;) , and this is a somewhat typical result of the entire arch tree: > > Some files not compressible, some marginally compressible, and some very > compressible. I had a play with pngcrush, to see if the same space savings couldn't be achieved in the arch tree itself, I ran PNG crush on all the png files, then compared the filesizes before and after. I dumped a list of all the images which are reduced in size by 10 bytes or more at http://pastebin.ca/47176 (I strongly suspect that any gain less than this is likely to be completely wiped out by those clients which need to recache the image after it changes, and indeed, the threshold at which that is true may well be closer to 50-100 bytes) Note however, that the images which most benefited from this are /not/ the same ones that gzip seems to be able to compress well. (if anyone wants to try and recreate this, I used pngcrush -fix -l 9 with version 1.5.10) - I think this is something to do with palette utilisation in indexed images. From brenlally at gmail.com Mon Mar 27 10:57:56 2006 From: brenlally at gmail.com (Brendan Lally) Date: Mon, 27 Mar 2006 17:57:56 +0100 Subject: [crossfire] JCrossfire and Web playing In-Reply-To: <3fa509450603270759w608a03di2d12365a50df811f@mail.gmail.com> References: <3fa509450603270759w608a03di2d12365a50df811f@mail.gmail.com> Message-ID: <7903f03c0603270857n116cc035g73eaff1c8e81c55f@mail.gmail.com> On 3/27/06, Alberto S?ez Lodeiros wrote: > Then, you will ask...Quake2 on JAVA, maybe cool...but what is matter? The > cool thing is that you can play Quake2 using your web browser, if it has JWS > (Java Web Start) installed and supported. Also needed JRE 1.4. I have see > also a port of crossfire, using JAVA, then, a cool idea, can be to play CF > over the web browser, usin also JWS. This can allow to play CF without any > installation, compilation or so on, or maybe, players who can't download > software fron the web, to play Crossfire. For example, from a University, > from the job, and more. > > I have tested the Jake2, and he goes at same speed than normal Quake2 > (using Linux). > > Also, JCrossfire is more playable over windows than the GTK version (i have > tested gcfclient on windows, and it is really slow) But the very best of > JCrossfire over the browser is that the user will be playing the last > version released of JCrossfire. I'm not altogether sure what you mean by JCrossfire, there is jcrossclient, which is the java AWT client that I took over from Phil Brown, and jxclient which is a java+openGL one (or something like that) which is in crossfire CVS and primarily (exclusively?) developed by gros. In anycase, experimental Java WebStart scripts exist for both of them, gros is the person who actually understands it (and indeed helped me hack one for jcrossclient) In the case of jxclient, no public release has yet been made, so all JWS scripts are ad hoc ones for testing. In the case of jcrossclient, I didn't have the binaries from the previous release signed (or some such detail) so it didn't work nicely, and I didn't want to re-release the binary just for that. I can't comment on when gros thinks that jxclient will be in a state suitable for a stable JWS script, he will have to tell you that himself, for my part, jcrossclient /may/ have one for the next release, if I remember in time and find a sufficiantly straight-forward howto. :) From wim-cf at villerius.nl Mon Mar 27 11:21:27 2006 From: wim-cf at villerius.nl (Wim Villerius) Date: Mon, 27 Mar 2006 19:21:27 +0200 Subject: [crossfire] RFC: dynamic alchemy Message-ID: <1143480087.14079.216.camel@localhost.localdomain> Hi, Dynamic alchemy is a proposal which was discussed about a year ago on the message board. During that time I've been writing a message for the list that never was sent for a reason I cannot remember. Perhaps I judged the proposal to be too incomplete to lead anywhere. Perhaps it was because I am not capable to code anything myself. Anyway, since I think this would nevertheless be an interesting addition to Crossfire, I now do send it. Take your time, the message is pretty big now. (I'm sorry for that.) I don't think the idea in its current state is ready for implementation, but an idea - in whatever state it - is ready for discussion, right? ;) WHAT IS ALCHEMY? Alchemy is "a form of chemistry studied in the Middle Ages which involved trying to discover how to change ordinary metals into gold" (Oxford advanced learner's dictionary) WHAT IS ALCHEMY IN CROSSFIRE? In Crossfire, we don't try to create gold, for it is a rather useless metal. As far as I am aware alchemy is used like a fully controlled commercial process. It is highly accurate and reproducible, more or less like a chemical, an industrial process! So, current alchemy is more or less "an industry used to create predefined items in a predefined, reproducible - 'scientific' - way" WHAT SHOULD ALCHEMY BE IN CROSSFIRE? >From a role playing perspective, what should alchemy be? IMO this question is assuming too much. It does assume role-playing! Crossfire doesn't have much role-playing at all, since (almost) all players tend to be(come) a 'Jack of all trades' (and a master of all, if they spent sufficient time). OK, scratch that role-playing perspective for now, and just ask what alchemy should be. Way too hasty, first ask if there is any need for alchemy and if the current alchemy is not sufficient. Alchemy is not necessary (strictly speaking). Although it is an interesting addition to the game, it usually doesn't come in sight before a player is already quite experienced and has seen a lot of the world. At that stage, alchemy and alchemy results do not offer much - except little experience and some money. The artefacts found in game are better than alchemy results (except for results of shadow alchemy, a subject I don't wish to discuss). So, alchemy is not necessary. But that's not an answer to the question whether there is any need for alchemy or not. I would say "Yes!", playing with alchemy is (or is supposed to be) a lot of fun. The answer to the second question (Is the current alchemy system is sufficient?) is by me answered with a resounding "No!" Why is that? For reasons already mentioned: - results are pre-defined - results are not half as powerful as 'normal artefacts' In other words: If we manage to develop an alchemy system that allows one to create really powerful items, a system that does offer more than just predefined results, I'll be satisfied (but others wont). Before continuing with some more detailed descriptions, I would like to offer some in-game notes about alchemy. Since the game takes place in a not-so-very-high-tech world (where very high-tech things like teleportation are still magical) nobody (in that world) has exact knowledge of what alchemy is. Alchemy is an art practised by many, mastered by none. In ancient times, there where a few great alchemists, and their stars rose high. They all where capable creating highly enchanted equipment, and some of these items, amongst which the Dragon Scale Mail of Ruggilli still exist today. Perhaps the most praised White Dragon Scale Mail still exist somewhere. Although equal in skills, the ancient masters of Alchemy had very different definitions of what exactly alchemy is, and they where likely all wrong. Since alchemy is a business enshrouded in a cloud of vagueness, nobody exactly knows what could be the result of an alchemical process. Therefore, nowadays alchemists describe the art of alchemy as "a mystic process used to transfer magical powers from one item to an other." This is the baseline I will use in the development of a new alchemy system, which I would like to call 'dynamic alchemy'. DYNAMIC ALCHEMY AND THE CURRENT SYSTEM Dynamic alchemy is not intended to be a complete replacement for current alchemy, but it is more than just an extension. Dynamic alchemy is used to create 'advanced' equipment, current alchemy remains to create base ingredients (such as water of the wise, (fixed) mercury, potions of ...). Since equipment is not created with alchemy but rather with bowyery, jewellery, smithery, thaumaturgy or woodsman, we perhaps should speak about dynamic bowyery (etc.). I will not do so, but please keep in mind that experience gained from any dynamic process will go (I assume) in one of these skills and not in alchemy. For the user nothing but the recipes (and results) changes, but under the hood, there will be lots of difference. DESCRIPTION OF 'DYNAMIC ALCHEMY' As said before, dynamic alchemy is the art of transferring magical powers from items to other items. This naturally leads us to the conclusion that in order to do alchemy, one needs at least two components: one base item and at least one addition. Definition: base item: The base is the item a player wants to improve. Definition: addition: An addition is a (supposed) source of transferable 'magical powers'. The base can be some item found in the world, but it also might be an item that is created with traditional alchemy, or even dynamic alchemy. An addition can be literally everything - though not everything will lead to anything (desired). During the process the magical powers (hopefully) flow from the addition(s) to the base item and (hopefully) improve it. What exactly the improvement is, depends on the additions. ON MAGICAL POWERS AND TRANSFERING THEM I have been talking about 'transferring magical powers' from something to something else. Fine, but as long as I leave undefined what 'magical powers' are and how they are transferred, the proposal will go nowhere. Therefore, I will pay some attention to what magical powers are and how they are to be transferred. Of course, 'magical powers' are not 'transferred' during an alchemical process. All that happens is that the server searches ingredients for a match against a table, applies some random numbers and modifies the ingredients. Happily a player can remain unknowing of all this, he just has to learn that the steak of an ancient red dragon is a magical source for fire resistance when used in dynamic alchemy. He does not know that this is because the ancient red dragon steak is listed in a table as containing a 'resist fire +50' modifier. Magical powers are in fact pre-defined item-modifiers, and their transference is server side number'magic'. I have more to say about item-modifiers and number magic later, I should first give an example of dynamic processing. EXAMPLE Assume some player adds an ancient red dragon's steak to a mithril chainmail and then uses his skill. there are three possible outcomes: 1) the powers travel one object to the other 2) nothing happens (that is: both ingredients are still in the forge) 3) something strange happens 1) ... from steak to chainmail or vice versa. The first would result in a mithril chainmail (resist fire/magic +); the second would give some 'enchanted food'. This is either poisoned or good dragon food. It can even be reused as ingredient for another attempt, perhaps giving a mithril chainmail with fire/magic resistance and a little more ac. 2) Sometimes, just nothing happens. 3) and the powers leave one object but do _not_ enter the other item. This might result in lost items, or uncontrolled mana, or evil masters, or a random object (cursed or not) , or ... or ... or a cursed forge or an enchanted forge (even uncontrolled forces can be good!) Another example: A player adds a dragon scale mail and a dragon's steak in a forge. After using his skill (and being successful) he gets a dragon scale mail with increased fire resistance. ON ADDITIONS I now want to say something about additions - the so called sources of magical power. Theoretically, everything can give an interesting improvement. In practice, this is a little different. Since the server has to be aware of possible improvements, they have to be listed somewhere. I can imagine two suitable locations. The first being a large table, the second somewhere in the arch-files. Bot choices have their pro's and con's. Adding it to the arches almost guarantees that every new item is checked for/attributed alchemy settings, but a huge table is easier to maintain and to use. I myself don't want to mess with the arches, and thus prefer the table solution. In such a table should be listed the item name, the resistances it gives and the max resistances it can give. Think about the following example: begin Chinese dragon * cold 30 poison 20 end begin ancient red dragon * fire 50 magic 40 physical 40 end begin dread all -godpower -holy -light 30 confusion fear paralyse slow 100 end begin true lead physical 50 end (Note that these are examples, and hence contain example values. As with all examples, they might be completely off and terribly odd.) The list of items that can be used is limited only by the number of items in the game, though lots of items just do not make sense in any (dynamic) alchemical process. For sure any item not in the table does not have magical powers. The number of transferred properties is not limited to resistances only. Adding feathers to a plate mail might reduce its weight. And adding true lead might not only add physical resistance, but can possibly increase the weight as well (depending on the skill of the alchemist) ON TRANSFERING MAGICAL POWERS Processing dynamic alchemy involves quite a few steps 1) identifying the base item 2) identifying the additions 3) deciding what will happen 4) adding certain 'bonuses' 1) I suggest this should be done with a 'prepare item' scroll. This way, an item is bound to a player. Of course, check whether the alchemist is the same as the one who prepared the item. 2) find them in the table, and collect all the (possible) bonuses they give. 3) this is the hard part to get right. It involves some numerology. Which resistances are added to the base item depends on several factors (level, int, luck, server mood, ...) and the additions. a) Every addition with magical power gives one or more possible resistances. First, we choose one of them, for one item can give only one resistance each time. b) Then a list of additions is made and then a number of these resistances is chosen. (It is likely that all resistances are chosen for a sufficient high lvl player.) c) Next, the selected resistances should be given a value - namely the value that is added to the base item. How this exactly must be calculated is not yet clear. I suggest a formula in the line: (max_resistance(addition) - current_resistance(base)) * ((skill_lvl - 10)/100 + 0.1) * random_factor where random_factor is a number <= 1 (and perhaps has a lower limit as well) (max_resistance(addition) - current_resistance(base)) to enforce max_resistance ((skill_lvl - 10)/100 + 0.1) guarantees a minimum of 10%, high lvl players can gain 110%. random_factor for to make stuff a little more dynamic ;) 4) no comment. Perhaps an example might help. A player performs dynamic alchemy with a dragon scale mail and two ancient red dragon's steaks. step 1: The base item is identified, it is a dragon scale mail: dragon mail +3 (ac+6)(item_power +5)(Max speed 1.30)(Spell regen penalty 9)(armour +50)(resist fire +40) step 2: the addition is found in the list: begin ancient red dragon * fire 50 magic 40 physical 40 end step 3: a) choose a random resistance for item 1: fire choose a random resistance for item 2: magic b) the list contains fire and magic. The player has luck and is high lvl (63), so he gets both c) value calculation: (max_resistance(addition) - current_resistance(base)) * ((skill_lvl - 10)/100 + 0.1) * random_factor gives: fire: (50 - 40) * ((63 - 10)/100 + 0.1) * 0.731 = 4.6 magic: (40 - 0) * ((63 - 10)/100 + 0.1) * 0.328 = 8.3 4: add 5 fire resistance and 8 magic resistance to the dragon scale mail I am sure this section needs more explanation, but I cannot think of anything right now. Ask and ye will be answered. Note by the way that this somehow might be related to the way a dragon's hide grows better. ON ADDITIONS (SECOND TIME) Until now I have only been speaking about resistances. I have a word to say about stats, attunements and attack types as well (is there anything else that could be added?) for I don't think there is any a priory reason to forbid these to be added. I just don't know what would be reasonable for them to be added (since some of these options are very powerful). WHAT IS DYNAMIC IN 'DYNAMIC ALCHEMY'? - there are no pre-defined recipes, only pre-defined items which give certain bonuses - the results are more or less unpredictable - under the same circumstances, a recipe can give different results: more or less resistance/bonus/... - using two dragon steaks (and not one) can result in more fire resistance COMMENTS REQUESTED... things that need to be thought out are, amongst others not mentioned: - what items give what bonuses? I suggest to have some items that give always the same (fragment of chaos) some items that give fire, magic or physical resistance (ancient red dragon) some items that give completely random resistances (beholder/dread/skull parts for example) - which path do the magical powers take? Usually, they will go from the item with the lowest power to the item with the highest magical power since alchemy breaks thermodynamics ;) This is perhaps not compatible with my previous suggestion to use scrolls of prepare for dynamic alchemy, for these scrolls suggest that magical powers will always go to the base item. But maybe saying that an item that is prepared for dynamic alchemy gains quite a boost in magical power gives a solution to this problem (although I don't like it) If these ideas don't match, a choice must be made: A: prepare with a scroll and the magical powers always go to the prepared item (or fail to reach their destination, but that should be rare) B: magical powers usually go from low to high. B has as advantages that it is much more dynamic and gives an arguably lower rate of success. A has as advantages that it allows dynamic alchemy results to be bound to a player and that it is easy to determine the base item (the target so to say) - what magical powers can be transferred? Basically all, but specifically: - resistances - attunements - stats The question is not: what? but: how? - What if someone drops two dragon scale mails in a cauldron? Assuming something happens, we could create a scale mail that has resist fire 30+.3*70 = 51 and no armour and a scale mail that has no fire resistance and all the armour, or something in between. (Note: I think we should not add resistances linear) - would dynamic alchemy not create way too powerful items, and be somehow a legalisation of shadow alchemy? I think not. Shadow alchemy is an exploit, used to create items that are impossible to create with dynamic alchemy. (It is impossible to have items with resist_something > 99 - and this limit could even be set lower) Also the price for an item with str+50 would be extremely high - in fact too high to be paid. (using the current weapon improvement, it would be 2550 potions) Shadow alchemy ignores item power code, dynamic alchemy will not. Nevertheless, 'some' balancing has to be done. If you made it this far, you made it to the end! Thanks for reading, feel free to comment, criticize or to suggest improvements (the latter is preferred). greetings Wim Villerius From tchize at myrealbox.com Mon Mar 27 11:22:24 2006 From: tchize at myrealbox.com (tchize) Date: Mon, 27 Mar 2006 19:22:24 +0200 Subject: [crossfire] Protocol & compression. In-Reply-To: <442506CB.6020701@sonic.net> References: <442506CB.6020701@sonic.net> Message-ID: <44281F50.3090902@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Just a note about the suggested s->c compressed c->s compressed (yeah imho shoud go in both directions) if we assume data contains a compressed list of 1 or more commands, i think the question on what need and what need not to be compressed os not immediate and we can have various attempt with various server / client version. The fact of assuming any command can be compressed by algorithm X but that not all commands will be compressed, is enough to write this protocol add-on. Then it's a matter of tuning the compression triggers, but this can be done without breaking interaction with previous versions. So imho, the 'when' to compress should not be fixed in protocol, only the how is to be fixed. One of the most important question is which algorithm do we use? You said you gave a try with zlib, but which algorithm does it uses? Does it involves a dictionnary? If yes, do we plan to reset the dictionnary content between each compress command or do we plan to keep it from begin to end? My opinion currently is - assume client can receive any data in compressed mode, but that not all datas are compressed (the sender has choice for every command) - assume the compression stream as something interleaved with not compressed stream, identified by a specific marker (compressed) - assume the compressed stream continuous (same 'zlib/any chosen algorithm' session, usefull considering number of repeated text messages) - assume setup negociate the algorithm (client say i support x,y,z then server send ok, let's go for y algorithm, this is how http does it) Regards Mark Wedel a ?crit : > On the mailing list, irc, and elsewhere discussion came up about > rather than trying to be too clever about minimize bandwidth with > things like animations to just compress the data itself, as that > keeps things simpler. > > Alex ran some quick tests, getting ~40% compression rate on big map > payloads. However, that was client side, so I quickly hacked the > server to do some compression on map packets (map1a). This way, I > could also time how long it takes to do the compression (running on > an athlon mp 2000 here). > > General notes - small map packets are not worth compressing. The > cut off to be worth while is probably around 200 bytes. > > For a big map transfer, in this case, leaving the scorn apartment > building with a 25x25 map in dm mode (so everything is visible), > zlib compressed 3034 bytes to 1637 (47%) in 952 ?sec. bz2 didn't > do quite so good (1818) in 2113 ?sec > > The other case I quickly tested was standing at the far north end > of scorn (still in DM mode) to get a lot of ocean spaces. In this > case, zlib compressed 806 bytes to 270 bytes (67%) in 505 ?sec. > bz2 compressed it to 245 in 408 ?sec. > > Note that 1000 ?sec = 1 ms, and by default, there is 120 ms/game > tick. So spending a few milliseconds on compression doesn't seem > to likely add much to the load (get enough players it adds up, but > then so does the overall bandwidth compression). > > I'm personally think zlib is better in this case, as it is faster, > and for big data, is smaller, and the interface is simpler. > > For other reasons, I still think I'll add animation support to the > map2 command. However, I think it also worthwhile to add something > like: > > S->C: compress > > Where data is the block of compressed data. The length of data can > be determined from the packet header (a shorter command, like comp > or something could be done). > > would get uncompressed on the client, and just contain > normal protocol commands that the client then processes. By > abstracting at a higher level, it allows us to compress any other > protocol commands (think itemcmd for a large inventory. Or it > would involve more work, but a long list of drawinfos, like from a > shop listing). > > Thoughts/comments? On the server, this is pretty simple to do > (simplest would be to add another parameter to send_with_handling > on whether to compress the data) (some data, like png images, > aren't worth trying to compress). > > For the client, it is more complicated, because you could have > something like 'command; compressed data; command;' - right now, it > justs uses a larger ring buffer IIRC. We don't want to have to > move all the data beyond our compressed ata back - I suppose that > since it is a ring buffer, we could backtrack the buffer to insert > the uncompressed data. Or use a few buffers. > > > > > > > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire > > -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEKB9QHHGOa1Q2wXwRAouFAKDKQdr4SKQFpEVDWltOGoBsoYzeFwCeO4Dn tFKA2o4lip80LoXZQk6VZa8= =fZWn -----END PGP SIGNATURE----- From tchize at myrealbox.com Mon Mar 27 13:01:27 2006 From: tchize at myrealbox.com (tchize) Date: Mon, 27 Mar 2006 21:01:27 +0200 Subject: [crossfire] arch.c badly named functions Message-ID: <44283687.3020200@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hello While writing arch check code, i noticed this. There are a few functions in arch.c which are named get_archetype_xxxxxx but in fact return a new object of that archetype using arch_to_object. I plan to rename those create_object_xxxxxx, which i think is more suitable. Any objection? Tchize -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFEKDaGHHGOa1Q2wXwRAqB6AKDgrS0EOuD2fQgO5VlbEmTremjbKACfY1sz Dp2D4B5cqgJBOWUL3HWxjco= =eWQ3 -----END PGP SIGNATURE----- From mwedel at sonic.net Tue Mar 28 00:13:55 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 27 Mar 2006 22:13:55 -0800 Subject: [crossfire] arch.c badly named functions In-Reply-To: <44283687.3020200@myrealbox.com> References: <44283687.3020200@myrealbox.com> Message-ID: <4428D423.6050208@sonic.net> tchize wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hello > While writing arch check code, i noticed this. > > There are a few functions in arch.c which are named > get_archetype_xxxxxx but in fact return a new object of that archetype > using arch_to_object. I plan to rename those create_object_xxxxxx, > which i think is more suitable. Any objection? Not by me. From mwedel at sonic.net Tue Mar 28 00:43:29 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 27 Mar 2006 22:43:29 -0800 Subject: [crossfire] RFC: dynamic alchemy In-Reply-To: <1143480087.14079.216.camel@localhost.localdomain> References: <1143480087.14079.216.camel@localhost.localdomain> Message-ID: <4428DB11.1050101@sonic.net> Various thoughts: 1) The idea is interesting. However, like most such proposals, balance has to be maintained - if I can take a couple ancient red dragon steaks and get mithril chain resist fire +90, the case can be made that that is a bit too power. 2) You mention where to store information about alchemical improvements, and state your preference for a table instead of the arches. I'd say arches are the right place - a large table is just unwieldy, and unlikely to get updated (I can see the relatively common case of someone copying one arch to another, changing the name, and making some other changes. This won't match in the table, and thus the table is out of date. Yet if they copy the archetype, they are likely to see alchemy_... fields.) The other point is that if anything, the more recent push has been to get rid of files in the lib directory and put that into archetypes. I'm specifically thinking of the treasurelists here - no longer do we need a monolithic file for all the treasure lists, these can be in the arch directory tree. 3) Other things that could be added: hp/sp/grace regen (unless you count those as stats). sustenance (slower digestion). Bonus movement types (flying, swimming, etc). This last one is trickier because it is really an all or nothing type of thing (either the item lets you fly, or it doesn't). An unrelated but perhaps interesting improvement would by duration items. Eg, this object will let you fly for up to 1000 ticks. Then, for each tick it doesn't fly, it recharges 1 tick of duration. In that model, partial movement types make sense - this object lets you fly, but right now, only for 20 ticks before it needs to rest - further improvements increase the duration. Doing this wouldn't be that far off from the rod code. 4) In terms of stats - they are sort of like movement type - either you add a stat point or don't. However, the key-value lists could be used to hold fractional improvements. So each improvement gets you say 0.1 of a point - you could in fact use similar logic to your resistance improvement idea. Thus, it could a bunch of objects to improve a stat. 5) Direction of resistance - if prepare weapon scroll is used, as said, that solves the problem. However, as one of the potential bad effects, maybe it does reverse. One problem with 'low to high' is that if you are starting with something relatively mundane you want to improve, that is unpredictable. Lets suppose for some reason you just want to start with a simple +1 sword. That could be low. However, I think that given crossfire is multiplayer, binding improved objects to players isn't a good idea. I should be able to create some cool stuff for a friend - that will help things IMO than everyone having their own stash. It also means that not everyone has to be an alchemists - a few powerful player alchemists in the town could possibly make pretty good business improvement objects for other players. However, one could perhaps change the enchant item scrolls - it just marks the object for improvement, but doesn't tie it to the player. 6) I think even some more dynamic aspects are needed. For example, you can't really enumerate the normal rings - rings have their resistances added in the treasure code - there is no way to say a ring of str +1 is this archetype. So you need some way to say 'if this is a ring, examine what properties it has and choose one for dynamic alchemy'. Perhaps some for a large majority of food items. One thought on this is that for a baseline, the object can't improve the object any more than it grants. For example, you have a ring str+1 resist fire +18 You toss it in the pot to transfer to your plate armor. If your plate armor already has str +1 or resist fire +18, this ring can't help out at all. However, if the plate armor has less than that, this ring can help bring it to that point. This does get interesting if you have a ring like 'resist fire +20, resist cold -20'. Can resistances (or other things) get drained away? Does the code try to optimize for improvements? That also raises the other interesting point: Suppose I have plate armor resist cold -20. Can I transfer away that resist cold -20 to just some other object, or is the only way to get rid of it is via resist cold + objects? I bring that point up because that could be used to explain why there are items with negative resistances - they were used to get rid of the undesirable aspects of an otherwise good object. From mwedel at sonic.net Tue Mar 28 00:48:44 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 27 Mar 2006 22:48:44 -0800 Subject: [crossfire] Indexed PNGS, was Re: Protocol & compression. In-Reply-To: <7903f03c0603270812r54f89fcdo34e13fe08a282a8e@mail.gmail.com> References: <442506CB.6020701@sonic.net> <20060325095155.GA11407@hogia.net> <44262E90.9080507@sonic.net> <20060326110855.GA25148@hogia.net> <44274749.2030204@sonic.net> <7903f03c0603270812r54f89fcdo34e13fe08a282a8e@mail.gmail.com> Message-ID: <4428DC4C.4010907@sonic.net> Brendan Lally wrote: > On 3/27/06, Mark Wedel wrote: >> I just ran a quick test (find . -name "*.png" -exec gzip -vc {} > /dev/null >> \;) , and this is a somewhat typical result of the entire arch tree: >> > >> Some files not compressible, some marginally compressible, and some very >> compressible. (the ones very compressible are indexed images, not RGB) < Portion about Brendan using png crush to reduce image sizes somewhat deleted> > Note however, that the images which most benefited from this are /not/ > the same ones that gzip seems to be able to compress well. (if anyone > wants to try and recreate this, I used pngcrush -fix -l 9 with version > 1.5.10) - I think this is something to do with palette utilisation in > indexed images. Briefly looking over the pngcrush page, it seems what it really does is uses maximum (and not default) compression level, as well as delete portions of the PNG file not really needed (comments, etc). It doesn't seem to actually change the form of the PNG - an indexed image will remain and indexed image. IMO, pngcrush may be of marginal value - next time someone loads up that PNG and does any work on it, when they save it out, it will go back to being at normal compression level and any fields removed might get added. But the question of whether to go through the arch try and convert any indexed images to RGB is still there. My bet is that it is purely a factor of what format the editor used to create them was set to use, and not anything intentional (I'd have to look over the list - it could in fact be that the xpm -> png conversion used indexed images). If no complaints, I'll look at doing this - have to see what tool(s) will work best to do so. From mwedel at sonic.net Tue Mar 28 01:26:15 2006 From: mwedel at sonic.net (Mark Wedel) Date: Mon, 27 Mar 2006 23:26:15 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <44281F50.3090902@myrealbox.com> References: <442506CB.6020701@sonic.net> <44281F50.3090902@myrealbox.com> Message-ID: <4428E517.3040303@sonic.net> tchize wrote: > -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Just a note about the suggested > s->c compressed > c->s compressed (yeah imho shoud go in both directions) I'm not sure if there is anything to really gain by the client compressing the data. I can't really think of many times the client is actually sending enough data that compression will do any good what so ever. The one exception might be very long chat/shout/say messages, but even then, that seems fairly unlikely. Granted, probably wouldn't be that hard to add, but does add some at least minimal complication, and if it doesn't gain us anything, I'd rather avoid that. > > if we assume data contains a compressed list of 1 or more commands, i > think the question on what need and what need not to be compressed os > not immediate and we can have various attempt with various server / > client version. The fact of assuming any command can be compressed by > algorithm X but that not all commands will be compressed, is enough to > write this protocol add-on. Then it's a matter of tuning the > compression triggers, but this can be done without breaking > interaction with previous versions. So imho, the 'when' to compress > should not be fixed in protocol, only the how is to be fixed. correct. That was my assumption - the server would figure out what it thinks is worthy of compression. A server with gobs of bandwidth but not a lot of cpu time could decide that nothing is worth compressing. > One of the most important question is which algorithm do we use? You > said you gave a try with zlib, but which algorithm does it uses? Does > it involves a dictionnary? If yes, do we plan to reset the dictionnary > content between each compress command or do we plan to keep it from > begin to end? I used the 'compress' function of zlib: http://www.zlib.net/manual.html#compress Since each call to compress is self contained, the compressed data then includes all the dictionary or other info necessary. Note that given crossfire will be working on multiple sockets, we can't use a library that holds any state. And if there are new structures needed to hold state, this starts to increase the complication level some. > > My opinion currently is > - assume client can receive any data in compressed mode, but that not > all datas are compressed (the sender has choice for every command) > - assume the compression stream as something interleaved with not > compressed stream, identified by a specific marker (compressed) > - assume the compressed stream continuous (same 'zlib/any chosen > algorithm' session, usefull considering number of repeated text messages) This point is the real gotcha however - since the server can choose what data to compress, the question then becomes what portion of the commands are being compressed? If less than say 50%, then we're better of going with explicit 'this data is compressed' than continual stream, as we're then spending more bandwidth on the transitions than we would just be prefixing. Also note that the real question comes where do we do the compression. It is trivially easy to modify Send_With_Handling to take another flag (compressible) and compress the data and send it along. It is harder to do it as a stream method, especially if we want to turn of compression. This is because if you want to do it as a stream, easiest approach then is to do the compression before writing to the actual socket. But by the point, all we have in the input buffer is just a bunch of bytes - we have no idea if some should or should not be compressed. If we were to go that approach, the socket code basically has to be rewritten. The best method would be to basically have a list of SockList structs, and add to that a field for the compress byte. Then when we go to send the actual data, the server could parse all the SockList, and based on current state of socket and the compress flag, figure out what to do (if for example, socket is in non compressed state and socklist says don't compress, just send it along. states don't match, send command to transition state. Compress all socklists with compress flag set as a single stream, etc. But this starts to lead down a pretty slippery slope. In that model, you almost want to start reorganizing the packets - for example, right now, with the map commands, you are going to often get images sent (non compressible) right next to smoothing information (compressible). Ideally, you want to organize all the face data together as one non compressible block, and all the smooth information as a compressible block. But re-arranging order of commands starts to get tricky - the client is currently coded (and says so in the spec) that it will get image info before that image is referenced, so we can't re-order image commands after map command. But knowing what to reorder and what not is where this cans of worms is. As I said before, at current time, I'm much more interested in code cleanliness and simple code than getting things too complicated. Especially because complicated code tends to take longer to write, and if it never gets done, there isn't much point. If we are going to do stream compression, I'd say we just compress everything we send to the client, and don't care about the cpu time and/or data that doesn't compress well. That is the simpler approach, and could get done in relatively easily. > - assume setup negociate the algorithm (client say i support x,y,z > then server send ok, let's go for y algorithm, this is how http does it) Yes, but IMO, I don't see the need for more than one algorithm. I'd say we just standardize on zlib. Sure, there may be other libraries which do marginally better. But once again, is it worth while to have another compression method that might be marginally better (in terms of code complication, library support, etc). If there is some library that is clearly better, or one is written, we could easily enough add support for it at that point. One could very well see things like: gzstart .... gzend and bz2start .... bz2end And so on. In many cases, the support for different methods is more for backwards compatiblity (at the time, A was best, but now B is better). We're not at that point, since we don't even have A. I'd also think that we could use the method that is done right now for the map commands. Basically, it goes like: C->S: setup map2cmd 1 S->C: setup map2cmd false C->S: setup map1acmd S->C: setup map1acmd false C->S: setup map1cmd S->C: setup map1cmd true (if the client sends true back for an earlier revision, the client stops its fallback method). That logic would find for compress methods down the road (setup compression gz, if that doesn't work, setup compression bz2, setup compression whatever). From daniel.daxler at vbsbowl.com Tue Mar 28 02:14:20 2006 From: daniel.daxler at vbsbowl.com (Daniel Daxler) Date: Tue, 28 Mar 2006 10:14:20 +0200 Subject: [crossfire] Protocol & compression. (tchize) In-Reply-To: Message-ID: Just thought I would mention this super fast compression and decompression, that I have had good experience with (over modem line). http://www.lzop.org/ Or the mini-version miniLZO. http://www.oberhumer.com/opensource/lzo/#download I believe the sever cannot spend much time to compress, and response time for the user is essential here. Faster is better than better compression ratio. (Apart from total map pre zipped package.) Any "small" package is not worth packing, and "small" may have to be redefined. From nicolas.weeger at laposte.net Tue Mar 28 11:23:56 2006 From: nicolas.weeger at laposte.net (Nicolas Weeger) Date: Tue, 28 Mar 2006 19:23:56 +0200 Subject: [crossfire] arch.c badly named functions In-Reply-To: <44283687.3020200@myrealbox.com> References: <44283687.3020200@myrealbox.com> Message-ID: <4429712C.7080309@laposte.net> > There are a few functions in arch.c which are named > get_archetype_xxxxxx but in fact return a new object of that archetype > using arch_to_object. I plan to rename those create_object_xxxxxx, > which i think is more suitable. Any objection? None by me, let they be renamed and some coherence made! :) Nicolas From temitchell at sympatico.ca Tue Mar 28 11:49:48 2006 From: temitchell at sympatico.ca (temitchell at sympatico.ca) Date: Tue, 28 Mar 2006 12:49:48 -0500 Subject: [crossfire] Indexed PNGS, was Re: Protocol & compression. Message-ID: <20060328174948.YWCQ20622.tomts10-srv.bellnexxia.net@smtp1.sympatico.ca> When making images for crossfire I tried to stick with indexed pngs and use the smallest colour size possible (usually 16-32 colours). This made the files much smaller than the same images in rgb format and usually there was no noticable differences since the graphics were too small for much shading or graduation. A lot of the indexed png images do not use the full 256 colours. Some are saved with smaller index table and some aren't. I suspect the ones that can be compressed are in the latter category. From tchize at myrealbox.com Tue Mar 28 12:17:47 2006 From: tchize at myrealbox.com (tchize) Date: Tue, 28 Mar 2006 20:17:47 +0200 Subject: [crossfire] Protocol & compression. In-Reply-To: <4428E517.3040303@sonic.net> References: <442506CB.6020701@sonic.net> <44281F50.3090902@myrealbox.com> <4428E517.3040303@sonic.net> Message-ID: <44297DCB.2080507@myrealbox.com> Mark Wedel a ?crit : >tchize wrote: > > >>-----BEGIN PGP SIGNED MESSAGE----- >>Hash: SHA1 >> >>Just a note about the suggested >>s->c compressed >>c->s compressed (yeah imho shoud go in both directions) >> >> > > I'm not sure if there is anything to really gain by the client compressing the >data. I can't really think of many times the client is actually sending enough >data that compression will do any good what so ever. The one exception might be >very long chat/shout/say messages, but even then, that seems fairly unlikely. > > Granted, probably wouldn't be that hard to add, but does add some at least >minimal complication, and if it doesn't gain us anything, I'd rather avoid that. > > > >>if we assume data contains a compressed list of 1 or more commands, i >>think the question on what need and what need not to be compressed os >>not immediate and we can have various attempt with various server / >>client version. The fact of assuming any command can be compressed by >>algorithm X but that not all commands will be compressed, is enough to >>write this protocol add-on. Then it's a matter of tuning the >>compression triggers, but this can be done without breaking >>interaction with previous versions. So imho, the 'when' to compress >>should not be fixed in protocol, only the how is to be fixed. >> >> > > correct. That was my assumption - the server would figure out what it thinks >is worthy of compression. A server with gobs of bandwidth but not a lot of cpu >time could decide that nothing is worth compressing. > > > >>One of the most important question is which algorithm do we use? You >>said you gave a try with zlib, but which algorithm does it uses? Does >>it involves a dictionnary? If yes, do we plan to reset the dictionnary >>content between each compress command or do we plan to keep it from >>begin to end? >> >> > > I used the 'compress' function of zlib: >http://www.zlib.net/manual.html#compress > > Since each call to compress is self contained, the compressed data then >includes all the dictionary or other info necessary. Note that given crossfire >will be working on multiple sockets, we can't use a library that holds any >state. And if there are new structures needed to hold state, this starts to >increase the complication level some. > > Not really, it's just a matter of storing a pointer to the library handle. I think if we should use a library that as some sort of permanent state. This will allows compression of similar messages far better (i think about all those you hit xxxx very hard' ) > > >>My opinion currently is >> - assume client can receive any data in compressed mode, but that not >>all datas are compressed (the sender has choice for every command) >> - assume the compression stream as something interleaved with not >>compressed stream, identified by a specific marker (compressed) >> - assume the compressed stream continuous (same 'zlib/any chosen >>algorithm' session, usefull considering number of repeated text messages) >> >> > > This point is the real gotcha however - since the server can choose what data >to compress, the question then becomes what portion of the commands are being >compressed? > > I was unclear. I just meaned, the server would do something like and his datas (--> decompress to and it's data) and his datas I never suggested to compress partially a command :) It's complicate and the job of compression libarry to do such decision :) I just said we should have both compressed and uncompressed command on the wire, sender choosing if a specific command is worth compressing. > > As I said before, at current time, I'm much more interested in code >cleanliness and simple code than getting things too complicated. Especially >because complicated code tends to take longer to write, and if it never gets >done, there isn't much point. > > I never suggested to complicate the job > If we are going to do stream compression, I'd say we just compress everything >we send to the client, and don't care about the cpu time and/or data that >doesn't compress well. That is the simpler approach, and could get done in >relatively easily. > > I don't agree, we can just have a flag telling 'can compress' when we send a command, and the socket writer will decide if it encapsulate it in a compression. However, once again if client assume data can be compressed or uncompressed, we can implement selective compression later and for now compress everything. > > >> - assume setup negociate the algorithm (client say i support x,y,z >>then server send ok, let's go for y algorithm, this is how http does it) >> >> > > Yes, but IMO, I don't see the need for more than one algorithm. I'd say we >just standardize on zlib. > > Don't agree, we might now be ok with zlib, but people might give a try to a few other algorithms and in 6 month someone comes with an algorithm that get 20% better compression with 5% less cpu overhead. That day we don't want to have an awfull hack in client/server protocol to handle this new algorithm. As you said, it's better to have a clean code, that also mean a clean protocol :) > Sure, there may be other libraries which do marginally better. But once >again, is it worth while to have another compression method that might be >marginally better (in terms of code complication, library support, etc). If >there is some library that is clearly better, or one is written, we could easily >enough add support for it at that point. One could very well see things like: > >gzstart >.... >gzend > >and > >bz2start >.... >bz2end > > And so on. In many cases, the support for different methods is more for >backwards compatiblity (at the time, A was best, but now B is better). We're >not at that point, since we don't even have A. > > This is not clean imho. I suggest using what is the current scheme of every commands sending, that is S-C -> which applied to compression gives S-C -> As currently all commands are words and data are either binary either text, i would suggest to use a very small command for compress header (so we don't lose all gain of compression :/) a simple character like # or @ or & should be enough The would end, in S -> C # > I'd also think that we could use the method that is done right now for the map >commands. Basically, it goes like: > >C->S: setup map2cmd 1 >S->C: setup map2cmd false >C->S: setup map1acmd >S->C: setup map1acmd false >C->S: setup map1cmd >S->C: setup map1cmd true > > I think it's good to have this C -> S: setup compress zlib,bzip2,rle S -> C: setup compress zlib In one exchange, both sides agreed to use zlib. If server doesn't support compression (like current server) or doesn't support any requested algorithm, you would obviously have C -> S: setup compress zlib,bzip2,rle S -> C: setup compress false please note there are already setup commands that send various parameter and let server confirm a part of them > (if the client sends true back for an earlier revision, the client stops its >fallback method). That logic would find for compress methods down the road >(setup compression gz, if that doesn't work, setup compression bz2, setup >compression whatever). > > > >_______________________________________________ >crossfire mailing list >crossfire at metalforge.org >http://mailman.metalforge.org/mailman/listinfo/crossfire > > > > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 189 bytes Desc: OpenPGP digital signature Url : http://mailman.metalforge.org/pipermail/crossfire/attachments/20060328/a129b71d/attachment.pgp From gabriele.diniciacci at gmail.com Tue Mar 28 14:15:52 2006 From: gabriele.diniciacci at gmail.com (Gabriele Dini Ciacci) Date: Tue, 28 Mar 2006 22:15:52 +0200 Subject: [crossfire] Invitation for developers to a vacation. The CF party Message-ID: I write this mail to invite all cf developers to my Lake house for a week end. Date is from friday 28 april (arrival) to sunday 30 of april (or monday 1 of may, I'm very frlexible, your leaving just depends on the day you find a cheap fligth) The week end can take various form, for example as a round table talking about 2.0 release, as a way to gather photos of us all togheder for the site, as a vacation to the wonderful place as "Lake D'Orta" (for free), or as an occasion to just meet people you talk from years. The invitation is open to all developers of cf, or contributors or people that has come in contact with me and interacted in some pacific way over irc, this exclude flamers and nasty poster, cause I fear they would flame in real life too, but, if they promise to be nice, it can be a good occasion of redention and to become all again all freinds and close some old still bleeding wound. My house has if I rember well 14 bed, and 3 bathrooms (italian style, so they are "complete"), the bedrooms are only 5, the other rooms are located in living rooms. Wife and GF are admitted and well accepted (it's an occasion to enjoy all togheder) Food expenses will be divided between all, do not expect more than 10 euros each day per person, wine and alcholic excuded. Fare for fligths from any location to "Milano Orio al Serio Airport" Milano BGY are rated MAX 50 euros tax included per trip.. so round trip, tax included will not cost more than 100 euros, notice that I personally never expended more than 54 euros for a roudn trip. http://www.ryanair.com/site/ For the rich they can land at Malpensa airport, that is very luxurious airport with luxurious flying company and confortable fligth. I Will pick you all up by car at the airport(s). What i can say more, come, for less than 100 euros you can spend a nice week-end in Italy.. I'm not sure that is gonna happen anytime soon again :) LINKS: Lake house location: http://maps.google.com/maps?f=q&hl=en&q=arona,+Italy&ll=45.818541,8.408607&spn=0.003813,0.01031 People has confirmed and has hi probablity to come tchize (on his own plane) gros (as tchize luggage or with a normal big plane) Best Regards Gabriele Dini Ciacci -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060328/99f2c55b/attachment.htm From mwedel at sonic.net Wed Mar 29 00:57:21 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 28 Mar 2006 22:57:21 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <44297DCB.2080507@myrealbox.com> References: <442506CB.6020701@sonic.net> <44281F50.3090902@myrealbox.com> <4428E517.3040303@sonic.net> <44297DCB.2080507@myrealbox.com> Message-ID: <442A2FD1.80401@sonic.net> tchize wrote: >>> >> This point is the real gotcha however - since the server can choose what data >> to compress, the question then becomes what portion of the commands are being >> compressed? >> >> > I was unclear. I just meaned, the server would do something like > and his datas > (--> decompress to and it's data) > and his datas Ok. That is what I was thinking. What I thought you were talking about was something like: compress_start command1 (compressed) command2 (compressed) ... compress_end type of setup, which then leads to the question how many of that data should be compressed. >> If we are going to do stream compression, I'd say we just compress everything >> we send to the client, and don't care about the cpu time and/or data that >> doesn't compress well. That is the simpler approach, and could get done in >> relatively easily. >> >> > I don't agree, we can just have a flag telling 'can compress' when we > send a command, and the socket writer will decide if it encapsulate it > in a compression. However, once again if client assume data can be > compressed or uncompressed, we can implement selective compression later > and for now compress everything. To me, there are really 3 ways to deal with the compression: 1) Have Send_With_Handling compress the packet, if so requested. Pros: Very simple to do - just a few lines of code to add. Cons: Each compress is only 1 command, so multiple small commands wouldn't be combined together and compresed to save more space. 2) Middle approach - have Send_With_Handling queue all data that can be compressed. The instance it gets called with data that shouldn't be compressed, it compresses everything it has queued up and sends that, then sends the uncompressed command. There would also need to be a seperate flush_queue() that is called at the end of each tick to also flush this queued data. Pros: Lets us combine various small packets into a single larger block to compress, thus getting better results (think a bunch of drawinfos). Cons: Adds some level of complication, but not a huge amount (need another buffer to store data to compress - this could be made a little simpler by having logic such that if the buffer would overflow, we compress that and then put the new block in that buffer to compress. Also, if there are a lot of compressible packets interleaved with non compressible (image/smooth/image/smooth), you have small blocks to try and compress again. 3) Compress everything sent. This should be done at a lower level (when we actually write to the socket). Pros: Everything is compressed - interleaved data isn't a problem. Cons: Stille harder to do - if we compress a block of data, but can only write half to the socket, we have to put the other have in a 'this data is compressed and send it next' buffer (current logic just moves the pointer in the ring buffer). We may end up compressing more data than we need - isn't really a convenient way to turn on/off compression. Now my personal thought is point 1 is really easy to do, and doesn't really in any way prevent point 2 from happening or make it harder to do. I'd personally start with the easiest solution and then start moving to more complicated solutions after we see how that does. For example, if hypothetically, it gets us 90% of the compression we could get compared to method #3, we may say 'that's good enough' If it gets us 50%, then clearly we need to do more work. > Don't agree, we might now be ok with zlib, but people might give a try > to a few other algorithms and in 6 month someone comes with an algorithm > that get 20% better compression with 5% less cpu overhead. That day we > don't want to have an awfull hack in client/server protocol to handle > this new algorithm. As you said, it's better to have a clean code, that > also mean a clean protocol :) but I don't consider the setup commands to figure out compression a bad hack. That code is all there already. The only really question would be should just a general 'compress' be used no matter what the compression method, or should each method have its own prefix (gz, bz2, lzop, whatever). I personally lean to the second - client knows what compress method it will be getting. But also, it then allows us to mix compression methods on the same socket. Suppose the client supports every compression method the server does. It could be that through experimentation, we know the method gz works best on maps, bz2 best on text, lzop best on something else. So for best results, the code could perhaps optimize for that (but then as I type this in, that starts to get pretty complicated). > > As currently all commands are words and data are either binary either > text, i would suggest to use a very small command for compress header > (so we don't lose all gain of compression :/) a simple character like # > or @ or & should be enough > > The would end, in > S -> C # Yes, a 1 or 2 character method would be best. perhaps use Z, since z seems to be the standard letter for compression. Then, it could be something like: zg - zlib (gzip) zb - bzip2 zo - lzop, etc. > > I think it's good to have this > C -> S: setup compress zlib,bzip2,rle > S -> C: setup compress zlib Having a comma separated list in the setup command is different than current semantics. That setup, I think you could do: C->S: setup compress zlib compress bzip2 compress rle And since the server process in that order, it would basically use that as preference (right most being one to use). Hmmm. I'll have see about doing that with the map commands From mwedel at sonic.net Wed Mar 29 01:02:11 2006 From: mwedel at sonic.net (Mark Wedel) Date: Tue, 28 Mar 2006 23:02:11 -0800 Subject: [crossfire] Protocol & compression. (tchize) In-Reply-To: References: Message-ID: <442A30F3.70606@sonic.net> Daniel Daxler wrote: > Just thought I would mention this super fast compression and decompression, > that I have had good experience with (over modem line). > http://www.lzop.org/ > > Or the mini-version miniLZO. > http://www.oberhumer.com/opensource/lzo/#download > > I believe the sever cannot spend much time to compress, and response time > for the user is essential here. > > Faster is better than better compression ratio. (Apart from total map pre > zipped package.) One reason I'm keen on zlib is because it is standardized. This is especially true because the png library requires zlib. So if you are going to compile the client, you must have zlib installed - this does not add a new dependency. Given that compression will, at least for the time being, be optional, choosing a library that many people might not have installed may not be the most useful. From bofh-lists-crossfire-dev at diegeekdie.com Wed Mar 29 02:41:40 2006 From: bofh-lists-crossfire-dev at diegeekdie.com (Sebastian Andersson) Date: Wed, 29 Mar 2006 10:41:40 +0200 Subject: [crossfire] Protocol & compression. (tchize) In-Reply-To: <442A30F3.70606@sonic.net> References: <442A30F3.70606@sonic.net> Message-ID: <20060329084140.GE25560@hogia.net> On Tue, Mar 28, 2006 at 11:02:11PM -0800, Mark Wedel wrote: > One reason I'm keen on zlib is because it is standardized. It also have many implementations in different langauges, so a pure java client could use it with a java implementation, a .Net client can use a .Net version of it without using unmanaged code. Regards, /Sebastian -- .oooO o,o Oooo. Ad: http://dum.acc.umu.se/ ( ) \_/ ( ) (o_ "Life is not fair, but root \ ( /|\ ) / (o_ //\ password helps!" -- The BOFH \_) (_/ (/)_ V_/_ From sa at hogia.net Wed Mar 29 02:38:56 2006 From: sa at hogia.net (Sebastian Andersson) Date: Wed, 29 Mar 2006 10:38:56 +0200 Subject: [crossfire] Protocol & compression. In-Reply-To: <442A2FD1.80401@sonic.net> References: <442506CB.6020701@sonic.net> <44281F50.3090902@myrealbox.com> <4428E517.3040303@sonic.net> <44297DCB.2080507@myrealbox.com> <442A2FD1.80401@sonic.net> Message-ID: <20060329083855.GD25560@hogia.net> On Tue, Mar 28, 2006 at 10:57:21PM -0800, Mark Wedel wrote: > 3) Compress everything sent. This should be done at a lower level (when we > actually write to the socket). > Cons: Stille harder to do - if we compress a block of data, but can only write > half to the socket, we have to put the other have in a 'this data is compressed > and send it next' buffer (current logic just moves the pointer in the ring > buffer). We may end up compressing more data than we need - isn't really a > convenient way to turn on/off compression. I've only glanced at the code, but is it not simply a matter of renaming Write_To_Socket to Really_Write_To_Socket, and then create a new Write_To_Socket that calls Really_Write_To_Socket if compression isn't turned on for the client? If it is turned on, put the output data in the z_stream (z_stream->avail_in = len, next_in = (Bytef*)buf), loop over deflate until avail_in == 0, and anything in the compression buffer is sent to Really_Write_To_Socket, thus sending or storing it like usual. There would also have to be a flush function to call deflate with the Z_SYNC_FLUSH flag to flush after the tick has been processed. To me, that seems like the simplest thing since the least amount of code would have to be changed and without compression turned on, the affected code paths are trivial to verify. The socket_struct would have to get a new z_stream* field and an extra buffer to store compressed data in (1024 bytes perhaps?). The code from my test program can actually be used for this after some clean up. And while looking at the networking code... Perhaps I've missed something, but isn't Nagle's algorithm disabled (TCP_NODELAY)? That makes the final message of each tick lag for up to 200ms on at least linux servers. On the other hand, with Nagle's algorithm disabled the server will probably send a lot of short packets. A hack, that might work is to turn off TCP_NODELAY, process a tick and then turn on TCP_NODELAY. At least linux servers will send any queued data when TCP_NODELAY is turned on. If the server supports TCP_CORK (linux-2.2 and newer, I think), that should be used instead, turn it on before the tick is processed and turn it off afterwards. (FreeBSD 4.5 and has a semanticly equivalent TCP_NOPUSH option, other BSD versions has, as far as I know, an incompatible TCP_NOPUSH that do not send the queued data until there is something more to send). Regards, /Sebastian -- .oooO o,o Oooo. Ad: http://dum.acc.umu.se/ ( ) \_/ ( ) (o_ "Life is not fair, but root \ ( /|\ ) / (o_ //\ password helps!" -- The BOFH \_) (_/ (/)_ V_/_ From mwedel at sonic.net Thu Mar 30 01:35:17 2006 From: mwedel at sonic.net (Mark Wedel) Date: Wed, 29 Mar 2006 23:35:17 -0800 Subject: [crossfire] Protocol & compression. In-Reply-To: <20060329083855.GD25560@hogia.net> References: <442506CB.6020701@sonic.net> <44281F50.3090902@myrealbox.com> <4428E517.3040303@sonic.net> <44297DCB.2080507@myrealbox.com> <442A2FD1.80401@sonic.net> <20060329083855.GD25560@hogia.net> Message-ID: <442B8A35.4080604@sonic.net> Sebastian Andersson wrote: > On Tue, Mar 28, 2006 at 10:57:21PM -0800, Mark Wedel wrote: >> 3) Compress everything sent. This should be done at a lower level (when we >> actually write to the socket). >> Cons: Stille harder to do - if we compress a block of data, but can only write >> half to the socket, we have to put the other have in a 'this data is compressed >> and send it next' buffer (current logic just moves the pointer in the ring >> buffer). We may end up compressing more data than we need - isn't really a >> convenient way to turn on/off compression. > > I've only glanced at the code, but is it not simply a matter of renaming > Write_To_Socket to Really_Write_To_Socket, and then create a new > Write_To_Socket that calls Really_Write_To_Socket if compression isn't > turned on for the client? If it is turned on, put the output data in the > z_stream (z_stream->avail_in = len, next_in = (Bytef*)buf), loop over > deflate until avail_in == 0, and anything in the compression buffer is > sent to Really_Write_To_Socket, thus sending or storing it like usual. > There would also have to be a flush function to call deflate with > the Z_SYNC_FLUSH flag to flush after the tick has been processed. > > To me, that seems like the simplest thing since the least amount of code > would have to be changed and without compression turned on, the affected > code paths are trivial to verify. The socket_struct would have to get > a new z_stream* field and an extra buffer to store compressed data in > (1024 bytes perhaps?). It isn't really hard to compress everything, but still harder than the first case I mentioned. The first case, add parameter to Send_With_Handling about compression, is probably about 5-10 lines of code, and that is the only code needed. No changing of structures. No renaming of functions. No extra buffers. No need to add calls to flush buffers, etc. However, it seems likely that a compress everything approach will be done at some point. But it certainly isn't the simplest. > And while looking at the networking code... > Perhaps I've missed something, but isn't Nagle's algorithm disabled > (TCP_NODELAY)? That makes the final message of each tick lag for up > to 200ms on at least linux servers. On the other hand, with Nagle's > algorithm disabled the server will probably send a lot of short packets. > A hack, that might work is to turn off TCP_NODELAY, process a tick and > then turn on TCP_NODELAY. At least linux servers will send any queued > data when TCP_NODELAY is turned on. If the server supports TCP_CORK > (linux-2.2 and newer, I think), that should be used instead, turn it on > before the tick is processed and turn it off afterwards. > (FreeBSD 4.5 and has a semanticly equivalent TCP_NOPUSH option, other > BSD versions has, as far as I know, an incompatible TCP_NOPUSH that do > not send the queued data until there is something more to send). At some level, a strong case for redoing most of the socket code could be made. However, you are correct that TCP_NODELAY really should be used. But you are also right in that if we just enabled, we'd send a lot of small packets. I'm not 100% sure, but I'd think if we did something like: setsockopt(.., TCP_NDELAY, 1) write_to_socket("hello") setsockopt(..., TCP_NDELAY, 0) (hello should be replaced by something else), but I'd think that would cause all data currently in the TCP buffer to get flushed out. Since there has also been a discussion that the server should send info for each tick it processes (so animations and other stuff can remain in sync), sending that instead of the hello would probably work fine, and kill two birds with one stone, so to speak. I'm not particularly fond of using features specific to one OS - starts to make the code messier. And generally speaking, I don't think TCP_CORK should really be necessary - basically, the code figures out everything to send to one player at once, sends it, then moves to the next player, etc. So all that data should be generated at a pretty small time gap. the only exceptions I can think of this are shout/tell/says messages (as one player instigates them it sends them to the other players at that time), and sound events (sort of same reason, but map2 should move the sound events into that command). From tchize at myrealbox.com Thu Mar 30 13:55:43 2006 From: tchize at myrealbox.com (tchize) Date: Thu, 30 Mar 2006 21:55:43 +0200 Subject: [crossfire] Invitation for developers to a vacation. The CF party In-Reply-To: References: Message-ID: <442C37BF.4010507@myrealbox.com> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Gabriele Dini Ciacci a ?crit : > I write this mail to invite all cf developers to my Lake house for > a week end. > > Date is from friday 28 april (arrival) to sunday 30 of april (or > monday 1 of may, I'm very frlexible, your leaving just depends on > the day you find a cheap fligth) > > The week end can take various form, for example as a round table > talking about 2.0 release, as a way to gather photos of us all > togheder for the site, as a vacation to the wonderful place as > "Lake D'Orta" (for free), or as an occasion to just meet people you > talk from years. Do i bring my roleplay books? :D > > The invitation is open to all developers of cf, or contributors or > people that has come in contact with me and interacted in some > pacific way over irc, this exclude flamers and nasty poster, cause > I fear they would flame in real life too, but, if they promise to > be nice, it can be a good occasion of redention and to become all > again all freinds and close some old still bleeding wound. Does someone provide the swords? > > My house has if I rember well 14 bed, and 3 bathrooms (italian > style, so they are "complete"), the bedrooms are only 5, the other > rooms are located in living rooms. Do you populate bedrooms before arrival with welcome gifts? > > Wife and GF are admitted and well accepted (it's an occasion to > enjoy all togheder) What kind of 'enjoyement' did you plan with other CFers GF/Wife? > > Food expenses will be divided between all, do not expect more than > 10 euros each day per person, wine and alcholic excuded. Do Belgians have to provide the real Beer? > > Fare for fligths from any location to "Milano Orio al Serio > Airport" Milano BGY are rated MAX 50 euros tax included per trip.. > so round trip, tax included will not cost more than 100 euros, > notice that I personally never expended more than 54 euros for a > roudn trip. http://www.ryanair.com/site/ > > For the rich they can land at Malpensa airport, that is very > luxurious airport with luxurious flying company and confortable > fligth. > > I Will pick you all up by car at the airport(s). > > What i can say more, come, for less than 100 euros you can spend a > nice week-end in Italy.. I'm not sure that is gonna happen anytime > soon again :) > > > LINKS: Lake house location: > http://maps.google.com/maps?f=q&hl=en&q=arona,+Italy&ll=45.818541,8.408607&spn=0.003813,0.01031 > > > > People has confirmed and has hi probablity to come tchize (on his > own plane) Problem is - - car is quite expensive to italy - - airport ... Don't really like to put my small air plane in their big air plane (had some problems in marseille recently) So i will most probably come by classical plane and most probably without my ultralight :( (Each time you bring it in an airport it's jeopardy to know if they will accept it) > gros (as tchize luggage or with a normal big plane) I heard the wheel seats are cheap but very cold during flight PS has been suggested to postpone one week the meeting, as flight are way cheaper at week-end of 6-7 may. Am ok with it. > > > > Best Regards Gabriele Dini Ciacci > > > > ---------------------------------------------------------------------- > > > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFELDe/HHGOa1Q2wXwRAnOpAJ9ew5PLU95fwOWSd3lcFRyCasHNWgCfTLad tB4/Uc6vCwuiKeBz9telSIc= =O3tI -----END PGP SIGNATURE----- From gabriele.diniciacci at gmail.com Thu Mar 30 16:25:42 2006 From: gabriele.diniciacci at gmail.com (Gabriele Dini Ciacci) Date: Fri, 31 Mar 2006 00:25:42 +0200 Subject: [crossfire] Invitation for developers to a vacation. The CF party Message-ID: Gabriele Dini Ciacci a ?crit : > I write this mail to invite all cf developers to my Lake house for > a week end. > > Date is from friday 28 april (arrival) to sunday 30 of april (or > monday 1 of may, I'm very frlexible, your leaving just depends on > the day you find a cheap fligth) > > The week end can take various form, for example as a round table > talking about 2.0 release, as a way to gather photos of us all > togheder for the site, as a vacation to the wonderful place as > "Lake D'Orta" (for free), or as an occasion to just meet people you > talk from years. >Do i bring my roleplay books? :D We are to few players and we have by FAR many thigns to see :) (and to eat...) > > The invitation is open to all developers of cf, or contributors or > people that has come in contact with me and interacted in some > pacific way over irc, this exclude flamers and nasty poster, cause > I fear they would flame in real life too, but, if they promise to > be nice, it can be a good occasion of redention and to become all > again all freinds and close some old still bleeding wound. >Does someone provide the swords? Should have enoght cuttign material for all the salami you can eat :D > > My house has if I rember well 14 bed, and 3 bathrooms (italian > style, so they are "complete"), the bedrooms are only 5, the other > rooms are located in living rooms. >Do you populate bedrooms before arrival with welcome gifts? Wellcome girls only.. sorry > > Wife and GF are admitted and well accepted (it's an occasion to > enjoy all togheder) >What kind of 'enjoyement' did you plan with other CFers GF/Wife? While you are occupeied with wellcome girls I will unit test your GF/Wife > > Food expenses will be divided between all, do not expect more than > 10 euros each day per person, wine and alcholic excuded. >Do Belgians have to provide the real Beer? Presents are allways wellcome, but you will have to drink it all :D > > Fare for fligths from any location to "Milano Orio al Serio > Airport" Milano BGY are rated MAX 50 euros tax included per trip.. > so round trip, tax included will not cost more than 100 euros, > notice that I personally never expended more than 54 euros for a > roudn trip. http://www.ryanair.com/site/ > > For the rich they can land at Malpensa airport, that is very > luxurious airport with luxurious flying company and confortable > fligth. > > I Will pick you all up by car at the airport(s). > > What i can say more, come, for less than 100 euros you can spend a > nice week-end in Italy.. I'm not sure that is gonna happen anytime > soon again :) > > > LINKS: Lake house location: > http://maps.google.com/maps?f=q&hl=en&q=arona,+Italy&ll=45.818541,8.408607&spn=0.003813,0.01031 > > > > People has confirmed and has hi probablity to come tchize (on his > own plane) Problem is - - car is quite expensive to italy - - airport ... Don't really like to put my small air plane in their big air plane (had some problems in marseille recently) So i will most probably come by classical plane and most probably without my ultralight :( (Each time you bring it in an airport it's jeopardy to know if they will accept it) :(( > gros (as tchize luggage or with a normal big plane) >I heard the wheel seats are cheap but very cold during flight eeh >PS has been suggested to postpone one week the meeting, as flight are >way cheaper at week-end of 6-7 may. Am ok with it. Suggestion was from me! :) Sure portponing it a week make it MUCH cheaper for everyone!! Let's do it, so come in the week-ed AROUND 6-7, come before or after is no problem, stay as much as you can, at least 5 day is best so you can see Milano and Bergamo too (apart Lake house) > Best Regards Gabriele Dini Ciacci > _______________________________________________ crossfire mailing > list crossfire at metalforge.org > http://mailman.metalforge.org/mailman/listinfo/crossfire P.S. I will pay the food for all those that come and does not have anymore money after that big (50 euros) expense. That include Maligor for now, others just say that, I have limited budget (say I can expend 300 euros on your food) _______________________________________________ crossfire mailing list crossfire at metalforge.org http://mailman.metalforge.org/mailman/listinfo/crossfire -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mailman.metalforge.org/pipermail/crossfire/attachments/20060331/13565cd4/attachment.htm From tchize at myrealbox.com Fri Mar 31 04:14:48 2006 From: tchize at myrealbox.com (Tchize) Date: Fri, 31 Mar 2006 12:14:48 +0200 Subject: [crossfire] Invitation for developers to a vacation. The CF In-Reply-To: References: Message-ID: <442D0118.4050000@myrealbox.com> Gabriele Dini Ciacci a ?crit : > > > >Do you populate bedrooms before arrival with welcome gifts? > > Wellcome girls only.. sorry I bet i'll have to satisify myself with it :D > > > > > > Wife and GF are admitted and well accepted (it's an occasion to > > enjoy all togheder) > > >What kind of 'enjoyement' did you plan with other CFers GF/Wife? > > While you are occupeied with wellcome girls I will unit test your GF/Wife Yeah, try to unit test a void, that could be fun :) > > > P.S. > I will pay the food for all those that come and does not have anymore > money > after that big (50 euros) expense. Around 6-7 may, it cost a total trip price of 30 euros from belgium (4 euros + taxes) From elmex at ta-sa.org Fri Mar 31 19:52:06 2006 From: elmex at ta-sa.org (Robin Redeker) Date: Sat, 1 Apr 2006 03:52:06 +0200 Subject: [crossfire] Random encounters Message-ID: <20060401015206.GA6516@elmex> Hi! Is that right what i just read: The random encounters where took out of the code around 2001? Why was it removed? Is it possbile to reimplement it? Robin -- elmex at ta-sa.org / robin at nethype.de / r.redeker at gmail.com Robin Redeker