EvEmu  0.8.4
11 September 2021
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
InsuranceService.cpp
Go to the documentation of this file.
1 /*
2  ------------------------------------------------------------------------------------
3  LICENSE:
4  ------------------------------------------------------------------------------------
5  This file is part of EVEmu: EVE Online Server Emulator
6  Copyright 2006 - 2021 The EVEmu Team
7  For the latest information visit https://evemu.dev
8  ------------------------------------------------------------------------------------
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License along with
19  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20  Place - Suite 330, Boston, MA 02111-1307, USA, or go to
21  http://www.gnu.org/copyleft/lesser.txt.
22  ------------------------------------------------------------------------------------
23  Author: Zhur
24  Rewrite: Allan
25 */
26 
27 #include "eve-server.h"
28 
29 #include "PyBoundObject.h"
30 #include "PyServiceCD.h"
31 #include "Client.h"
32 #include "account/AccountService.h"
33 #include "chat/LSCService.h"
35 #include "system/SystemEntity.h"
36 #include "system/SystemManager.h"
37 
38 /* TODO:
39 * - set ship->basePrice to use history market value from marketProxy!
40 */
41 
43 : public PyBoundObject
44 {
45 public:
47 
49  : PyBoundObject(mgr),
50  m_db(db),
51  m_dispatch(new Dispatcher(this)) {
53 
55  PyCallable_REG_CALL(InsuranceBound, UnInsureShip);
56  PyCallable_REG_CALL(InsuranceBound, GetContracts);
57  PyCallable_REG_CALL(InsuranceBound, GetInsurancePrice);
58 
59  m_strBoundObjectName = "InsuranceBound";
60  }
61 
62  virtual ~InsuranceBound() { delete m_dispatch; }
63  virtual void Release() {
64  //I hate this statement
65  delete this;
66  }
67 
68  PyCallable_DECL_CALL(InsureShip);
69  PyCallable_DECL_CALL(UnInsureShip);
70  PyCallable_DECL_CALL(GetContracts);
71  PyCallable_DECL_CALL(GetInsurancePrice);
72 
73 protected:
75  Dispatcher *const m_dispatch;
76 };
77 
79 
81 : PyService(mgr, "insuranceSvc"),
82  m_dispatch(new Dispatcher(this))
83 {
84  _SetCallDispatcher(m_dispatch);
85 
86  PyCallable_REG_CALL(InsuranceService, GetContractForShip);
87  PyCallable_REG_CALL(InsuranceService, GetInsurancePrice);
88  //SetSessionCheck?
89 }
90 
92  delete m_dispatch;
93 }
94 
96  return new InsuranceBound( m_manager, &m_db );
97 }
98 
99 PyResult InsuranceService::Handle_GetContractForShip( PyCallArgs& call ) {
100  return m_db.GetInsuranceByShipID(call.tuple->GetItem(0)->AsInt()->value());
101 }
102 
103 PyResult InsuranceBound::Handle_UnInsureShip( PyCallArgs& call ) {
104  m_db->DeleteInsuranceByShipID(call.tuple->GetItem(0)->AsInt()->value());
105  return PyStatic.NewNone();
106 }
107 PyResult InsuranceService::Handle_GetInsurancePrice( PyCallArgs& call ) {
108  /* called in space */
109  const ItemType *type = sItemFactory.GetType(PyRep::IntegerValue(call.tuple->GetItem(0)));
110  if (type != nullptr)
111  return new PyFloat(type->basePrice());
112 
113  return PyStatic.NewZero();
114 }
115 
116 PyResult InsuranceBound::Handle_GetInsurancePrice( PyCallArgs& call ) {
117  /* called when docked */
118  const ItemType *type = sItemFactory.GetType(PyRep::IntegerValue(call.tuple->GetItem(0)));
119  if (type != nullptr)
120  return new PyFloat(type->basePrice());
121 
122  return PyStatic.NewZero();
123 }
124 
125 PyResult InsuranceBound::Handle_GetContracts( PyCallArgs& call ) {
126  if (call.tuple->size() > 1) {
127  Call_IntBoolArg args;
128  if (!args.Decode(&call.tuple)) {
129  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
130  return nullptr;
131  }
132 
133  return m_db->GetInsuranceByOwnerID(call.client->GetCorporationID());
134  }
135 
136  return m_db->GetInsuranceByOwnerID(call.client->GetCharacterID());
137 }
138 
139 PyResult InsuranceBound::Handle_InsureShip( PyCallArgs& call ) {
140  call.Dump(SERVICE__CALL_DUMP);
141  Call_InsureShip args;
142  if (!args.Decode(&call.tuple)) {
143  codelog(SERVICE__ERROR, "%s: Failed to decode arguments.", GetName());
144  return nullptr;
145  }
146 
147  InventoryItemRef shipRef = sItemFactory.GetItem(args.shipID);
148  if (shipRef.get() == nullptr) // make error here
149  return nullptr;
150 
151  if (shipRef->groupID() == EVEDB::invGroups::Rookieship) {
152  call.client->SendInfoModalMsg("You cannot insure Rookie ships.");
153  return PyStatic.NewNone();
154  } // end rookie ship check
155 
156  /* INSURANCE FRACTION TABLE:
157  * Label Fraction Payment
158  * -------- -------- ------
159  * Platinum 1.0 0.3
160  * Gold 0.9 0.25
161  * Silver 0.8 0.2
162  * Bronze 0.7 0.15
163  * Standard 0.6 0.1
164  * Basic 0.5 0.05
165  * None 0.1 0.00
166  */
167  // calculate the fraction value
168  double paymentFraction = (args.amount / (shipRef->type().basePrice()));
169  if (paymentFraction < 0.05f) {
170  // catchall for fuckedup prices.
171  call.client->SendErrorMsg("Your payment of %.2f is below the minimum payment of %.2f required for coverage.", \
172  args.amount, (shipRef->type().basePrice() * 0.05f));
173  return PyStatic.NewNone();
174  }
175 
176  float fraction(0.1f); // with no insurance, SCC pays 40% on live. we pay 10%
177  if (paymentFraction == 0.05f) {
178  fraction = 0.5f;
179  } else if (paymentFraction == 0.1f) {
180  fraction = 0.6f;
181  } else if (paymentFraction == 0.15f) {
182  fraction = 0.7f;
183  } else if (paymentFraction == 0.2f) {
184  fraction = 0.8f;
185  } else if (paymentFraction == 0.25f) {
186  fraction = 0.9f;
187  } else if (paymentFraction == 0.3f) {
188  fraction = 1.0f;
189  }
190 
191  if (fraction < 0.05f) {
192  call.client->SendErrorMsg("There was a problem with your insurance premium calculation. Ref: ServerError 75520.");
193  throw UserError ("InsureShipFailed");
194  } else if (fraction == 0.1f) {
195  call.client->SendErrorMsg("Your insurance is at minimum coverage due to incorrect base prices. Ref: ServerError 75521.");
196  }
197 
198  if (m_db->IsShipInsured(args.shipID)) { //this hits db...can you insure unloaded ship? (if no, make this a ship memobj)
199  if (call.byname.find("voidOld") != call.byname.end()) {
200  if (call.byname.find("voidOld")->second->AsBool()->value())
201  ShipDB::DeleteInsuranceByShipID(args.shipID);
202  } else { // this will send voidOld=true after asking player to cancel old insurance
203  throw UserError ("InsureShipFailedSingleContract");
204  }
205  }
206 
207  uint8 numWeeks(12);
208  double payout(shipRef->type().basePrice());
209  payout *= fraction;
210  if (m_db->InsertInsuranceByShipID(args.shipID, shipRef->name(), call.client->GetCharacterID(), fraction, payout, args.isCorp, numWeeks)) {
211  // it successfully added, now, have the player pay for the insurance
212  std::string reason = "Insurance Premium on ";
213  reason += call.client->GetShip()->itemName();
214  reason += ". Reference ID : xxxxx"; // put contractID here
215  AccountService::TranserFunds(call.client->GetCharacterID(), corpSCC, args.amount, reason, \
216  Journal::EntryType::Insurance, -shipRef->itemID()); // for paying ins, shipID should be negative
217  } else {
218  throw UserError ("InsureShipFailed");
219  }
220 
221  // TODO: send mail detailing insurance coverage and length of coverage
222  // this works...mail is saved in db, but player not notified and cant see msg.
223  const std::string subject = "New Ship Insurance"; //std::string("New application from ") + call.client->GetName(),
224  std::string body = "Dear valued customer,<br>";
225  body += "Congratulations on the insurance on your ship. A very wise choice indeed.<br>";
226  body += "This letter is to confirm that we have issued an insurance contract for your ship, ";
227  body += shipRef->itemName();
228  body += ", at level of ";
229  body += std::to_string(fraction * 100);
230  body += "%.<br>This contract will expire after 12 weeks, on xxxxx";
231  // body += GetExpireDate(); //*insert endDate Here*,
232  body += "<br><br>";
233  body += "Best Wishes,<br>";
234  body += "The Secure Commerce Commission,<br><br>";
235  body += "Reference ID: xxxxx <br>"; // put contractID here
236  body += "jav";
237 
238  m_manager->lsc_service->SendMail(corpSCC, call.client->GetCharacterID(), subject, body);
239 
240  return m_db->GetInsuranceByShipID(args.shipID);
241 }
Base Python wire object.
Definition: PyRep.h:66
Dispatcher *const m_dispatch
unsigned __int8 uint8
Definition: eve-compat.h:46
PyCallable_Make_Dispatcher(InsuranceBound) InsuranceBound(PyServiceMgr *mgr
void SendErrorMsg(const char *fmt,...)
Definition: Client.cpp:2719
PyCallable_Make_InnerDispatcher(InsuranceService) InsuranceService
virtual void Release()
PyRep * GetInsuranceByOwnerID(uint32 ownerID)
Definition: ShipDB.cpp:46
PyRep * GetItem(size_t index) const
Returns Python object.
Definition: PyRep.h:602
int32 value() const
Definition: PyRep.h:247
Dispatcher *const m_dispatch
std::map< std::string, PyRep * > byname
Definition: PyCallable.h:51
size_t size() const
Definition: PyRep.h:591
PyCallable_DECL_CALL(InsureShip)
void SendMail(uint32 sender, uint32 recipient, const std::string &subject, const std::string &content)
Definition: LSCService.h:64
void SendInfoModalMsg(const char *fmt,...)
Definition: Client.cpp:2756
Python floating point number.
Definition: PyRep.h:292
int32 GetCharacterID() const
Definition: Client.h:113
int32 GetCorporationID() const
Definition: Client.h:123
std::string m_strBoundObjectName
Definition: PyBoundObject.h:54
const char * name()
virtual ~InsuranceBound()
uint16 groupID() const
void _SetCallDispatcher(CallDispatcher *d)
Definition: PyCallable.h:87
* args
const ItemType & type() const
#define codelog(type, fmt,...)
Definition: logsys.h:128
Definition: ShipDB.h:37
bool IsShipInsured(uint32 shipID)
Definition: ShipDB.cpp:81
static void DeleteInsuranceByShipID(uint32 shipID)
Definition: ShipDB.cpp:65
static void TranserFunds(uint32 fromID, uint32 toID, double amount, std::string reason="", uint8 entryTypeID=Journal::EntryType::Undefined, uint32 referenceID=0, uint16 fromKey=Account::KeyType::Cash, uint16 toKey=Account::KeyType::Cash, Client *pClient=nullptr)
PyServiceMgr *const m_manager
Definition: PyService.h:91
#define PyStatic
Definition: PyRep.h:1209
X * get() const
Definition: RefPtr.h:213
ShipItemRef GetShip() const
Definition: Client.h:167
Client *const client
Definition: PyCallable.h:49
Python object "ccp_exceptions.UserError".
Definition: PyExceptions.h:121
#define PyCallable_REG_CALL(c, m)
Definition: PyServiceCD.h:78
Definition: Client.h:66
LSCService * lsc_service
Definition: PyServiceMgr.h:77
virtual PyBoundObject * CreateBoundObject(Client *pClient, const PyRep *bind_args)
double basePrice() const
Definition: ItemType.h:78
PyServiceMgr *const m_manager
Definition: PyBoundObject.h:53
const std::string & itemName() const
PyRep * GetInsuranceByShipID(uint32 shipID)
Definition: ShipDB.cpp:32
bool InsertInsuranceByShipID(uint32 shipID, std::string name, uint32 ownerID, float level, double payOut, bool isCorpItem=false, uint8 numWeeks=12)
Definition: ShipDB.cpp:56
void Dump(LogType type) const
Definition: PyCallable.cpp:81
#define sItemFactory
Definition: ItemFactory.h:165
static int64 IntegerValue(PyRep *pRep)
Definition: PyRep.cpp:118
Dispatcher *const m_dispatch
PyInt * AsInt()
Definition: PyRep.h:122
virtual ~InsuranceService()
uint32 itemID() const
Definition: InventoryItem.h:98
const char * GetName() const
Definition: PyBoundObject.h:44
PyTuple * tuple
Definition: PyCallable.h:50