void move_object(int i, int16_t x, int16_t y) { if (object[i].draw_index < 255) // object was visible... { if (on_screen(x, y)) { // object is still visible, need to sort draw_order.. but do it later! object[i].iy = y - tile_map_y; object[i].ix = x - tile_map_x; } else // object is no longer visible { for (int k=object[i].draw_index+1; k<drawing_count; ++k) { // move the pointers around for the objects draw_index: // object at draw_order k should go to spot k-1: int object_k = draw_order[k]; // move down draw_order: object[object_k].draw_index = k-1; draw_order[k-1] = object_k; } object[i].iy = SCREEN_H; object[i].ix = SCREEN_W; object[i].draw_index = -1; --drawing_count; } } else // wasn't visible { if (on_screen(x, y)) { // object has become visible make_unseen_object_viewable(i); } else // object is still not visible { // do nothing! } } object[i].y = y; object[i].x = x; }
void MonsterController::post_draw(GameState* gs) { PlayerInst* player = gs->local_player(); if (!player) { return; } EnemyInst* target = (EnemyInst*)gs->get_instance(player->target()); if (!target) { return; } ldraw::draw_circle_outline(COL_GREEN.alpha(140), on_screen(gs, target->ipos()), target->target_radius + 5, 2); }
int create_object(int sprite_draw_index, int16_t x, int16_t y, uint8_t z) { if (object_count >= MAX_OBJECTS) return -1; int i = first_free_object; // setup head of list for both free and used: first_free_object = object[i].next_free_object; object[i].next_used_object = first_used_object; first_used_object = i; // add in object properties object[i].y = y; object[i].x = x; object[i].z = z; if (on_screen(object[i].x, object[i].y)) make_unseen_object_viewable(i); else object[i].draw_index = -1; object[i].sprite_index = sprite_draw_index; ++object_count; return i; }
short treasure::eat_me(walker * eater) { short guys_here; oblink *here; static text eattext(screenp); char message[80]; Sint32 distance; walker *target, *flash; static char exitname[40]; Sint32 leftside, rightside; switch (family) { case FAMILY_DRUMSTICK: if (eater->stats->hitpoints >= eater->stats->max_hitpoints) return 1; else { eater->stats->hitpoints += (short) ((10*stats->level) + (short) random((short) 10*stats->level)); if (eater->stats->hitpoints > eater->stats->max_hitpoints) eater->stats->hitpoints = eater->stats->max_hitpoints; dead = 1; if (on_screen()) screenp->soundp->play_sound(SOUND_EAT); return 1; } case FAMILY_GOLD_BAR: if (eater->team_num == 0 || eater->myguy) { myscreen->m_score[eater->team_num] += (200*stats->level); dead = 1; if (on_screen()) screenp->soundp->play_sound(SOUND_MONEY); } return 1; case FAMILY_SILVER_BAR: if (eater->team_num == 0 || eater->myguy) { myscreen->m_score[eater->team_num] += (50*stats->level); dead = 1; if (on_screen()) screenp->soundp->play_sound(SOUND_MONEY); } return 1; case FAMILY_FLIGHT_POTION: if (!eater->stats->query_bit_flags(BIT_FLYING) ) { eater->flight_left += (150*stats->level); if (eater->user != -1) { sprintf(message, "Potion of Flight(%d)!", stats->level); screenp->do_notify(message, eater); } dead = 1; } return 1; case FAMILY_MAGIC_POTION: if (eater->stats->magicpoints < eater->stats->max_magicpoints) eater->stats->magicpoints = eater->stats->max_magicpoints; eater->stats->magicpoints += (50*stats->level); dead = 1; if (eater->user != -1) { sprintf(message, "Potion of Mana(%d)!", stats->level); screenp->do_notify(message, eater); } return 1; case FAMILY_INVULNERABLE_POTION: if (!eater->stats->query_bit_flags(BIT_INVINCIBLE) ) { eater->invulnerable_left += (150*stats->level); dead = 1; if (eater->user != -1) { sprintf(message, "Potion of Invulnerability(%d)!", stats->level); screenp->do_notify(message, eater); } } return 1; case FAMILY_INVIS_POTION: eater->invisibility_left += (150*stats->level); if (eater->user != -1) { sprintf(message, "Potion of Invisibility(%d)!", stats->level); screenp->do_notify(message, eater); } dead = 1; return 1; case FAMILY_SPEED_POTION: eater->speed_bonus_left += 50*stats->level; eater->speed_bonus = stats->level; if (eater->user != -1) { sprintf(message, "Potion of Speed(%d)!", stats->level); screenp->do_notify(message, eater); } dead = 1; return 1; case FAMILY_EXIT: // go to another level, possibly if (eater->in_act) return 1; if (eater->query_act_type()!= ACT_CONTROL || (eater->skip_exit > 1)) return 1; eater->skip_exit = 10; // See if there are any enemies left ... if (screenp->level_done == 0) guys_here = 1; else guys_here = 0; // Get the name of our exit.. sprintf(message, "scen%d", stats->level); strcpy(exitname, myscreen->get_scen_title(message, myscreen) ); //buffers: PORT: using strcmp instead of stricmp if (!strcmp(exitname, "none")) sprintf(exitname, "Level %d", stats->level); leftside = 160 - ( (strlen(exitname) + 18) * 3); rightside = 160 + ( (strlen(exitname) + 18) * 3); // First check to see if we're withdrawing into // somewhere we've been, in which case we abort // this level, and set our current level to // that pointed to by the exit ... if ( screenp->is_level_completed(stats->level) && !screenp->is_level_completed(screenp->scen_num) && (guys_here != 0) ) // okay to leave { leftside -= 12; rightside += 12; char buf[40]; snprintf(buf, 40, "Withdraw to %s?", exitname); bool result = yes_or_no_prompt("Exit Field", buf, false); // Redraw screen .. screenp->redrawme = 1; if (result) // accepted level change { clear_keyboard(); // Delete all of our current information and abort .. here = myscreen->oblist; while (here) { if (here->ob && here->ob->query_order() == ORDER_LIVING) { //myscreen->remove_ob(here->ob); here->ob->dead = 1; myscreen->myobmap->remove (here->ob); //myscreen->remove_obmap(here->ob); } here = here->next; } //here = myscreen->fxlist; //while (here) //{ // if (here->ob) // myscreen->remove_fx_ob(here->ob); // here = here->next; //} // Now load the game as it was ... load_saved_game("save0", myscreen); myscreen->scen_num = (short) (stats->level-1); myscreen->end = 1; save_game("save0", myscreen); retreat = 1; return screenp->endgame(1, stats->level); // retreat } // end of accepted withdraw to new level .. clear_keyboard(); } // end of checking for withdrawal to completed level //buffers: also, allow exit if scenario_type == can exit if (!guys_here || (screenp->scenario_type == SCEN_TYPE_CAN_EXIT)) // nobody evil left, so okay to exit level .. { char buf[40]; snprintf(buf, 40, "Exit to %s?", exitname); bool result = yes_or_no_prompt("Exit Field", buf, false); // Redraw screen .. screenp->redrawme = 1; if(result) // accepted level change { clear_keyboard(); //screenp->levelstatus[screenp->scen_num] = 1; return screenp->endgame(0, stats->level); } clear_keyboard(); return 1; } return 1; case FAMILY_TELEPORTER: if (eater->skip_exit > 1) return 1; distance = distance_to_ob_center(eater); // how away? if (distance > 21) return 1; if (distance < 4 && eater->skip_exit) { //eater->skip_exit++; eater->skip_exit = 8; return 1; } // If we're close enough, teleport .. eater->skip_exit += 20; if (!leader) target = find_teleport_target(); else target = leader; if (!target) return 1; leader = target; eater->center_on(target); if (!screenp->query_passable(eater->xpos, eater->ypos, eater)) { eater->center_on(this); return 1; } // Now do special effects flash = screenp->add_ob(ORDER_FX, FAMILY_FLASH); flash->ani_type = ANI_EXPAND_8; flash->center_on(this); return 1; case FAMILY_LIFE_GEM: // get back some of lost man's xp .. if (eater->team_num != team_num) // only our team can get these return 1; myscreen->m_score[eater->team_num] += stats->hitpoints; flash = screenp->add_ob(ORDER_FX, FAMILY_FLASH); flash->ani_type = ANI_EXPAND_8; flash->center_on(this); dead = 1; death(); return 1; case FAMILY_KEY: // get the key to this door .. if (!(eater->keys & (Sint32)(pow((double) 2, stats->level)) )) // just got it? { eater->keys |= (Sint32) (pow((double)2, stats->level)); // ie, 2, 4, 8, 16... if (eater->myguy) sprintf(message, "%s picks up key %d", eater->myguy->name, stats->level); else sprintf(message, "%s picks up key %d", eater->stats->name, stats->level); if (eater->team_num == 0) // only show players picking up keys { myscreen->do_notify(message, eater); if (eater->on_screen()) myscreen->soundp->play_sound(SOUND_MONEY); } } return 1; default: return 1; } // end of treasure-check }
// death is called when an object dies (or weapon destructed, etc.) // for special effects .. short effect::death() { // Note that the 'dead' variable should ALREADY be set by the // time this function is called, so that we can easily reverse // the decision :) oblink *scarelist, *here; oblink *frylist; // for the thief's bombs :) short howmany = 0; walker *newob; Sint32 xdelta,ydelta; Sint32 tempx, tempy, generic; if (death_called) return 0; death_called = 1; switch (family) { case FAMILY_GHOST_SCARE: // the ghost's scare if (!owner || owner->dead) return 0; scarelist = screenp->find_foes_in_range(screenp->oblist, 50+(10*owner->stats->level), &howmany, owner); if (howmany < 1) return 0; here = scarelist; while (here) { if (here->ob && here->ob->query_order() == ORDER_LIVING) { tempx = here->ob->xpos - xpos; if (tempx) tempx = tempx / (abs(tempx)); tempy = here->ob->ypos - ypos; if (tempy) tempy = tempy / (abs(tempy)); generic = (owner->stats->level*25); if (here->ob->myguy) generic -= random(here->ob->myguy->constitution); if (generic > 0) here->ob->stats->force_command(COMMAND_WALK, (short) generic, (short) tempx, (short) tempy); } // end of valid target here = here->next; } // end of cycle through scare list delete_list(scarelist); break; // end of ghost scare case FAMILY_BOMB: // Burning bomb if (!owner || owner->dead) owner = this; if (on_screen()) screenp->soundp->play_sound(SOUND_EXPLODE); newob = screenp->add_ob(ORDER_FX, FAMILY_EXPLOSION, 1); newob->owner = owner; newob->stats->hitpoints = 0; newob->stats->level = owner->stats->level; newob->ani_type = ANI_EXPLODE; //newob->setxy(xpos, ypos); newob->center_on(this); newob->damage = damage; break; case FAMILY_EXPLOSION: // the bomb's explosion if (!owner || owner->dead) owner = this; // Set the max distance for a bomb .. generic = 4*owner->stats->level; if (generic > 96) // set max range to about 6 tiles generic = 96; if (skip_exit) // magical, ie mage, don't go far .. { generic = 16; } frylist = screenp->find_in_range(screenp->oblist, 15+generic, &howmany, this); //Log("got in range, %d\n", howmany); // Damage our tile location .. screenp->damage_tile( (short) (xpos+(sizex/2)), (short) (ypos+(sizey/2)) ); if (howmany < 1) return 0; // Set our team number to garbage so we can hurt everyone //team_num = 50; here = frylist; while (here) { if (here->ob && !here->ob->dead && (here->ob->query_order() != ORDER_TREASURE) && (here->ob->query_order() != ORDER_FX) && (!skip_exit || here->ob != owner) ) //&& // here->ob->query_order() == ORDER_LIVING // && here->ob->team_num != owner->team_num // ) { //shove the target xdelta = here->ob->xpos - xpos; if (xdelta) xdelta = xdelta/abs(xdelta); ydelta = here->ob->ypos - ypos; if (ydelta) ydelta = ydelta/abs(ydelta); // Set the distance to 'shove' by explosion generic = 2+owner->stats->level/15; if (generic > 8) // max of about 8 steps generic = 8; here->ob->stats->force_command(COMMAND_WALK,generic,(short)xdelta,(short)ydelta); // Damage (attack) the object if (here->ob == owner) // do less damage { damage /= 4; attack(here->ob); damage *= 4; } else if (!owner->dead && owner->is_friendly(here->ob)) { damage /= 2; attack(here->ob); damage *= 2; } else attack(here->ob); } here = here->next; } break; // end explosion case default: break; } // end of switch family for effect objects return 1; }
short effect::act() { short temp; Sint32 xd, yd, distance, generic; oblink *foelist, *here; walker *newob; short numfoes; // Make sure everyone we're poshorting to is valid if (foe && foe->dead) foe = NULL; if (leader && leader->dead) leader = NULL; if (owner && owner->dead) owner = NULL; collide_ob = NULL; // always start with no collison.. // Any special actions .. switch (family) // determine what to do.. { case FAMILY_GHOST_SCARE: if (owner) center_on(owner); break; case FAMILY_MAGIC_SHIELD: // revolve around owner if (!owner || owner->dead) { dead = 1; death(); break; } switch (drawcycle % 16) { case 0: xd = 0; yd = -24; break; case 1: xd = -9; yd = -22; break; case 2: xd = -17; yd = -17; break; case 3: xd = -22; yd = -9; break; case 4: xd = -24; yd = 0; break; case 5: xd = -22; yd = 9; break; case 6: xd = -17; yd = 17; break; case 7: xd = -9; yd = 22; break; case 8: xd = 0; yd = 24; break; case 9: xd = 9; yd = 22; break; case 10: xd = 17; yd = 17; break; case 11: xd = 22; yd = 9; break; case 12: xd = 24; yd = 0; break; case 13: xd = 22; yd = -9; break; case 14: xd = 17; yd = -17; break; case 15: xd = 9; yd = -22; break; } center_on(owner); setxy( (short)( xpos+xd ), (short) (ypos+yd) ); foelist = screenp->find_foe_weapons_in_range( screenp->oblist, sizex, &temp, this); here = foelist; while (foelist) // first weapons { stats->hitpoints -= foelist->ob->damage; foelist->ob->dead = 1; foelist->ob->death(); foelist = foelist->next; } delete_list(here); foelist = screenp->find_foes_in_range( screenp->oblist, sizex, &temp, this); here = foelist; while (foelist) // second enemies { stats->hitpoints -= foelist->ob->damage; attack(foelist->ob); dead = 0; foelist = foelist->next; } delete_list(here); if ( (stats->hitpoints <= 0) || (lifetime-- < 0) ) { dead = 1; death(); } break; // end of magic shield case case FAMILY_BOOMERANG: // fighter's boomerang // Zardus: FIX: if the drawcycle is in its >253s, the boomerang dies. This will fix the bug where // the boomerang comes back to 0 (owner) after spiraling around all the way if the owner has // that good of an ability (to keep its life so high). This caps boomerang ability, though... Another // fix could be to make the drawcycle var an int or at least something with more capacity than char. if (!owner || owner->dead || drawcycle > 253) { dead = 1; death(); break; } switch (drawcycle % 16) { case 0: xd = 0; yd = -24; break; case 1: xd = -9; yd = -22; break; case 2: xd = -17; yd = -17; break; case 3: xd = -22; yd = -9; break; case 4: xd = -24; yd = 0; break; case 5: xd = -22; yd = 9; break; case 6: xd = -17; yd = 17; break; case 7: xd = -9; yd = 22; break; case 8: xd = 0; yd = 24; break; case 9: xd = 9; yd = 22; break; case 10: xd = 17; yd = 17; break; case 11: xd = 22; yd = 9; break; case 12: xd = 24; yd = 0; break; case 13: xd = 22; yd = -9; break; case 14: xd = 17; yd = -17; break; case 15: xd = 9; yd = -22; break; } xd *= (drawcycle+4); xd /= 48; yd *= (drawcycle+4); yd /= 48; center_on(owner); setxy((short) (xpos+xd), (short) (ypos+yd) ); foelist = screenp->find_foe_weapons_in_range( screenp->oblist, sizex*2, &temp, this); here = foelist; while (foelist) // first weapons { stats->hitpoints -= foelist->ob->damage; foelist->ob->dead = 1; foelist->ob->death(); foelist = foelist->next; } delete_list(here); foelist = screenp->find_foes_in_range( screenp->oblist, sizex, &temp, this); here = foelist; while (foelist) // second enemies { stats->hitpoints -= foelist->ob->damage; attack(foelist->ob); dead = 0; foelist = foelist->next; } delete_list(here); if ( (stats->hitpoints <= 0) || (lifetime-- < 0) ) { dead = 1; death(); } break; // end of boomerang case case FAMILY_KNIFE_BACK: // returning blade if (!owner || owner->dead) { dead = 1; break; } distance = distance_to_ob(owner); if (distance > 10) { xd = yd = 0; // zero out distance movements if (owner->xpos > xpos) { if ( (owner->xpos - xpos) > stepsize ) xd = stepsize; else xd = owner->xpos - xpos; } else if (owner->xpos < xpos) { if ( (xpos - owner->xpos) > stepsize ) xd = -stepsize; else xd = owner->xpos - xpos; } if (owner->ypos > ypos) { if ( (owner->ypos - ypos) > stepsize ) yd = stepsize; else yd = owner->ypos - ypos; } else if (owner->ypos < ypos) { if ( (ypos - owner->ypos) > stepsize ) yd = -stepsize; else yd = owner->ypos - ypos; } setxy((short) (xpos+xd), (short) (ypos+yd) ); newob = screenp->add_ob(ORDER_WEAPON, FAMILY_KNIFE); newob->damage = damage; newob->owner = owner; newob->team_num = team_num; newob->death_called = 1; // to ensure no spawning of more .. newob->setxy(xpos, ypos); if (!screenp->query_object_passable((short) (xpos+xd), (short) (ypos+yd), newob)) { newob->attack(newob->collide_ob); damage /= 4; //setxy(xpos-(2*xd)+random(xd), ypos-(2*yd)+random(yd)); } newob->dead = 1; } else { owner->weapons_left++; //if (owner->user != -1) //{ // sprintf(message, "Knives now %d", owner->weapons_left); // screenp->do_notify(message, owner); //} ani_type = ANI_WALK; dead = 1; } break; case FAMILY_CLOUD: // poison cloud if (lifetime > 0) lifetime--; else { dead = 1; death(); } if (lifetime < 8) invisibility_left +=3; if (invisibility_left > 0) invisibility_left--; // Hit any nearby foes (not friends, for now) foelist = screenp->find_foes_in_range( screenp->oblist, sizex, &temp, this); here = foelist; while (foelist) // { if (hits(xpos, ypos, sizex, sizey, // this is the cloud foelist->ob->xpos, foelist->ob->ypos, foelist->ob->sizex, foelist->ob->sizey) ) { attack(foelist->ob); } // end of actual hit foelist = foelist->next; } delete_list(here); // Are we performing some action? if (stats->commandlist) temp = stats->do_command(); else { xd = yd = 0; while (xd == 0 && yd == 0) { xd = random(3)-1; yd = random(3)-1; } stats->add_command(COMMAND_WALK, (short) random(20), (short) xd, (short) yd); } break; // end of cloud case FAMILY_CHAIN: // chain lightning .. if (!leader || lineofsight<1 || !owner) // lost our leader, etc.? kill us .. { dead = 1; death(); return 1; } // Are we at our leader? If so, attack him :) if (hits(xpos, ypos, sizex, sizey, leader->xpos, leader->ypos, leader->sizex, leader->sizey)) { // Do things .. newob = screenp->add_ob(ORDER_FX, FAMILY_EXPLOSION); if (!newob) { dead = 1; death(); return 1; // failsafe } newob->owner = owner; newob->team_num = team_num; newob->stats->level = stats->level; newob->damage = damage; newob->ani_type = ANI_EXPLODE; newob->center_on(this); leader->skip_exit += 3; // can't hit us for 3 rounds .. if (on_screen()) screenp->soundp->play_sound(SOUND_EXPLODE); // Now make new objects to seek out foes .. // First, are our offspring powerful enough at 1/2 our power? generic = (damage)/2; if (owner->myguy) foelist = screenp->find_foes_in_range(screenp->oblist, 240+(owner->myguy->intelligence/2), &temp, this); else foelist = screenp->find_foes_in_range(screenp->oblist, 240+stats->level*5, &temp, this); if (temp && generic>20) // more foes to find .. { here = foelist; numfoes = random(owner->stats->level)+1; while (here && numfoes--) { if (here->ob != leader && here->ob->skip_exit<1) // don't hit current guy, etc. { newob = screenp->add_ob(ORDER_FX, FAMILY_CHAIN); if (!newob) { delete_list(foelist); return 0; // failsafe } newob->owner = owner; // our caster newob->leader = here->ob; // guy to attack newob->stats->level = stats->level; newob->stats->set_bit_flags(BIT_MAGICAL, 1); newob->damage = generic; newob->team_num = team_num; newob->center_on(this); } // end of wasn't current guy case here = here->next; } // end of loop for nearby foes we found } // end of check for nearby foes // Clean up our list .. ? // Zardus: TAG: nah, lets use delete_list /*here = foelist->next; while (here) { delete foelist; foelist = here; here = here->next; } delete foelist;*/ delete_list(foelist); dead = 1; death(); return 1; } // Move toward our leader .. lineofsight--; distance = distance_to_ob_center(leader); if (distance > stepsize*2) { xd = yd = 0; // zero out distance movements if (leader->xpos > xpos) { if ( (leader->xpos - xpos) > stepsize ) xd = stepsize; else xd = leader->xpos - xpos; } else if (leader->xpos < xpos) { if ( (xpos - leader->xpos) > stepsize ) xd = -stepsize; else xd = leader->xpos - xpos; } if (leader->ypos > ypos) { if ( (leader->ypos - ypos) > stepsize ) yd = stepsize; else yd = leader->ypos - ypos; } else if (leader->ypos < ypos) { if ( (ypos - leader->ypos) > stepsize ) yd = -stepsize; else yd = leader->ypos - ypos; } // Set our facing? curdir = facing(xd, yd); set_frame(ani[curdir][0]); } // end of big step else { //xd = leader->xpos; //yd = leader->ypos; center_on(leader); return 1; } setxy((short) (xpos+xd), (short) (ypos+yd) ); return 1; // so as not to animate, etc. //break; // end of FAMILY_CHAIN case FAMILY_DOOR_OPEN: // Here is how doors work. They start out as a FAMILY_DOOR // from ORDER_WEAPON under the weaplist. When the door is // collided with, the obmap marks the door as dead, and spawns // the FAMILY_DOOR_OPEN on the weaplist (this object). It // animates ANI_DOOR_OPEN, and when it is done, it dies and // spawns a FAMILY_DOOR_OPEN on the fxlist. The amusing part // is that now that it is on the fxlist, it won't act anymore, // thus preventing it from continuously respawning itself. if (ani_type != ANI_WALK) return animate(); newob = screenp->add_fx_ob(ORDER_FX, FAMILY_DOOR_OPEN); if (!newob) break; newob->ani_type = ANI_WALK; newob->setxy(xpos, ypos); newob->stats->level = stats->level; newob->team_num = team_num; newob->ignore = 1; newob->curdir = curdir; // set correct frame newob->animate(); dead = 1; death(); return 1; break; default: break; } // Complete previous animations (like firing) if (ani_type != ANI_WALK) return animate(); switch (family) // determine what to do.. { default: dead = 1; death(); break; } return 0; }
// death is called when an object dies (weapon destructed, etc.) // for special effects .. short weap::death() { // Note that the 'dead' variable should ALREADY be set by the // time this function is called, so that we can easily reverse // the decision :) walker *newob = NULL; if (death_called) // Make sure we don't get multiple deaths return 0; death_called = 1; switch (family) { case FAMILY_KNIFE: // for returning knife if (owner && owner->query_family() != FAMILY_SOLDIER) break; // only soldiers get returning knives newob = screenp->add_ob(ORDER_FX, FAMILY_KNIFE_BACK); newob->owner = owner; newob->center_on(this); newob->lastx = lastx; newob->lasty = lasty; newob->stepsize = stepsize; newob->ani_type = ANI_ATTACK; newob->damage = damage; break; // end of soldier returning knife case FAMILY_ROCK: // used for the elf's bouncing rock, etc. if (!do_bounce || !lineofsight || collide_ob) // died of natural causes break; dead = 0; // first, un-dead us so we can collide .. // Did we hit a barrier? if (screenp->query_grid_passable(xpos+lastx, ypos+lasty, this)) { dead = 1; break; // if not, die like normal } if (screenp->query_grid_passable(xpos-lastx, ypos+lasty, this)) { setxy(xpos-lastx, ypos+lasty); // bounce 'down-left' lastx = -lastx; death_called = 0; break; } if (screenp->query_grid_passable(xpos+lastx, ypos-lasty, this)) { setxy(xpos+lastx, ypos-lasty); // bounce 'up-right' lasty = -lasty; death_called = 0; break; } if (screenp->query_grid_passable(xpos-lastx, ypos-lasty, this)) { setxy(xpos-lastx, ypos-lasty); lastx = -lastx; lasty = -lasty; death_called = 0; break; } // Else we're really stuck, so die :) dead = 1; break; case FAMILY_FIRE_ARROW: // only for exploding, really case FAMILY_BOULDER: if (!skip_exit) break; // skip_exit means we're supposed to explode :) if (!owner || owner->dead) owner = this; newob = screenp->add_ob(ORDER_FX, FAMILY_EXPLOSION, 1); if (!newob) break; // failsafe if (on_screen()) screenp->soundp->play_sound(SOUND_EXPLODE); newob->owner = owner; newob->stats->hitpoints = 0; newob->stats->level = owner->stats->level; newob->ani_type = ANI_EXPLODE; newob->center_on(this); newob->damage = damage*2; break; // end fire (exploding) arrows case FAMILY_WAVE: // grow to wave2 dead = 0; transform_to(ORDER_WEAPON, FAMILY_WAVE2); stats->hitpoints = stats->max_hitpoints; break; // end wave -> wave2 case FAMILY_WAVE2: // grow to wave3 dead = 0; transform_to(ORDER_WEAPON, FAMILY_WAVE3); stats->hitpoints = stats->max_hitpoints; break; // end wave2 -> wave3 case FAMILY_DOOR: // display open picture newob = screenp->add_weap_ob(ORDER_FX, FAMILY_DOOR_OPEN); if (!newob) break; newob->ani_type = ANI_DOOR_OPEN; newob->setxy(xpos, ypos); newob->stats->level = stats->level; newob->team_num = team_num; // newob->ignore = 1; // What way are we 'facing'? if (mysmoother->query_genre_x_y((xpos/GRID_SIZE),(ypos/GRID_SIZE)-1) == TYPE_WALL) // a wall above us? { newob->curdir = FACE_RIGHT; // newob->setxy(xpos, ypos-12); // and move us 'up' } else { curdir = FACE_UP; } break; // end open the door .. default: break; } return 1; }