Pol  Revision:cb584c9
spelbook.cpp
Go to the documentation of this file.
1 
11 #include "spelbook.h"
12 
13 #include <sstream>
14 #include <stddef.h>
15 
16 #include "../clib/cfgelem.h"
17 #include "../clib/logfacility.h"
18 #include "../clib/streamsaver.h"
19 #include "../plib/systemstate.h"
20 #include "baseobject.h"
21 #include "globals/uvars.h"
22 #include "item/itemdesc.h"
23 #include "mobile/charactr.h"
24 #include "network/client.h"
25 #include "network/packethelper.h"
26 #include "network/packets.h"
27 #include "polclass.h"
28 #include "ufunc.h"
29 #include "uobject.h"
30 
31 namespace Pol
32 {
33 namespace Core
34 {
36  : UContainer( descriptor ), spell_school( 0 )
37 {
38  if ( descriptor.spelltype == "Magic" )
39  spell_school = 0;
40  else if ( descriptor.spelltype == "Necro" )
41  spell_school = 1;
42  else if ( descriptor.spelltype == "Paladin" )
43  spell_school = 2;
44  // Use spell school 3 for Mysticism with spellid 678+ because on OSI nothing uses this so we can
45  // use this here.
46  else if ( descriptor.spelltype == "Mysticism" )
47  spell_school = 3;
48  else if ( descriptor.spelltype == "Bushido" )
49  spell_school = 4;
50  else if ( descriptor.spelltype == "Ninjitsu" )
51  spell_school = 5;
52  else if ( descriptor.spelltype == "SpellWeaving" )
53  spell_school = 6;
54  else if ( descriptor.spelltype == "BardMasteries" )
55  spell_school = 7;
56  for ( int i = 0; i < 8; ++i )
57  bitwise_contents[i] = 0;
58 }
59 
61 
63 {
64  return sizeof( u8 ) * 8 /* bitwise_contents*/
65  + sizeof( u8 ) /*spell_school*/
67 }
68 
70 {
71  if ( client->chr->is_equipped( this ) )
72  {
73  send_put_in_container( client, this );
74  send_wornitem( client, client->chr, this );
75  }
76  else if ( container != nullptr )
77  send_put_in_container( client, this );
78  else
79  {
80  send_sysmessage( client, "Spellbooks must be equipped or in the top level backpack to use." );
81  return;
82  }
83 
84  if ( bitwise_contents[0] == 0 ) // assume never been clicked using the new bitwise spell scheme
86 
87  if ( !( client->UOExpansionFlag & Network::AOS ) && ( spell_school == 0 ) )
88  {
89  send_book_old( client );
90  }
91  else if ( !( client->UOExpansionFlag & Network::AOS ) &&
92  ( spell_school == 1 || spell_school == 2 ) )
93  {
94  send_sysmessage( client, "This item requires at least the Age of Shadows Expansion." );
95  return;
96  }
97  else if ( !( client->UOExpansionFlag & Network::SE ) &&
98  ( spell_school == 4 || spell_school == 5 ) )
99  {
100  send_sysmessage( client, "This item requires at least the Samurai Empire Expansion." );
101  return;
102  }
103  else if ( !( client->UOExpansionFlag & Network::ML ) && spell_school == 6 )
104  {
105  send_sysmessage( client, "This item requires at least the Mondain's Legacy Expansion." );
106  return;
107  }
108  else if ( !( client->UOExpansionFlag & Network::SA ) &&
109  ( spell_school == 3 || spell_school == 7 ) )
110  {
111  send_sysmessage( client, "This item requires at least the Stygian Abyss Expansion." );
112  return;
113  }
114  else
115  {
116  // Ok, now we do a strange check. This is for those people who have no idea that you
117  // must have AOS Features Enabled on an acct with AOS Expansion to view Magery book.
118  // All newer spellbooks will bug out if you use this method though.
119  if ( ( client->UOExpansionFlag & Network::AOS ) && ( spell_school == 0 ) &&
121  {
122  if ( Plib::systemstate.config.loglevel > 1 )
123  INFO_PRINT << "Client with AOS Expansion Account using spellbook without UOFeatureEnable "
124  "0x20 Bitflag.\n";
125  send_book_old( client );
126  return;
127  }
128 
129  send_open_gump( client, *this );
130 
132  msg->WriteFlipped<u16>( 23u );
133  msg->offset += 2; // sub
134  msg->WriteFlipped<u16>( 1u );
135  msg->Write<u32>( serial_ext );
136  msg->WriteFlipped<u16>( graphic );
137 
138  // Check Mysticism spell here
139  if ( spell_school == 3 )
140  msg->WriteFlipped<u16>( 678u );
141  else
142  msg->WriteFlipped<u16>( ( spell_school * 100u ) + 1u );
143 
144  msg->Write( bitwise_contents, 8 );
145  msg.Send( client );
146  }
147 }
148 
149 bool Spellbook::has_spellid( unsigned int spellid ) const
150 {
151  u8 spellschool;
152 
153  // Check Mysticism here
154  if ( spellid >= 678 && spellid <= 693 )
155  spellschool = 3;
156  else
157  spellschool = static_cast<u8>( spellid / 100 );
158 
159  if ( spellschool == this->spell_school )
160  {
161  u16 spellnumber;
162 
163  // Check Mysticism here
164  if ( spellid >= 678 && spellid <= 693 )
165  spellnumber = static_cast<u16>( spellid - 677 );
166  else
167  spellnumber = static_cast<u16>( spellid % 100 );
168 
169  // Limits spellnumber to be between 1-64
170  spellnumber = spellnumber & 63;
171  if ( spellnumber == 0 )
172  spellnumber = 64;
173 
174  u8 spellslot = spellnumber & 7;
175  if ( spellslot == 0 )
176  spellslot = 8;
177 
178  if ( ( ( bitwise_contents[( spellnumber - 1 ) >> 3] ) & ( 1 << ( spellslot - 1 ) ) ) != 0 )
179  return true;
180  }
181  return false;
182 }
183 
184 bool Spellbook::remove_spellid( unsigned int spellid )
185 {
186  if ( has_spellid( spellid ) )
187  {
188  u16 spellnumber;
189 
190  // Check Mysticism here
191  if ( spellid >= 678 && spellid <= 693 )
192  spellnumber = static_cast<u16>( spellid - 677 );
193  else
194  spellnumber = static_cast<u16>( spellid % 100 );
195 
196  // Limits spellnumber to be between 1-64
197  spellnumber = spellnumber & 63;
198  if ( spellnumber == 0 )
199  spellnumber = 64;
200 
201  u8 spellslot = spellnumber & 7;
202  if ( spellslot == 0 )
203  spellslot = 8;
204  bitwise_contents[( spellnumber - 1 ) >> 3] &= ~( 1 << ( spellslot - 1 ) );
205  return true;
206  }
207  return false;
208 }
209 
210 bool Spellbook::add_spellid( unsigned int spellid )
211 {
212  if ( !has_spellid( spellid ) )
213  {
214  u16 spellnumber;
215 
216  // Check Mysticism here
217  if ( spellid >= 678 && spellid <= 693 )
218  spellnumber = static_cast<u16>( spellid - 677 );
219  else
220  spellnumber = static_cast<u16>( spellid % 100 );
221 
222  // Limits spellnumber to be between 1-64
223  spellnumber = spellnumber & 63;
224  if ( spellnumber == 0 )
225  spellnumber = 64;
226 
227  u8 spellslot = spellnumber & 7;
228  if ( spellslot == 0 )
229  spellslot = 8;
230  bitwise_contents[( spellnumber - 1 ) >> 3] |= 1 << ( spellslot - 1 );
231  return true;
232  }
233  return false;
234 }
235 
236 bool Spellbook::can_add( const Item& item ) const
237 {
238  // note: item count maximums are implicitly checked for.
239 
240  // you can only add scrolls to spellbooks
243  {
244  return false;
245  }
246 
247  // you can only add one of each kind of scroll to a spellbook.
249  u8 spellslot = spellnum & 7;
250  if ( spellslot == 0 )
251  spellslot = 8;
252  if ( bitwise_contents[( spellnum - 1 ) >> 3] & ( 1 << ( spellslot - 1 ) ) )
253  return false;
254 
255  return true;
256 }
257 
258 void Spellbook::add_bulk( int /* item_count_delta */, int /* weight_delta */ )
259 {
260  // spellbooks don't modify their weight, either when adding
261  // or when removing an item.
262 }
263 
264 void Spellbook::add( Item* item )
265 {
266  // UContainer::add(item);
268  u8 spellslot = spellnum & 7;
269  if ( spellslot == 0 )
270  spellslot = 8;
271  bitwise_contents[( spellnum - 1 ) >> 3] |= 1 << ( spellslot - 1 );
272  item->destroy();
273  // item->saveonexit(0);
274 }
275 
277 {
278  base::printProperties( sw );
279 
280  for ( int i = 0; i < 8; ++i )
281  sw() << "\tSpellbits" << i << "\t" << (int)bitwise_contents[i] << pf_endl;
282 }
283 
284 
286 {
287  base::readProperties( elem );
288  std::ostringstream os;
289  for ( int i = 0; i < 8; ++i )
290  {
291  os << "Spellbits" << i;
292  bitwise_contents[i] = (u8)elem.remove_ushort( os.str().c_str(), 0 );
293  os.str( "" );
294  }
295 }
296 
297 
299 {
300  base::printOn( sw );
301  printContents( sw );
302 }
303 
305 {
306  base::printOn( sw );
307 }
308 
309 
311 {
312  for ( UContainer::const_iterator itr = begin(), itrend = end(); itr != itrend; ++itr )
313  {
314  const Item* scroll = GET_ITEM_PTR( itr );
316  u8 spellslot = spellnum & 7;
317  if ( spellslot == 0 )
318  spellslot = 8;
319  bitwise_contents[( spellnum - 1 ) >> 3] |= 1 << ( spellslot - 1 );
320  }
321 
322  // ok, it's been upgraded. Destroy everything inside it.
323  for ( UContainer::iterator itr = begin(), itrend = end(); itr != itrend; ++itr )
324  {
325  Item* scroll = GET_ITEM_PTR( itr );
326  scroll->destroy();
327  }
328 }
329 
331  : Item( itemdesc, UOBJ_CLASS::CLASS_ITEM )
332 {
333 }
334 
336 {
337  u16 spellnum = static_cast<u16>( objtype - gamestate.spell_scroll_objtype_limits[school][0] + 1 );
338  if ( school == 0 ) // weirdness in order of original spells
339  {
340  if ( spellnum == 1 )
341  spellnum = 7;
342  else if ( spellnum <= 7 )
343  --spellnum;
344  }
345  return spellnum;
346 }
347 
348 // Spell scrolls send their spell ID in AMOUNT while they're in a spellbook.
349 // Otherwise, they're stackable I believe.
351 {
352  if ( ( container != nullptr ) && ( container->script_isa( POLCLASS_SPELLBOOK ) ) )
353  {
354  Spellbook* book = static_cast<Spellbook*>( container );
356  }
357  else // not contained, or not in a spellbook
358  {
359  return amount_;
360  }
361 }
363 {
364  return base::estimatedSize();
365 }
366 
368 {
369  client->pause();
370 
371  if ( !locked() )
372  {
373  send_open_gump( client, *this );
374  send_spellbook_contents( client, *this );
375  }
376  else
377  {
378  send_sysmessage( client, "That is locked." );
379  }
380 
381  client->restart();
382 }
383 
385 {
387  msg->offset += 4; // msglen+count
388  u16 count = 0;
389  for ( u16 i = 0; i < 64; ++i )
390  {
391  u32 objtype = gamestate.spell_scroll_objtype_limits[0][0] + i;
392  u16 spellnumber = USpellScroll::convert_objtype_to_spellnum( objtype, spellbook.spell_school );
393  u8 spellpos = spellnumber & 7; // spellpos is the spell's position it it's circle's array.
394  if ( spellpos == 0 )
395  spellpos = 8;
396  if ( ( ( spellbook.bitwise_contents[( ( spellnumber - 1 ) >> 3 )] ) &
397  ( 1 << ( spellpos - 1 ) ) ) != 0 )
398  {
399  msg->Write<u32>( 0x7FFFFFFFu - spellnumber );
400  msg->WriteFlipped<u16>( objtype );
401  msg->offset++; // unk6
402  msg->WriteFlipped<u16>( spellnumber ); // amount
403  msg->WriteFlipped<u16>( 1u ); // x
404  msg->WriteFlipped<u16>( 1u ); // y
405  if ( client->ClientType & Network::CLIENTTYPE_6017 )
406  msg->Write<u8>( 0u ); // slotindex
407  msg->Write<u32>( spellbook.serial_ext );
408  msg->WriteFlipped<u16>( 0u ); // color
409  ++count;
410  }
411  }
412  u16 len = msg->offset;
413  msg->offset = 1;
414  msg->WriteFlipped<u16>( len );
415  msg->WriteFlipped<u16>( count );
416  msg.Send( client, len );
417 }
418 }
419 }
Contents::const_iterator const_iterator
Definition: containr.h:115
unsigned char u8
Definition: rawtypes.h:25
bool add_spellid(unsigned int spellid)
Definition: spelbook.cpp:210
void send_book_old(Network::Client *client)
Definition: spelbook.cpp:367
u8 bitwise_contents[8]
Definition: spelbook.h:61
virtual void printProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: containr.cpp:867
SystemState systemstate
Definition: systemstate.cpp:12
const u16 ML
Definition: client.h:77
USpellScroll(const Items::ItemDesc &descriptor)
Definition: spelbook.cpp:330
virtual void double_click(Network::Client *client) POL_OVERRIDE
Definition: spelbook.cpp:69
void send_open_gump(Network::Client *client, const UContainer &cont)
Definition: ufunc2.cpp:67
virtual void printOn(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: spelbook.cpp:298
const u16 SE
Definition: client.h:76
Contents::iterator iterator
Definition: containr.h:114
virtual void readProperties(Clib::ConfigElem &elem) POL_OVERRIDE
Definition: containr.cpp:880
virtual void add_bulk(int item_count_delta, int weight_delta) POL_OVERRIDE
Definition: spelbook.cpp:258
virtual ~Spellbook()
Definition: spelbook.cpp:60
Mobile::Character * chr
Definition: client.h:182
virtual bool script_isa(unsigned isatype) const POL_OVERRIDE
Definition: uoscrobj.cpp:4576
unsigned short u16
Definition: rawtypes.h:26
unsigned int u32
Definition: rawtypes.h:27
bool has_spellid(unsigned int spellid) const
Definition: spelbook.cpp:149
const u16 AOS
Definition: client.h:75
virtual void printSelfOn(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: spelbook.cpp:304
virtual void destroy()
Definition: uobject.cpp:122
void Send(Client *client, int len=-1) const
Definition: packethelper.h:69
virtual u16 get_senditem_amount() const POL_OVERRIDE
Definition: spelbook.cpp:350
virtual void add(Items::Item *item) POL_OVERRIDE
Definition: spelbook.cpp:264
unsigned short uo_feature_enable
Definition: ssopt.h:57
std::array< std::array< u32, 2 >, 8 > spell_scroll_objtype_limits
Definition: uvars.h:185
Core::UContainer * container
Definition: item.h:256
#define GET_ITEM_PTR(itr)
Definition: containr.h:38
const u32 objtype_
Definition: uobject.h:249
virtual void printOn(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: containr.cpp:99
GameState gamestate
Definition: uvars.cpp:74
void send_wornitem(Client *client, const Character *chr, const Item *item)
Definition: ufunc.cpp:825
SettingsManager settingsManager
Definition: settings.cpp:14
unsigned int count() const
Definition: refptr.h:130
const unsigned POLCLASS_SPELLBOOK
Definition: polclass.h:21
virtual size_t estimatedSize() const POL_OVERRIDE
Definition: item00.cpp:58
virtual void printProperties(Clib::StreamWriter &sw) const POL_OVERRIDE
Definition: spelbook.cpp:276
bool remove_spellid(unsigned int spellid)
Definition: spelbook.cpp:184
virtual size_t estimatedSize() const POL_OVERRIDE
Definition: spelbook.cpp:362
bool is_equipped(const Items::Item *item) const
Definition: charactr.cpp:1342
const u16 SA
Definition: client.h:80
virtual size_t estimatedSize() const POL_OVERRIDE
Definition: spelbook.cpp:62
unsigned short remove_ushort(const char *propname)
Definition: cfgfile.cpp:318
virtual bool can_add(const Items::Item &item) const POL_OVERRIDE
Definition: spelbook.cpp:236
const ItemDesc & itemdesc() const
Definition: item.cpp:127
virtual size_t estimatedSize() const POL_OVERRIDE
Definition: containr.cpp:67
#define INFO_PRINT
Definition: logfacility.h:223
#define pf_endl
Definition: proplist.cpp:25
void send_spellbook_contents(Network::Client *client, Spellbook &spellbook)
Definition: spelbook.cpp:384
void calc_current_bitwise_contents()
Definition: spelbook.cpp:310
Spellbook(const Items::SpellbookDesc &descriptor)
Definition: spelbook.cpp:35
Definition: berror.cpp:12
static u16 convert_objtype_to_spellnum(u32 objtype, u8 school)
Definition: spelbook.cpp:335
void send_sysmessage(Network::Client *client, const char *text, unsigned short font, unsigned short color)
Definition: ufunc.cpp:1147
void send_put_in_container(Client *client, const Item *item)
Definition: ufunc.cpp:528
virtual void readProperties(Clib::ConfigElem &elem) POL_OVERRIDE
Definition: spelbook.cpp:285
void printContents(Clib::StreamWriter &sw) const
Definition: containr.cpp:110