mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
This restores sending items to EVENT_TRADE that are updated by source
controlled delivery tasks which was removed in 7cf96ca2d8.
That patch filtered out items consumed by task updates to fix a few bugs
with items being returned despite incrementing a task:
- If an npc without a quest trade event handler was the target of a
delivery task for a NoDrop/non-Quest item, the npc would auto return
it due to the `ReturnNonQuestNoDropItems` rule.
- If an npc without a quest trade event handler was the target of a
delivery task for a non-NoDrop item, the item would be added to the
npc's loot.
- If an npc with an EVENT_ITEM/EVENT_TRADE quest handler used the Lua
or Perl trade plugins, the plugins would return task items unless
specific checks for the turned in slots existed.
The quest plugin item returns are problematic for this since they just
summon to return items not handled by the script
e.g. For a task to deliver N Large Fruit Bat Wings (item id 19616),
if a player turned in 1 Wing in slot 1 and a stack of 20 Wings in slot
2, the task would be incremented 21 times and the following Lua trade
handler would return the stack of 20 from the 2nd trade slot:
```lua
function event_trade(e)
local item_lib = require("items")
if item_lib.check_turn_in(e.trade, { item1 = 19616 }) then
eq.debug("Lua consumed 1 slot and will return other slots")
end
item_lib.return_items(e.self, e.other, e.trade)
end
```
This also occured with the perl plugin though slightly differently
since that plugin returns all slots unless the exact handin slot count
matches (requiring check_handin conditions for all slots):
```perl
sub EVENT_ITEM {
if (plugin::check_handin(\%itemcount, 19616 => 1)) {
# No issue if only one slot used for trade (item not returned)
}
# Perl fails handin check if multiple slots not checked and returns all
plugin::return_items(\%itemcount);
}
```
While that patch solved the issue, it's inconvenient and wrong to not
receive items in trade events used in a source task update. It breaks
existing trade scripts for tasks that aren't quest controlled and it
forces tasks to be changed to quest controlled and manually updated to
script any extra behavior.
This patch stores the task update count on the item instance before
dispatching it to quests. The burden is now on quests and plugins to
use that value in order to prevent returning items consumed by tasks.
`ItemInstance::RemoveTaskDeliveredItems` has been added to simplify
handling this in plugins which is also used for non-quest item returns.
175 lines
4.6 KiB
C++
175 lines
4.6 KiB
C++
/*
|
|
Embperl.h
|
|
---------------
|
|
eqemu perl wrapper
|
|
Eglin
|
|
*/
|
|
|
|
#ifndef EMBPERL_H
|
|
#define EMBPERL_H
|
|
|
|
#ifdef EMBPERL
|
|
|
|
#include "zone_config.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
// this option disables distinct int/float/string function argument types for
|
|
// backwards compatibility with current perl api usage
|
|
// e.g. quest::settimer(0, 1) using number for timer name instead of string
|
|
#define PERLBIND_NO_STRICT_SCALAR_TYPES
|
|
#include <perlbind/perlbind.h>
|
|
namespace perl = perlbind;
|
|
|
|
#ifdef WIN32
|
|
#define snprintf _snprintf
|
|
#endif
|
|
|
|
//perl defines these macros and dosent clean them up, lazy bastards. -- I hate them too!
|
|
#ifdef Copy
|
|
#undef Copy
|
|
#endif
|
|
|
|
#ifdef list
|
|
#undef list
|
|
#endif
|
|
|
|
#ifdef write
|
|
#undef write
|
|
#endif
|
|
|
|
#ifdef bool
|
|
#undef bool
|
|
#endif
|
|
|
|
#ifdef Zero
|
|
#undef Zero
|
|
#endif
|
|
//These need to be cleaned up on FreeBSD
|
|
|
|
#ifdef __FreeBSD__
|
|
#ifdef do_open
|
|
#undef do_open
|
|
#endif
|
|
|
|
#ifdef do_close
|
|
#undef do_close
|
|
#endif
|
|
#endif
|
|
|
|
//so embedded scripts can use xs extensions (ala 'use socket;')
|
|
EXTERN_C void boot_DynaLoader(pTHX_ CV* cv);
|
|
EXTERN_C void xs_init(pTHX);
|
|
|
|
extern const ZoneConfig *Config;
|
|
class Embperl
|
|
{
|
|
private:
|
|
//if we fail inside a script evaluation, this will hold the croak msg (not much help if we die during construction, but that's our own fault)
|
|
mutable std::string errmsg;
|
|
//kludgy workaround for the fact that we can't directly do something like SvIV(get_sv($big[0]{ass}->{struct}))
|
|
SV * my_get_sv(const char * varname) {
|
|
char buffer[256];
|
|
snprintf(buffer, 256, "if(defined(%s)) { $scratch::temp = %s; } else { $scratch::temp = 'UNDEF'; }", varname, varname);
|
|
eval(buffer);
|
|
return get_sv("scratch::temp", false);
|
|
}
|
|
|
|
//install a perl func
|
|
void init_eval_file(void);
|
|
|
|
bool in_use; //true if perl is executing
|
|
protected:
|
|
//the embedded interpreter
|
|
PerlInterpreter * my_perl;
|
|
|
|
void DoInit();
|
|
|
|
public:
|
|
Embperl(void); //This can throw errors! Buyer beware
|
|
~Embperl(void);
|
|
|
|
void Reinit();
|
|
|
|
//return the last error msg
|
|
std::string lasterr(void) const { return errmsg;};
|
|
//evaluate an expression. throws string errors on fail
|
|
int eval(const char * code);
|
|
//execute a subroutine. throws lasterr on failure
|
|
int dosub(const char * subname, const std::vector<std::string> * args = nullptr, int mode = G_SCALAR|G_EVAL);
|
|
|
|
//Access to perl variables
|
|
//all varnames here should be of the form package::name
|
|
//returns the contents of the perl variable named in varname as a c int
|
|
int geti(const char * varname) { return static_cast<int>(SvIV(my_get_sv(varname))); };
|
|
//returns the contents of the perl variable named in varname as a c float
|
|
float getd(const char * varname) { return static_cast<float>(SvNV(my_get_sv(varname)));};
|
|
//returns the contents of the perl variable named in varname as a string
|
|
std::string getstr(const char * varname) {
|
|
SV * temp = my_get_sv(varname);
|
|
return std::string(SvPV_nolen(temp),SvLEN(temp));
|
|
}
|
|
|
|
//put an integer into a perl varable
|
|
void seti(const char *varname, int val) const {
|
|
SV *t = get_sv(varname, true);
|
|
sv_setiv(t, val);
|
|
}
|
|
//put a real into a perl varable
|
|
void setd(const char *varname, float val) const {
|
|
SV *t = get_sv(varname, true);
|
|
sv_setnv(t, val);
|
|
}
|
|
//put a string into a perl varable
|
|
void setstr(const char *varname, const char *val) const {
|
|
SV *t = get_sv(varname, true);
|
|
sv_setpv(t, val);
|
|
}
|
|
// put a pointer into a blessed perl variable
|
|
void setptr(const char* varname, const char* classname, void* val) const {
|
|
SV* t = get_sv(varname, GV_ADD);
|
|
sv_setref_pv(t, classname, val);
|
|
}
|
|
|
|
// put key-value pairs in hash
|
|
void sethash(const char *varname, std::map<std::string,std::string> &vals)
|
|
{
|
|
std::map<std::string,std::string>::iterator it;
|
|
|
|
// Get hash and clear it.
|
|
HV *hv = get_hv(varname, TRUE);
|
|
hv_clear(hv);
|
|
|
|
// Iterate through key-value pairs, storing them in hash
|
|
for (it = vals.begin(); it != vals.end(); ++it)
|
|
{
|
|
int keylen = static_cast<int>(it->first.length());
|
|
|
|
SV *val = newSVpv(it->second.c_str(), it->second.length());
|
|
|
|
// If val was not added to hash, reset reference count
|
|
if (hv_store(hv, it->first.c_str(), keylen, val, 0) == nullptr)
|
|
val->sv_refcnt = 0;
|
|
}
|
|
}
|
|
|
|
//loads a file and compiles it into our interpreter (assuming it hasn't already been read in)
|
|
//idea borrowed from perlembed
|
|
int eval_file(const char * packagename, const char * filename);
|
|
|
|
inline bool InUse() const { return(in_use); }
|
|
|
|
//check to see if a sub exists in package
|
|
bool SubExists(const char *package, const char *sub);
|
|
|
|
//check to see if a variable exists in package
|
|
bool VarExists(const char *package, const char *var);
|
|
};
|
|
#endif //EMBPERL
|
|
|
|
#endif //EMBPERL_H
|