Page 1 of 1

UselessMine - Create Mines with the Useless Flag Once Again!

Posted: Thu Sep 15, 2011 10:37 am
by SkillDude
Plugin Name: Useless Mine
Minimum Version: 2.4.0
License: Public Domain
Author: sigonasr2 (Joshua Sigona)

This plugin is the Useless Mine plugin. It has once been created beforehand by Enigma, and has been re-implemented for version 2.4.0 along with a few tweaks.

The original shot types from the 2.0 version of Useless Mine have been removed. The cr, sr, and sb options were all neat, but were not nearly as useful or guaranteed as a shockwave, so they have been removed. Because there is only one type of mine now, the command has been stripped down to just /mine. This should make it easier for players to type and realize what to do.

Just like Enigma's plugin, it is completely possible to avoid the mine if you creep up to it very slowly. So there can be some tactic to disarming them. :)

Plugin considers the _shockOutRadius variable, so changing that will automatically increase or decrease the range of the mine accordingly!

Speaking of making it easier for players, whenever they do grab a useless flag, they are notified with the message "You have grabbed a useless flag! Type /mine to set a mine!". Very helpful for them and provides them with information about the mine plugin without needed a help file.

In addition, this plugin also has some witty comments when players get destroyed by mines. The number of mines still set, just like the previous version is also displayed in [] brackets at the end of the server message.

Enjoy! Plugin is in the Public Domain.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Thu Sep 22, 2011 9:27 pm
by allejo
Nothing against Enigma's genius-ness, but this is a much a simpler version. love it :D

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Sat Oct 01, 2011 11:20 pm
by Enigma
You know, I have thought about just using a single mine type for a while, and I actually started on a plug-in that only used shock waves. Somehow I managed to lose the code, and I didn't want to start all over again, so I gave up. I have been away from BZFlag as well.

I like that someone made changes to my code :-). And you wrote the whole thing with only 250 lines of code. I always end up with a ton more code than I need. The reason is I get stuck on smaller problems, or sub-problems of my original problem. I'll spend a lot of time thinking about better ways doing things. But anyways, I also like the random messages.

Although I probably won't write any plug-ins, I have a few comments on your code. I mean them as constructive comments.

If you use a map instead of a switch statement, your code will clean up better.

Code: Select all

// Define this in your class.
std::map<int, std::string> wittyMsgMap;

// Put this in your constructor.
wittyMsgMap[0] = '"%s was killed by %s's mine. [%d]";
wittyMsgMap[1] = "%s was owned by %s's mine. [%d]";
...
wittyMsgMap[19] = "I ascertain that %s has been ruptured by a mine created from the heavens with the name dubbed %s. [%d]";


// Then send the message.
msg = wittyMsgMap[rand() % wittyMsgMap.size()];
bz_sendTextMessagef(BZ_SERVER, BZ_ALLUSERS, msg.c_str(), pr->callsign.c_str(), kr->callsign.c_str(), CountMines());
All of the functions in your class are declared as virtual. You might want to look up virtual functions. A virtual function is a function that can be re-implemented by a subclass. There are also pure virtual functions. Pure virtual functions must be redefined by every direct subclass. Using virtual functions here is harmless, but I don't think you intend on subclassing the uselessmine class. It would be better to write:

Code: Select all

virtual const char* Name (){return "Useless Mine";}
	void Init (const char* /*config*/);
	void Event(bz_EventData *eventData);
	bool SlashCommand (int playerID,bz_ApiString command,bz_ApiString message,bz_APIStringList* params);
	void Cleanup ();
	int CountMines();
	void SetMine(int playerID,float pos1,float pos2,float pos3);
	void RemoveMine(int id);
	void RemoveAllMines(int playerID);
There is a better way you could count the mines. Instead of looping through an array every time you want to count the number of mines, you could use a state variable. When someone adds a mine, increment by one, and when someone removes a mine, decrement by one.

What wasn't working with the following code? Using the flag grabbed event would be a better way of handling flag grabbed messages. Maybe instead of getting the flag type from the player, you should get the flag type from the event data? The grabbed flag type is stored in the bz_FlagGrabbedEventData_V1 class. Using the flag grabbed event, you could remove the minenotify array.

