Allow items to specify their missile animation and also allow for custom missiles

- Custom missiles are untested
- Items with custom missiles export the missile graphics in the party sheet
This commit is contained in:
2015-01-13 14:33:47 -05:00
parent 52c7bc126f
commit 5587bbb0f2
8 changed files with 109 additions and 43 deletions

View File

@@ -859,10 +859,12 @@ void place_target(location target) {
}
void do_combat_cast(location target) {
short adjust,r1,r2,targ_num,level,bonus = 1,i,item,store_sound = 0;
short adjust,r1,r2,targ_num,level,bonus = 1,i,item;
snd_num_t store_sound = 0;
cCreature *cur_monst;
bool freebie = false,ap_taken = false,cost_taken = false;
short num_targets = 1,store_m_type = 2;
short num_targets = 1;
miss_num_t store_m_type = 2;
eFieldType spray_type_array[15] = {
FIELD_WEB,FIELD_WEB,FIELD_WEB,
WALL_FORCE,WALL_FORCE,
@@ -1458,7 +1460,7 @@ void load_missile() {
void fire_missile(location target) {
short r1, r2, skill, dam, dam_bonus, hit_bonus, range, targ_monst, spec_dam = 0,poison_amt = 0;
short skill_item,m_type = 0;
short skill_item;
cCreature *cur_monst;
bool exploding = false;
missile_firer = current_pc;
@@ -1518,27 +1520,7 @@ void fire_missile(location target) {
std::string create_line = univ.party[missile_firer].name + " fires.";
add_string_to_buf(create_line);
if(overall_mode == MODE_THROWING) {
// TODO: Store the missile in cItem directly
switch(univ.party[missile_firer].items[ammo_inv_slot].item_level) {
case 7:
m_type = 10;
break;
case 4:
m_type = 1;
break;
case 8:
m_type = 5;
break;
case 9:
m_type = 7;
break;
default:
m_type = 10;
break;
}
} else if(overall_mode == MODE_FIRING || overall_mode == MODE_FANCY_TARGET)
m_type = univ.party[missile_firer].items[ammo_inv_slot].magic ? 4 : 3;
miss_num_t m_type = univ.party[missile_firer].items[ammo_inv_slot].missile;
run_a_missile(univ.party[missile_firer].combat_pos,target,m_type,1,(overall_mode == MODE_FIRING) ? 12 : 14,
0,0,100);
@@ -2878,7 +2860,8 @@ void monst_fire_missile(short m_num,short bless,short level,location source,shor
//dam_type; // 0 - fire 1 - cold 2 - magic
bool monst_breathe(cCreature *caster,location targ_space,short dam_type) {
short level,missile_t[4] = {13,6,8,8};
short level;
miss_num_t missile_t[4] = {13,6,8,8};
eDamageType type[4] = {eDamageType::FIRE, eDamageType::COLD, eDamageType::MAGIC, eDamageType::UNBLOCKABLE};
location l;
@@ -4356,7 +4339,9 @@ bool combat_cast_mage_spell() {
}
void combat_immed_mage_cast(short current_pc, eSpell spell_num, bool freebie) {
short target, store_m_type = 0, i, store_sound = 0, num_opp = 0, r1;
short target, i, num_opp = 0, r1;
snd_num_t store_sound = 0;
miss_num_t store_m_type = 0;
short bonus = freebie ? 1 : stat_adj(current_pc,eSkill::INTELLIGENCE);
cCreature* which_m;
start_missile_anim();
@@ -4544,7 +4529,9 @@ bool combat_cast_priest_spell() {
}
void combat_immed_priest_cast(short current_pc, eSpell spell_num, bool freebie) {
short target,i,store_sound = 0,store_m_type = 0,num_opp = 0;
short target,i,num_opp = 0;
snd_num_t store_sound = 0;
miss_num_t store_m_type = 0;
short bonus = freebie ? 1 : stat_adj(current_pc,eSkill::INTELLIGENCE);
cCreature *which_m;
effect_pat_type protect_pat = {{

View File

@@ -66,6 +66,7 @@ extern tessel_ref_t bw_pats[6];
extern short combat_posing_monster , current_working_monster ; // 0-5 PC 100 + x - monster x
extern short store_talk_face_pic;
extern cUniverse univ;
extern cCustomGraphics spec_scen_g;
// Talk vars
extern eGameMode store_pre_talk_mode;
@@ -91,18 +92,18 @@ extern short heal_costs[8];
extern short terrain_there[9][9];
// Missile anim vars
typedef struct {
struct store_missile_type {
location dest;
short missile_type; // -1 no miss
miss_num_t missile_type; // -1 no miss
short path_type,x_adj,y_adj;
} store_missile_type;
typedef struct {
};
struct store_boom_type {
location dest;
short val_to_place,offset;
short place_type; // 0 - on spot, 1 - random area near spot
short boom_type; // -1 no miss
short x_adj,y_adj;
} store_boom_type;
};
store_missile_type store_missiles[30];
store_boom_type store_booms[30];
bool have_missile,have_boom;
@@ -257,7 +258,7 @@ void end_missile_anim() {
boom_anim_active = false;
}
void add_missile(location dest,short missile_type,short path_type,short x_adj,short y_adj) {
void add_missile(location dest,miss_num_t missile_type,short path_type,short x_adj,short y_adj) {
short i;
if(!boom_anim_active)
@@ -280,7 +281,7 @@ void add_missile(location dest,short missile_type,short path_type,short x_adj,sh
}
}
void run_a_missile(location from,location fire_to,short miss_type,short path,short sound_num,short x_adj,short y_adj,short len) {
void run_a_missile(location from,location fire_to,miss_num_t miss_type,short path,short sound_num,short x_adj,short y_adj,short len) {
// if((cartoon_happening) && (anim_step < 140))
// return;
start_missile_anim();
@@ -434,11 +435,30 @@ void do_missile_anim(short num_steps,location missile_origin,short sound_num) {
missile_place_rect[i] = temp_rect;
// Now put in missile
from_rect = missile_origin_rect[i];
if(store_missiles[i].missile_type >= 7)
from_rect.offset(18 * (t % 8),0);
rect_draw_some_item(missiles_gworld,from_rect,
mainPtr,temp_rect,sf::BlendAlpha);
if(store_missiles[i].missile_type < 1000) {
from_rect = missile_origin_rect[i];
if(store_missiles[i].missile_type >= 7)
from_rect.offset(18 * (t % 8),0);
rect_draw_some_item(missiles_gworld,from_rect, mainPtr,temp_rect,sf::BlendAlpha);
} else {
// Custom missile graphics
// TODO: Test this!
int step = missile_origin_rect[i].left / 18;
miss_num_t base = store_missiles[i].missile_type;
bool isParty = false;
if(base >= 10000) {
isParty = true;
base -= 10000;
} else base -= 1000;
base += step % 4;
sf::Texture* from_gw;
graf_pos_ref(from_gw, from_rect) = spec_scen_g.find_graphic(base, isParty);
from_rect.width() = 18;
from_rect.height() = 18;
if(step >= 4)
from_rect.offset(0,18);
rect_draw_some_item(*from_gw,from_rect, mainPtr,temp_rect,sf::BlendAlpha);
}
}
mainPtr.display();
if((PSD[SDF_GAME_SPEED] == 3) || ((PSD[SDF_GAME_SPEED] == 1) && (t % 4 == 0)) ||

View File

@@ -48,10 +48,10 @@ bool try_pc_anim_move(short i,location start,short x,short y);
void start_missile_anim();
short get_missile_direction(location origin_point,location the_point);
void end_missile_anim() ;
void run_a_missile(location from,location fire_to,short miss_type,short path,short sound_num,short x_adj,short y_adj,short len);
void run_a_missile(location from,location fire_to,miss_num_t miss_type,short path,short sound_num,short x_adj,short y_adj,short len);
void run_a_boom(location boom_where,short type,short x_adj,short y_adj);
void mondo_boom(location l,short type);
void add_missile(location dest,short missile_type,short path_type,short x_adj,short y_adj);
void add_missile(location dest,miss_num_t missile_type,short path_type,short x_adj,short y_adj);
void add_explosion(location dest,short val_to_place,short place_type,short boom_type,short x_adj,short y_adj);
void do_missile_anim(short num_steps,location missile_origin,short sound_num) ;
void do_explosion_anim(short sound_num,short expand);

View File

@@ -740,6 +740,49 @@ void cItem::append(legacy::item_record_type& old){
unsellable = old.item_properties & 16;
reserved1 = old.reserved1;
reserved2 = old.reserved2;
// Set missile, if needed
switch(variety) {
case eItemType::ARROW:
case eItemType::BOLTS:
missile = magic ? 4 : 3;
break;
case eItemType::THROWN_MISSILE:
// This is tricky... basically, all we can really do is guess.
// We'll base our guess on the item's level, since the preset items have standard levels
switch(item_level) {
case 7: // Throwing knives
missile = 10;
break;
case 4: // Darts
missile = 1;
break;
case 8: // Javelins
missile = 5;
break;
case 9: // Razordisks
missile = 7;
break;
default:
auto npos = std::string::npos;
// Okay, that failed. Try examining the item's name.
// We'll use the unidentified name since it's more likely to contain the appropriate generic words
if(name.find("Knife") != npos) missile = 10;
else if(name.find("Knives") != npos) missile = 10;
else if(name.find("Spear") != npos) missile = 5;
else if(name.find("Javelin") != npos) missile = 5;
else if(name.find("Razordisk") != npos) missile = 7;
else if(name.find("Star") != npos) missile = 7;
else if(name.find("Dart") != npos) missile = 1;
else if(name.find("Rock") != npos) missile = 12;
// Okay, give up. Fall back to darts since we have no idea what's correct.
else missile = 1;
break;
}
case eItemType::MISSILE_NO_AMMO:
// Just assume it's a sling and use the rock missile.
missile = 12;
break;
}
}
void cItem::writeTo(std::ostream& file, std::string prefix) const {

View File

@@ -35,6 +35,7 @@ public:
short value;
unsigned int weight;
unsigned int special_class;
miss_num_t missile;
location item_loc;
std::string full_name;
std::string name;

View File

@@ -10,6 +10,7 @@
#define BOE_DATA_SIMPLETYPES_H
typedef unsigned short mon_num_t;
typedef signed short miss_num_t;
typedef unsigned short ter_num_t;
typedef signed short spec_num_t;
typedef signed short item_num_t;

View File

@@ -881,6 +881,13 @@ void cUniverse::check_item(cItem& item) {
check_monst(party.summons[monst - 10000]);
else check_monst(scenario.scen_monsters[monst]);
}
if(item.variety == eItemType::ARROW || item.variety == eItemType::BOLTS || item.variety == eItemType::MISSILE_NO_AMMO || item.variety == eItemType::THROWN_MISSILE) {
if(item.missile >= 10000)
for(int i = 0; i < 4; i++)
used_graphics.insert(item.missile - 10000 + i);
else if(item.missile >= 1000)
update_missiles[item.missile - 1000].insert(&item);
}
}
extern cCustomGraphics spec_scen_g;
@@ -895,6 +902,7 @@ pic_num_t cUniverse::addGraphic(pic_num_t pic, ePicType type) {
case PIC_MONST_LG: needSlots = 16; break;
case PIC_ITEM: needSlots = 1; break;
case PIC_PC: needSlots = 4; break;
case PIC_MISSILE: needSlots = 4; break;
default: break;
}
pic_num_t pos = -1;
@@ -923,7 +931,7 @@ void cUniverse::exportGraphics() {
// - Monster graphics for monsters summoned by custom items or captured in the party's soul crystal
// - Item graphics for custom items that the party has in their possession or in their saved item rectangles
// - Custom PC graphics - TODO: Rendering support for custom PC graphics
// TODO: Missile graphics for custom items/monsters
// TODO: Missile graphics for custom monsters
// So basically, almost all the graphics are linked to items.
used_graphics.clear();
for(int i = 0; i < 6; i++) {
@@ -960,6 +968,12 @@ void cUniverse::exportGraphics() {
item->graphic_num = 10000 + pos;
}
update_items.clear();
for(auto pic : update_missiles) {
pic_num_t pos = addGraphic(pic.first, PIC_MISSILE);
for(auto& item : pic.second)
item->missile = 10000 + pos;
}
update_missiles.clear();
for(auto pic : update_monsters) {
int sz = pic.first / 1000, base = pic.first % 1000;
ePicType type;

View File

@@ -154,7 +154,7 @@ enum eAmbientSound {
class cUniverse{
template<typename T> using update_info = std::set<T*>;
std::map<pic_num_t, update_info<cItem>> update_items;
std::map<pic_num_t, update_info<cItem>> update_items, update_missiles;
std::map<pic_num_t, update_info<cMonster>> update_monsters;
std::map<pic_num_t, update_info<cPlayer>> update_pcs;
std::set<pic_num_t> used_graphics;