Code: Select all

case bz_eFlagGrabbedEvent: {
			playerID=((bz_FlagGrabbedEventData_V1*)eventData)->playerID;
			/*bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);
			//bz_debugMessage(0,bz_getName(((bz_FlagGrabbedEventData_V1*)eventData)->flagID).c_str());
			if (pr) {
			if (!strcmp(pr->currentFlag.c_str(),"US")) {
				bz_sendTextMessage(BZ_SERVER,playerID,"You grabbed a Useless flag! Type /mine at any time to set a useless mine!");
			}
			bz_freePlayerRecord(pr);
			}*/
			minenotify[playerID]=1;
		}break;
I'm pretty sure calling delete on a null pointer does nothing, so it isn't necessary to check if a pointer actually points to something before deleting it.

Code: Select all

if (pr)
  bz_freePlayerRecord(pr);
if (kr)
  bz_freePlayerRecord(kr);
If anything, you should perform these checks when you allocate memory.

Code: Select all

bz_BasePlayerRecord *pr = bz_getPlayerByIndex(playerID);

if (!pr)
  return;

bz_BasePlayerRecord *kr = bz_getPlayerByIndex(mineplayer[i]);

if (!kr)
{
  bz_freePlayerRecord(pr);
  return;
}

// If we get to this point, then everything allocated properly.
In my original code, I actually used template metaprogramming to unroll loops at compile time when computing the vector product. I honestly shouldn't have done that because it overly complicated things when it wasn't necessary. My excuse is I was learning about template metaprogramming at the time ;-). But anyways, I guess you would prefer a bounding box rather than a sphere? I would just use the Euclidean distance http://en.wikipedia.org/wiki/Euclidean_distance.

Code: Select all

for (i=0;i<255;i++) {
					if (mine[i] && mineplayer[i]!=playerID && (pr->team==eRogueTeam || pr->team!=mineteam[i])) {
						if (pr->lastKnownState.pos[0]>minepos[i][0]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[0]<minepos[i][0]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[1]>minepos[i][1]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[1]<minepos[i][1]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[2]>minepos[i][2]-((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& pr->lastKnownState.pos[2]<minepos[i][2]+((bz_getBZDBDouble("_shockOutRadius")*0.75))
						&& safetytime[playerID]<=bz_getCurrentTime()
						) {
							bz_fireWorldWep("SW",2.0,BZ_SERVER,minepos[i],0,0,i+1000,0);
							RemoveMine(i);
						}
					}
			}
I think that is about it. My only other suggestion would be to use standard library containers instead of constant length arrays. You would need a random access container, since removing "mines" requires random access. That is, you need to be able to remove elements from the middle of the array.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Sat Oct 01, 2011 11:30 pm
by Enigma
Actually one more suggestion. For good programming, you should avoid repeating yourself. I'm referring to the DRY principle. What I mean is, you should avoid duplicate code as much as possible.

You use 255 for the size of several arrays. You should define a constant, say
MAX_MINE_COUNT = 255;
Then use this everywhere it makes sense. Later if you decide to change the size, you will only need to change one variable. Otherwise you would have to change every instance of 255. you can apply the same concept to functions and variables and probably other things.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Nov 02, 2011 12:29 am
by cidentan50
The problem with any of these mine plugins is that if a user lays a lot of mines, he or she will get warned and eventually kicked for spamming. That's because /mine is treated like any other chat message. I've run into that several times on maps with mine plugins. Is there a way to have the BZflag spam checker not count certain types of messages?

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Nov 02, 2011 1:37 am
by SkillDude
Implement a custom spam kicker if you are inclined to needing to kick other players that do have spam messages to make sure the command in question is not included in that. Better yet, just do that for any slash command the user tries to run. However, I highly recommend just using spam warning times of 1 second. Anyone who talks with messages at least a second apart is definitely not spamming, or not spamming to the extent where hundreds of messages are appearing.

As an offset note, thank you Enigma for pointing out your programming tips and advice. It will really benefit me in the future.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Nov 02, 2011 8:06 pm
by FangUp
May i ask you, is this the mine you guys are commenting about, the mine that may be set on SW or SB?

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Nov 02, 2011 9:26 pm
by cidentan50
No, this thread is about the plugin that's SW only. You type /mine and that's it. No other options.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Nov 02, 2011 9:33 pm
by FangUp
ok. Because i once played on a map where there were around 100 US flags. You could write in "/mine SW" or "/mine SB" (practicly same result) Good idea for the mines.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Thu Mar 01, 2012 12:05 am
by Jacko H
what is the actual thing you put in the config? -loadplugin (what in here?)

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Thu Mar 01, 2012 12:47 am
by blast
It doesn't take any special options. Just load the plugin like you would any other.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Tue Apr 17, 2012 1:12 pm
by easy tank
I cannot load the plugin. I put -loadplugin ./uselessmine.cpp in config file and it doesn't work :/
Can anyone help me with that problem? Thanks alot!

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Tue Apr 17, 2012 1:38 pm
by joevano
Easy Tank wrote:I cannot load the plugin. I put -loadplugin ./uselessmine.cpp in config file and it doesn't work :/
Can anyone help me with that problem? Thanks alot!
That is the source code for the plugin. You must compile it for the specific version of bzflag you are using.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Tue Apr 17, 2012 1:42 pm
by Jacko H
sig can you please compile so we can use it.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Tue Apr 17, 2012 2:38 pm
by blast
Anyone serious about server hosting should be compiling the server from the latest SVN source already. Just add the plugin to your build system.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Wed Apr 18, 2012 12:30 am
by I_Died_Once
Easy Tank & Jack-O, I could have sworn I told you this last night when you were asking me on the Apocalypse... You (or whoever is hosting your server) are going to have to compile the plugin from source. In short, to do this you 'cd' into the directory where the source (and other files associated) are needed and type in 'make' - (assuming you are using a linux operating system) and optionally 'make install'

See this page for more info, this is the full run down on exactly what you are seeking. If this is out of the scope of your capabilities, you might want to reconsider taking on hosting duties.

http://wiki.bzflag.org/Plug-ins

Try listening when someone is telling you what you are seeking to find out next time.
Much love & good luck.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Fri May 11, 2012 9:41 pm
by blast
Here is a compiled DLL for version 2.4.0 on Windows.

Re: UselessMine - Create Mines with the Useless Flag Once Ag

Posted: Fri Sep 05, 2014 6:24 am
by allejo
And because I felt like writing my own implementation out of boredom, knock yourself out. It works the same way as sigonasr2's implementation, it's just written differently.

Like with all my plug-ins, read the README file and my source code is documented.

README
UselessMine.cpp

Update 2016-01-18: I've fixed a plug-in bug that made kill assignment inaccurate with my plug-in (commit 39cc1be).
Update 2018-03-30: The plug-in has been updated to require bzfs 2.4.14+ which improves kill assignments a lot.

Re: UselessMine - Create Mines with the Useless Flag Once Again!

Posted: Sun Jun 03, 2018 2:47 pm
by optic delusion
In the grenade plugin, we can make the size of the shockwave produced smaller than _shockOutRadius, (but not larger). This is done by ending the shock early. Also, the speed of the shock's enlargement can be controled.
Can this effect be applied to this plugin?

Re: UselessMine - Create Mines with the Useless Flag Once Again!

Posted: Fri Jun 08, 2018 5:55 am
by allejo
optic delusion wrote:
Sun Jun 03, 2018 2:47 pm
In the grenade plugin, we can make the size of the shockwave produced smaller than _shockOutRadius, (but not larger). This is done by ending the shock early. Also, the speed of the shock's enlargement can be controled.
Can this effect be applied to this plugin?
I believed I followed up with you about this on IRC, but to document the answer to your question: this is no longer possible. After the world weapon API was rewritten in 2.4.14, all world weapons respect and behave like a regular player shot would. This was done since BZFlag is going to start moving towards consistency for several aspects of the game.

The way the grenade plug-in works, if I remember correctly, is that it bypasses the API and handles sending shots on its own, which is why it has control of modifying SWs like that.

Re: UselessMine - Create Mines with the Useless Flag Once Again!

Posted: Sat Jun 09, 2018 12:04 am
by Zehra
To add a bit to what allejo has said, there is also a few minor notes I'll make.

The grenade plug-in did a few things which were a bit different from other plug-ins.

Code: Select all

#include "bzfsAPI.h"
#include "../src/bzfs/bzfs.h"

#include <memory>

using namespace std;
It access directly "bzfs.h", a practice which is highly and strongly discouraged.(Note this is not "bzfsAPI.h", but "bzfs.h")
It also seems to "directly" fire world weapons, instead of using the API.

Code: Select all

static int sendShot(FlagType *f, float lifetime, TeamColor t, float *p,
                    float tilt, float dir, int shotId, float speed) {
  void *buf, *bufStart = getDirectMessageBuffer();
  FiringInfo firingInfo;
  firingInfo.timeSent = (float)TimeKeeper::getCurrent().getSeconds();
  firingInfo.flagType = f;
  firingInfo.lifetime = lifetime;
  firingInfo.shot.player = ServerPlayer;
  memmove(firingInfo.shot.pos, p, 3 * sizeof(float));
  const float tiltFactor = cosf(tilt);
  firingInfo.shot.vel[0] = speed * tiltFactor * cosf(dir);
  firingInfo.shot.vel[1] = speed * tiltFactor * sinf(dir);
  firingInfo.shot.vel[2] = speed * sinf(tilt);
  firingInfo.shot.id = shotId;
  firingInfo.shot.dt = 0.0f;
  firingInfo.shot.team = t;
  buf = firingInfo.pack(bufStart);
  broadcastMessage(MsgShotBegin, (char *) buf - (char *) bufStart, bufStart);
  return shotId;
}
It basically just sends a "shot fired" packet to the server in a ways. (if I am not mistaken.)
So these days, all shots basically get the same effect and no longer is it possible to generate entirely different lasting shots, infinitely lasting bullets..etc

There is some clever trickery which could be used to adjust the amount of times a shot lasts, I'm assuming, but doing so will have a few unintended side effects and can't be ported towards shockwaves and lasers.(And it would be a hack basically.)
(Shockwaves and lasers are the only weapons which do not end a shot when it hits a tank.)

The handling of the shots:

Code: Select all

  float minRange = (float) bz_getBZDBDouble("_grenadeMinRange");
  float maxRange = (float) bz_getBZDBDouble("_grenadeMaxRange");
  float lifetime = (float) bz_getBZDBDouble("_grenadeTriggerTime");
  float duration = (float) bz_getBZDBDouble("_grenadeShockDuration");
This was done when we were able to adjust shot lifetimes and more.

References:
Shockwave death plug-in Before API change.

Code: Select all

void SWDeathHandler::Event ( bz_EventData *eventData )
{
  // We only handle the player death event, so bail out otherwise
  if (eventData->eventType != bz_ePlayerDieEvent)
    return;

  // Cast our event data so we can access the death position
  bz_PlayerDieEventData_V1 *dieData = (bz_PlayerDieEventData_V1*)eventData;

  // Retrieve the current reload time value
  float reloadTime = (float)bz_getBZDBDouble("_reloadTime");

  // If _swDeathReloadFactor is defined and greater than zero, multiply the
  // reload time by this factor
  if (bz_BZDBItemExists("_swDeathReloadFactor") && bz_getBZDBDouble("_swDeathReloadFactor") > 0)
    reloadTime *= (float)bz_getBZDBDouble("_swDeathReloadFactor");

  // Fire a shockwave where the player died
  bz_fireWorldWep("SW", reloadTime, BZ_SERVER, dieData->state.pos, 0, 0, 0, 0.0f);
}
Shockwave plug-in after API change.

Code: Select all

void SWDeathHandler::Event ( bz_EventData *eventData )
{
  // We only handle the player death event, so bail out otherwise
  if (eventData->eventType != bz_ePlayerDieEvent)
    return;

  // Cast our event data so we can access the death position
  bz_PlayerDieEventData_V1 *dieData = (bz_PlayerDieEventData_V1*)eventData;

  // Fire a shockwave where the player died
  float vector[3] = {0, 0, 0};
  bz_fireServerShot("SW", dieData->state.pos, vector);
}
Hopefully this provides a bit of insight into the API changes and explains a bit of things as well.

-Zehra