michael@stb.info.com (Michael Gersten) (04/06/91)
cat > monsters.c << SHAR_EOF_monsters.c /* MDG Multiuser Dungeon Game -- monsters.c monster code MDG is Copyright 1990 John C. Gonnerman This program is subject to the general MDG copyright statement (see enclosed file, Copyright). */ static char *sccsvers = "@(#) monsters.c\t(1.2)\tcreated 1/12/91"; #include <stdio.h> #include "setup.h" #include "struct.h" extern char *progname; extern int errno; extern char *sys_errlist[]; extern struct map_seg *mseg; extern struct player_seg *pseg; extern int map_size, player_size; extern struct monster_tbl *m_table; extern int n_monster; int mon_count = 0; move_monsters() { int i, j; if (++mon_count < MON_TIME) return; mon_count = 0; for(i = 0; i < n_monster; i++) { if(m_table[i].loc.sector == LOC_NONESUCH) resurrect(i); else if(player_here(m_table[i].loc.sector)) for(j = m_table[i].mv_used; j < m_table[i].mv; j++) do_a_monster(i); else roll_over(i); m_table[i].mv_used = 0; m_table[i].att_used = 0; } } pace_monsters() { int i; for(i = 0; i < n_monster; i++) if(m_table[i].mv_used < m_table[i].mv && player_here(m_table[i].loc.sector)) { m_table[i].mv_used++; do_a_monster(i); } } roll_over(m_indx) int m_indx; { int dir; if((dir = at_edge(m_indx)) < 0) return; if(player_here(mseg->m[m_table[m_indx].loc.sector].links[dir])) move_a_monster(m_indx, dir); } int at_edge(m_indx) int m_indx; { switch(m_table[m_indx].loc.x) { case 0 : return L_WEST; case MAPCOLS - 1 : return L_EAST; } switch(m_table[m_indx].loc.y) { case 0 : return L_NORTH; case MAPROWS - 1 : return L_SOUTH; } return -1; } move_a_monster(m_indx, dir) int m_indx; unsigned char dir; { struct location loc; int sector; if((sector = m_table[m_indx].loc.sector) < 0) return; loc.sector = m_table[m_indx].loc.sector; loc.x = m_table[m_indx].loc.x; loc.y = m_table[m_indx].loc.y; mseg->m[loc.sector].map[loc.y][loc.x] = m_table[m_indx].loc.under; if(get_dest(&loc, dir) != -1) mmove_subcmd(m_indx, loc.sector, loc.x, loc.y); move_sym(&(m_table[m_indx].loc), m_table[m_indx].m_sym); mseg->map_sem++; } mmove_subcmd(m_indx, dest_a, dest_x, dest_y) int m_indx, dest_a, dest_x, dest_y; { int rc; rc = move_to(&(m_table[m_indx].loc), dest_a, dest_x, dest_y, -1); if(is_player(rc)) mattack(m_indx, dest_a, dest_x, dest_y); if(rc == 0) { if(dest_a != m_table[m_indx].loc.sector) notify(m_table[m_indx].loc.sector); notify(dest_a); } } int player_here(sector) int sector; { int i; if(sector < 0) return 0; for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].playernum >= 0 && pseg->p[i].loc.sector == sector) return 1; return 0; } int num_player_here(sector) int sector; { int i, j; j = 0; if(sector < 0) return 0; for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].playernum >= 0 && pseg->p[i].loc.sector == sector) j++; return j; } do_a_monster(m_indx) int m_indx; { int target_indx, rc; int m_x, m_y, m_a, p_x, p_y, p_a; if(m_table[m_indx].loc.sector < 0) return; m_table[m_indx].decay_cnt = 0; m_x = m_table[m_indx].loc.x; m_y = m_table[m_indx].loc.y; m_a = m_table[m_indx].loc.sector; if((target_indx = nearest(m_a, m_x, m_y)) == -1) return; p_x = pseg->p[target_indx].loc.x; p_y = pseg->p[target_indx].loc.y; p_a = pseg->p[target_indx].loc.sector; mseg->m[m_a].map[m_y][m_x] = m_table[m_indx].loc.under; if(m_x == p_x) app_m_move(m_indx, (m_y < p_y ? L_SOUTH : L_NORTH )); else if(m_y == p_y) app_m_move(m_indx, (m_x < p_x ? L_EAST : L_WEST )); else if(m_x < p_x) app_m_move(m_indx, (m_y < p_y ? L_SEAST : L_NEAST )); else if(m_x > p_x) app_m_move(m_indx, (m_y < p_y ? L_SWEST : L_NWEST )); move_sym(&(m_table[m_indx].loc), m_table[m_indx].m_sym); mseg->map_sem++; notify(m_a); } app_m_move(m_indx, dir) int m_indx, dir; { if(rnd(100) <= m_table[m_indx].iq) dir = smart_dir(m_indx, dir); else dir = stupid_dir(dir); move_a_monster(m_indx, dir); } int smart_dir(m_indx, dir) int m_indx, dir; { int ndir, mdir, nturn, mturn; mturn = rnd(2) - 1; nturn = mturn == 1 ? 0 : 1; if(test_dir(m_indx, dir)) return dir; if(test_dir(m_indx, (ndir = turn_it(dir, nturn)))) return ndir; if(test_dir(m_indx, (mdir = turn_it(dir, mturn)))) return mdir; if(test_dir(m_indx, (ndir = turn_it(ndir, nturn)))) return ndir; return turn_it(mdir, mturn); } int test_dir(m_indx, dir) int m_indx, dir; { struct location loc; int at_spot; loc = m_table[m_indx].loc; if(get_dest(&loc, dir) == -1 || loc.sector < 0) return 0; at_spot = mseg->m[loc.sector].map[loc.y][loc.x]; if(is_clear(at_spot) || is_player(at_spot)) return 1; return 0; } int stupid_dir(dir) int dir; { switch(rnd(7)) { case 1 : case 2 : return turn_it(dir, 0); case 3 : case 4 : case 5 : return dir; case 6 : case 7 : return turn_it(dir, 1); } } int turn_it(dir, rot) int dir, rot; { switch(dir) { case L_NORTH : return (rot ? L_NEAST : L_NWEST); case L_NEAST : return (rot ? L_EAST : L_NORTH); case L_EAST : return (rot ? L_SEAST : L_NEAST); case L_SEAST : return (rot ? L_SOUTH : L_EAST); case L_SOUTH : return (rot ? L_SWEST : L_SEAST); case L_SWEST : return (rot ? L_WEST : L_SOUTH); case L_WEST : return (rot ? L_NWEST : L_SWEST); case L_NWEST : return (rot ? L_NORTH : L_WEST); } } int nearest(dest_a, dest_x, dest_y) int dest_a, dest_x, dest_y; { int result, dist, n_dist, i; result = -1; dist = 100; for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].playernum != -1 && pseg->p[i].loc.sector == dest_a && !pseg->p[i].invis && (n_dist = distance(i, dest_x, dest_y)) < dist) { dist = n_dist; result = i; } return result; } int distance(indx, dest_x, dest_y) int indx, dest_x, dest_y; { int x_off, y_off; x_off = pseg->p[indx].loc.x - dest_x; y_off = pseg->p[indx].loc.y - dest_y; if(x_off < 0) x_off *= -1; if(y_off < 0) y_off *= -1; return x_off + y_off; } int count_monsters(sector) { int i, cnt; cnt = 0; for(i = 0; i < n_monster; i++) if(m_table[i].loc.sector == sector) cnt++; return cnt; } addMonster(sector) { /* Take a monster from the dead list, and put it in the sector. (Idea is to normally not resurrect monsters, but to add them instead). Future: Increase the number of living monsters */ int lev, mon; lev = mseg->m[sector].level; mon = find_monster(lev); if (mon != -1) place_a_monster (sector, mon); } find_monster(lev) { /* Look through the monster table for a monster of level lev-4 to lev */ static int last_mon = -1; int i, n, last_choice, mon; for(i = last_choice +1, n=n_monster-1; n >= 0; i++, n--) { if (i >= n_monster) i = 0; if (m_table[i].level > lev-4 && m_table[i].level < lev+1 && m_table[i].loc.sector == LOC_NONESUCH) { mon=i; if (rnd(4) == 1) return mon; } } return -1; } resurrect(m_indx) int m_indx; { int rc; int dest_a, dest_x, dest_y, at_loc; if(rnd(100) > RESURRECTION) return; dest_a = rnd(mseg->max_areas - 1); /* never at sector 0 */ if (dest_a == 0) dest_a = mseg->max_areas - 1; if(player_here(dest_a) || mseg->m[dest_a].level < m_table[m_indx].level || count_monsters(dest_a) >= MAX_MONSTERS || m_table[m_indx].level < (mseg->m[dest_a].level - 4)) return; if (count_monsters(dest_a) > MAX_MONSTERS/2 && rnd(4) != 1) return; place_a_monster(dest_a, m_indx); } place_a_monster(dest_a, m_indx) { int rc; int dest_x, dest_y, at_loc; dest_x = rnd(MAPCOLS) - 1; dest_y = rnd(MAPROWS) - 1; at_loc = mseg->m[dest_a].map[dest_y][dest_x]; if(at_loc == '%' || at_loc == '~' || at_loc == '^') return; rc = move_to(&(m_table[m_indx].loc), dest_a, dest_x, dest_y, -1); m_table[m_indx].decay_cnt = 0; if(rc == 0) { move_sym(&(m_table[m_indx].loc), m_table[m_indx].m_sym); m_table[m_indx].hp = m_table[m_indx].max_hp; mseg->map_sem++; notify(dest_a); } } lift_a_monster(m_indx) int m_indx; { int sector, x, y; sector = m_table[m_indx].loc.sector; x = m_table[m_indx].loc.x; y = m_table[m_indx].loc.y; mseg->m[sector].map[y][x] = m_table[m_indx].loc.under; } /* end of file. */ SHAR_EOF_monsters.c cat > combat.c << SHAR_EOF_combat.c /* MDG Multiuser Dungeon Game -- combat.c battle handlers MDG is Copyright 1990 John C. Gonnerman This program is subject to the general MDG copyright statement (see enclosed file, Copyright). */ static char *sccsvers = "@(#) combat.c\t(1.5)\tcreated 1/13/91"; #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "setup.h" #include "struct.h" #include "combat.h" extern struct map_seg *mseg; extern struct player_seg *pseg; extern int dqid, map_size, player_size; extern struct monster_tbl *m_table; extern int n_monster; attack(p_indx, dest_a, dest_x, dest_y) int p_indx, dest_a, dest_x, dest_y; { int i, attacker_indx; attacker_indx = p_indx; if(pseg->p[attacker_indx].attacks == 0) return; pseg->p[attacker_indx].attacks--; if(is_player(mseg->m[dest_a].map[dest_y][dest_x])) { for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == dest_a && pseg->p[i].loc.x == dest_x && pseg->p[i].loc.y == dest_y) pattackp(attacker_indx, i); } else { for(i = 0; i < n_monster; i++) if(m_table[i].loc.sector == dest_a && m_table[i].loc.x == dest_x && m_table[i].loc.y == dest_y) pattackm(attacker_indx, i); pace_monsters(); } } mattack(m_indx, dest_a, dest_x, dest_y) int m_indx, dest_a, dest_x, dest_y; { int i; for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == dest_a && pseg->p[i].loc.x == dest_x && pseg->p[i].loc.y == dest_y) switch(m_table[m_indx].attack) { case ATT_BREATH : /* not done yet. */ case ATT_HITS : mattackp(m_indx, i); break; case ATT_STEALS : mstealp(m_indx, i); break; case ATT_DRAINS : mdrainp(m_indx, i); break; case ATT_DRAINMP : mdrainmp(m_indx, i); break; case ATT_DRAINHP : mdrainhp(m_indx, i); break; case ATT_DRAINLIFE : mdrainl(m_indx, i); break; } } int mhit(a_indx, v_indx) int a_indx, v_indx; { int chance; chance = 50 + m_table[a_indx].fight - pseg->p[v_indx].fighting; chance = (chance + 51) / 2; if(chance < MIN_CHANCE) chance = MIN_CHANCE; if(chance > MAX_CHANCE) chance = MAX_CHANCE; return rnd(100) <= chance; } int ccomp(odds, a_indx) int odds, a_indx; { odds = (odds + 51) / 2; if(pseg->p[a_indx].knight) odds += 30; if(odds < MIN_CHANCE) odds = MIN_CHANCE; if(odds > MAX_CHANCE) odds = MAX_CHANCE; return odds; } int phitm(a_indx, v_indx) int a_indx, v_indx; { int chance, real_chance; real_chance = 50 + pseg->p[a_indx].fighting - m_table[v_indx].fight; chance = ccomp(real_chance, a_indx); if(rnd(100) <= chance) { improve_f(a_indx, real_chance); return 1; } return 0; } int phitp(a_indx, v_indx) int a_indx, v_indx; { int chance, real_chance; real_chance = 50 + pseg->p[a_indx].fighting - pseg->p[v_indx].fighting; chance = ccomp(real_chance, a_indx); if(rnd(100) <= chance) { improve_f(a_indx, real_chance); return 1; } return 0; } int mdamage(a_indx) int a_indx; { return rnd(m_table[a_indx].max_dam); } int pdamage(a_indx) int a_indx; { int wpn, eff; wpn = pseg->weapon[a_indx]; if(wpn < 0) return rnd(pseg->p[a_indx].fighting / 20); else if(wpn < pseg->item_count) { eff = pseg->itm[wpn].effect; if(pseg->itm[wpn].curse) eff = 0; return rnd(eff); } else { fprintf(stderr, "weapon range error, pnum = %d, wpn = %d\n", pseg->p[a_indx].playernum, wpn); pseg->weapon[a_indx] = -1; } return 0; } int ptakedamage(v_indx, damage) int v_indx, damage; { if(damage < 0) damage = 0; pseg->p[v_indx].hitpoints -= damage; pseg->player_sem++; tell_player(v_indx); if(pseg->p[v_indx].hitpoints < 1) { killp(v_indx); return -1; } return 0; } int pgetzapped(v_indx, damage) int v_indx, damage; { if(pseg->p[v_indx].ma_count > 0) damage = dcomp(damage, pseg->p[v_indx].m_armor); return(ptakedamage(v_indx, damage)); } int pgethit(v_indx, damage) int v_indx, damage; { int armor, ai, si; armor = 0; ai = pseg->armor[v_indx]; if(ai >= 0) { if(ai >= pseg->item_count) { fprintf(stderr, "Armor index out of range (%d)\n", ai); pseg->armor[v_indx] = -1; } else if(pseg->itm[ai].curse == 0) { armor += pseg->itm[ai].effect; } } si = pseg->shield[v_indx]; if(si >= 0) { if(si >= pseg->item_count) { fprintf(stderr, "Shield index out of range (%d)\n", si); pseg->shield[v_indx] = -1; } else if(pseg->itm[si].curse == 0) { armor += pseg->itm[si].effect; } } damage -= armor; return(pgetzapped(v_indx, damage)); } int mgethit(v_indx, damage) int v_indx, damage; { if(damage < 1) damage = 1; if(m_table[v_indx].hp > m_table[v_indx].max_hp) m_table[v_indx].hp = m_table[v_indx].max_hp; m_table[v_indx].hp -= damage; if(m_table[v_indx].hp < 1) { killm(v_indx); return -1; } return 0; } pattackp(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; int damage; if(pseg->p[v_indx].loc.sector == 0) return; if(pseg->p[a_indx].partners[v_indx] == 1) return; visible(a_indx); sprintf(buf, "%c attacked you!", '1' + a_indx); dmsg_add(v_indx, buf); if(!phitp(a_indx, v_indx)) { if(pseg->p[a_indx].brief) dmsg_add(a_indx, "You missed"); else dmsg_add(a_indx, "You missed the player"); return; } damage = pdamage(a_indx); if(pseg->p[a_indx].brief) dmsg_add(a_indx, "Hit player!"); else { dmsg_add(a_indx, "You hit the player!"); sprintf(buf, "Damage: %d", damage); dmsg_add(a_indx, buf); } sprintf(buf, "%c HIT you!", '1' + a_indx); dmsg_add(v_indx, buf); if(pgethit(v_indx, damage) == -1) { dmsg_add(a_indx, "You KILLED the player!"); pseg->p[a_indx].lives++; pseg->player_sem++; improve_h(a_indx, d_level(v_indx)); } } pattackm(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; int damage; visible(a_indx); if(!phitm(a_indx, v_indx)) { if(pseg->p[a_indx].brief) { sprintf(buf, "Missed %s", m_table[v_indx].name); dmsg_add(a_indx, buf); } else { sprintf(buf, "You missed the %s", m_table[v_indx].name); dmsg_add(a_indx, buf); } return; } damage = pdamage(a_indx); if(pseg->p[a_indx].brief) { sprintf(buf, "Hit %s!", m_table[v_indx].name, damage); dmsg_add(a_indx, buf); } else { sprintf(buf, "You hit the %s!", m_table[v_indx].name, damage); dmsg_add(a_indx, buf); sprintf(buf, "Damage: %d", damage); dmsg_add(a_indx, buf); } if(mgethit(v_indx, damage) == -1) { sprintf(buf, "You KILLED the %s", m_table[v_indx].name); dmsg_add(a_indx, buf); improve_h(a_indx, m_table[v_indx].danger); } } mattackp(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } (void)pgethit(v_indx, mdamage(a_indx)); } mdrainp(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } pseg->p[v_indx].magicpts -= mdamage(a_indx); if(pseg->p[v_indx].magicpts < 0) { pseg->p[v_indx].magicpts = 0; (void)pgetzapped(v_indx, mdamage(a_indx)); } } mdrainl(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } pseg->p[v_indx].lives--; if(pseg->p[v_indx].lives < 0) { pseg->p[v_indx].lives = 0; (void)pgetzapped(v_indx, mdamage(a_indx)); } clearm(a_indx, 0); } mdrainhp(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; int damage; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } if(pseg->p[v_indx].ma_count > 0) damage = dcomp(mdamage(a_indx), pseg->p[v_indx].m_armor); else damage = mdamage(a_indx); pseg->p[v_indx].max_hp -= damage; if(pseg->p[v_indx].max_hp < 2) { pseg->p[v_indx].max_hp = 2; (void)pgetzapped(v_indx, mdamage(a_indx)); } if(pseg->p[v_indx].hitpoints > pseg->p[v_indx].max_hp) pseg->p[v_indx].hitpoints = pseg->p[v_indx].max_hp; clearm(a_indx, 0); } mdrainmp(a_indx, v_indx) int a_indx, v_indx; { char buf[35]; int damage; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } if(pseg->p[v_indx].ma_count > 0) damage = dcomp(mdamage(a_indx), pseg->p[v_indx].m_armor); else damage = mdamage(a_indx); pseg->p[v_indx].max_mp -= damage; if(pseg->p[v_indx].max_mp < 2) { pseg->p[v_indx].max_mp = 2; (void)pgetzapped(v_indx, mdamage(a_indx)); } if(pseg->p[v_indx].magicpts > pseg->p[v_indx].max_mp) pseg->p[v_indx].magicpts = pseg->p[v_indx].max_mp; clearm(a_indx, 0); } #ifdef BUGGED_CODE_DO_NOT_USE int dcomp(damage, armor) int damage, armor; { int final_damage; final_damage = damage - armor; /* This routine is called with the magic armor value in armor. It can never be more than 6, so if damage is > 10 this section does nothing */ if(damage > 10) { if(final_damage < -20) final_damage = 0; else if(final_damage < 1) final_damage = 1; } else { /* Now this section allows the possibility of taking a point of damage with magic armor that would not have been taken without the magic armor */ if(final_damage < -10) final_damage = 0; else if(final_damage < 1) final_damage = 1; } return final_damage; } #else int dcomp(damage, armor) { if (damage < 0) return 0; if (damage < armor) return 1; /* magic armor can't stop everything */ return damage-armor; } #endif mstealp(a_indx, v_indx) int a_indx, v_indx; { int trys, item, i; char buf[35]; if(m_table[a_indx].att_used >= M_ATTACKS) return; m_table[a_indx].att_used++; if(!mhit(a_indx, v_indx)) { if(!pseg->p[v_indx].brief) { sprintf(buf, "%s missed you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } return; } if(!pseg->p[v_indx].brief) { sprintf(buf, "%s HIT you!", m_table[a_indx].name); dmsg_add(v_indx, buf); } if(rnd(PMAX_ITEMS) == 1) { pseg->p[v_indx].gold -= go2r(pseg->p[v_indx].gold); pseg->player_sem++; return; } for(trys = 0; trys < 3; trys++) { item = rnd(PMAX_ITEMS) - 1; if((i = pseg->p[v_indx].items[item]) != -1) { pseg->itm[i].loc.sector = LOC_NONESUCH; delete_item(v_indx, i); deselect(v_indx, i); pseg->item_sem++; pseg->player_sem++; return; } } } killp(v_indx) int v_indx; { int sector, x, y; sector = pseg->p[v_indx].loc.sector; x = pseg->p[v_indx].loc.x; y = pseg->p[v_indx].loc.y; mseg->m[sector].map[y][x] = pseg->p[v_indx].loc.under; drop_all(v_indx, sector, x, y); mseg->map_sem++; del_player(v_indx); pseg->p[v_indx].loc.sector = LOC_NONESUCH; notify(sector); pseg->player_sem++; tell_player(v_indx); } clearm(v_indx, t_flag) int v_indx, t_flag; { int sector, x, y; sector = m_table[v_indx].loc.sector; x = m_table[v_indx].loc.x; y = m_table[v_indx].loc.y; if (sector < 0) return; mseg->m[sector].map[y][x] = m_table[v_indx].loc.under; if(t_flag) do_treasure(v_indx); mseg->map_sem++; m_table[v_indx].loc.sector = LOC_NONESUCH; m_table[v_indx].decay_cnt = 0; } killm(v_indx) int v_indx; { int sector; sector = m_table[v_indx].loc.sector; clearm(v_indx, 1); notify(sector); } do_treasure(v_indx) int v_indx; { int tval, danger; int sector, x, y; sector = m_table[v_indx].loc.sector; x = m_table[v_indx].loc.x; y = m_table[v_indx].loc.y; danger = m_table[v_indx].danger; if(danger >= DANGER_CUT && rnd(CRYSTAL_ODDS) == 1) { put_crystal(sector, x, y); return; } tval = (m_table[v_indx].max_hp + (danger * 10)) / 2; #ifdef OLD_CODE_0 /* Used to be: Weak monsters had small chance of treasure, could be anything. */ if(rnd(100) > tval) return; #else /* Now: Chance of treasure is nearly flat. Stronger monsters have bigger treasure */ if (rnd(100) > tval && rnd(4) == 1) return; switch(rnd(2)) { case 1 : put_item_tr(sector, x, y, tval * 20); break; case 2 : put_treasure(tval * 20, sector, x, y); break; } } put_treasure(max_cash, sector, x, y) int max_cash, sector, x, y; { int i; for(i = 0; i < pseg->item_count; i++) { if(pseg->itm[i].loc.sector == LOC_NONESUCH && pseg->itm[i].type == CASH) { pseg->itm[i].decay_cnt = 0; pseg->itm[i].loc.under = mseg->m[sector].map[y][x]; pseg->itm[i].value = rnd(max_cash); (void)put_item(i, sector, x, y); return; } } /* If we got here, we are out of treasure spots. */ /* TARGET: Need to make new ones */ dmsg_all("Out Of Treasure Slots!"); } put_crystal(sector, x, y) int sector, x, y; { int i; for(i = 0; i < pseg->item_count; i++) { if(pseg->itm[i].loc.sector == LOC_NONESUCH && pseg->itm[i].type == CRYSTAL) { pseg->itm[i].decay_cnt = 0; pseg->itm[i].loc.under = mseg->m[sector].map[y][x]; pseg->itm[i].effect = 3 - go2r(2); (void)put_item(i, sector, x, y); return; } } } put_item_tr(sector, x, y, max_val) int sector, x, y, max_val; { int i, n; long min_val; static int choice = -1; static int last_choice = 0; /* Previously the award was based solely on danger. This made it impossible to award the top of the line prizes. */ /* Now give 1/3 to 2/3 the cash value in prizes. Winners pay all income tax themselves. Void where prohibited. */ max_val = max_val * 2 / 3; min_val = max_val / 2; for(i = last_choice +1, n=pseg->item_count-1; n >= 0; i++, n--) { if (i >= pseg->item_count) i = 0; if(pseg->itm[i].loc.sector == LOC_NONESUCH && pseg->itm[i].type != CRYSTAL && pseg->itm[i].type != CASH && pseg->itm[i].value >= min_val && pseg->itm[i].value < max_val) { if(choice == -1 || rnd(2) == 1) choice = i; if(rnd(4) == 1) break; } } if(choice == -1) return; last_choice = choice; pseg->itm[choice].decay_cnt = 0; pseg->itm[choice].loc.under = mseg->m[sector].map[y][x]; pseg->itm[choice].rem_uses = pseg->itm[choice].max_uses; (void)put_item(choice, sector, x, y); } drop_all(p_indx, sector, x, y) int p_indx, sector, x, y; { int i, playernum; playernum = pseg->p[p_indx].playernum; for(i = 0; i < pseg->item_count; i++) { if(pseg->itm[i].loc.sector == LOC_PLAYER && pseg->itm[i].loc.x == playernum) if(put_item(i, sector, x, y) == -1) pseg->itm[i].loc.sector = LOC_NONESUCH; if(pseg->p[p_indx].gold > 0 && pseg->itm[i].loc.sector == LOC_NONESUCH && pseg->itm[i].type == CASH) { pseg->itm[i].value = pseg->p[p_indx].gold; pseg->p[p_indx].gold = 0; put_item(i, sector, x, y); } } notify(sector); } damage_it(damage, t_a, t_x, t_y) int damage, t_a, t_x, t_y; { int i; if(is_player(mseg->m[t_a].map[t_y][t_x])) { for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == t_a && pseg->p[i].loc.x == t_x && pseg->p[i].loc.y == t_y) (void)pgethit(i, damage); } else { for(i = 0; i < n_monster; i++) if(m_table[i].loc.sector == t_a && m_table[i].loc.x == t_x && m_table[i].loc.y == t_y) mgethit(i, damage); } } /* tune the following if you make major changes */ /* to MAX_HP or allow monsters with greater than */ /* 200 fighting scores. */ int d_level(p_indx) int p_indx; { int danger; danger = pseg->p[p_indx].fighting / 30; danger += pseg->p[p_indx].max_hp / 20; return danger; } /* end of file. */ SHAR_EOF_combat.c cat > magic.c << SHAR_EOF_magic.c /* MDG Multiuser Dungeon Game -- magic.c magic handler MDG is Copyright 1990 John C. Gonnerman This program is subject to the general MDG copyright statement (see enclosed file, Copyright). */ static char *sccsvers = "@(#) magic.c\t(1.2)\tcreated 1/2/91"; #include <stdio.h> #include "setup.h" #include "struct.h" #include "spells.h" #define NOSPELL(x) dmsg_add(x, "spell not available") extern struct player_seg *pseg; extern struct map_seg *mseg; extern struct monster_tbl *m_table; extern int n_monster; extern char *spell_names[]; extern int spell_dd[]; extern struct ast a_spell_table[]; char under[8]; int n_sectors[4]; cast_spell(indx, mptr) int indx; struct dmessage *mptr; { int spell, who, what, dir, max_damage, rc; int x, y; /* debug */ char buf[35]; char *text; spell = mptr->subcmd; what = who = dir = mptr->arg; text = mptr->text; sprintf(buf, "cast %s...", spell_names[spell]); dmsg_add(indx, buf); if(cast_it(spell, indx) == -1) { pseg->p[indx].magicpts -= (pseg->p[indx].magicpts ? 1 : 0); sprintf(buf, "%s failed", spell_names[spell]); dmsg_add(indx, buf); return; } switch(spell + 'a') { case 'a' : /* armor */ /* debug pseg->p[indx].ma_count += rnd(300); pseg->p[indx].m_armor += rnd(5); */ x = rnd(300); y = rnd(5); pseg->p[indx].ma_count += x; pseg->p[indx].m_armor += y; if(pseg->p[indx].m_armor > MAX_MARMOR) pseg->p[indx].m_armor = MAX_MARMOR; pseg->player_sem++; tell_player(indx); break; case 'b' : /* block */ pseg->p[indx].blocked += go2r(100); dmsg_add(indx, "Seeks now blocked."); break; case 'c' : /* cold */ dmsg_add(indx, "Whoosh!"); visible(indx); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; cast_a_spell(&(pseg->p[indx].loc), AS_COLD, dir, go2r(max_damage)); break; case 'd' : /* detect */ detect(indx); tell_player(indx); break; case 'e' : /* escape */ if((rc = jump_to(indx, pseg->p[indx].home)) == -1) dmsg_add(indx, "escape bounced"); else if(rc == -2) dmsg_add(indx, "escape fizzled"); else dmsg_add(indx, "escaped!"); break; case 'f' : /* fireball */ visible(indx); dmsg_add(indx, "Boom!"); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; cast_a_spell(&(pseg->p[indx].loc), AS_FIREBALL, dir, go2r(max_damage)); break; case 'g' : /* glow */ glow(indx); tell_player(indx); break; case 'h' : /* heal */ heal(indx); tell_player(indx); break; case 'i' : /* invisible */ invisible(indx); tell_player(indx); break; case 'j' : /* jump back */ jump_back(indx); break; case 'k' : /* knight */ knight(indx); break; case 'l' : /* lightning */ visible(indx); dmsg_add(indx, "Crackle!"); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; cast_a_spell(&(pseg->p[indx].loc), AS_LIGHTNING, dir, go2r(max_damage)); break; case 'm' : /* missile */ visible(indx); dmsg_add(indx, "A fiery missile appears!"); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; ranged_spell(indx, dir, 'm' - 'a', go2r(10), max_damage); break; case 'n' : /* n */ nightmare(indx, who); break; case 'o' : /* obscure */ if(what >= 0) { toggle_obscure(what); dmsg_add(indx, "The object shimmers..."); } else if(what == -1) { pseg->p[indx].gold_hidden = (pseg->p[indx].gold_hidden ? 0 : 1); dmsg_add(indx, "Your gold shimmers..."); } else dmsg_add(indx, "obscure what?"); break; case 'p' : /* partners */ show_partners(indx); break; case 'q' : /* quit */ quit_spell(indx); break; case 'r' : /* death ray */ visible(indx); dmsg_add(indx, "Bzzzzzt!"); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; cast_a_spell(&(pseg->p[indx].loc), AS_DEATHRAY, dir, go2r(max_damage)); break; case 's' : /* seek */ seek_s(indx, who); break; case 't' : /* teleport */ teleport(indx); break; case 'u' : /* user */ pseg->p[indx].user_spell += go2r(USER_DUR); pseg->player_sem++; break; case 'v' : /* verify */ verify_item(indx, what); break; case 'w' : /* whisper */ whisper(indx, who, text); break; case 'x' : /* spell x */ spell_x(indx); break; case 'y' : /* yank */ yank(indx, who); break; case 'z' : /* zap */ visible(indx); dmsg_add(indx, "Zap!"); max_damage = (pseg->p[indx].spells[spell] + 50) / 3; cast_a_spell(&(pseg->p[indx].loc), AS_ZAP, L_EAST, go2r(max_damage)); break; default : break; } } quit_spell(indx) int indx; { int sector, x, y; sector = pseg->p[indx].loc.sector; if(sector < 0) return; x = pseg->p[indx].loc.x; y = pseg->p[indx].loc.y; mseg->m[sector].map[y][x] = pseg->p[indx].loc.under; mseg->map_sem++; pseg->p[indx].loc.x = sector; pseg->p[indx].loc.sector = LOC_HOME; } show_partners(p_indx) int p_indx; { int i, len; char o_buf[35]; strcpy(o_buf, "Partners:"); for(i = 0; i < MAX_PLAYERS; i++) if(i != p_indx && pseg->p[i].playernum >= 0 && pseg->p[i].partners[p_indx] == 1) { len = strlen(o_buf); o_buf[len] = ' '; o_buf[len + 1] = i + '1'; o_buf[len + 2] = '\0'; } dmsg_add(p_indx, o_buf); } int cast_it(spell, indx) int spell, indx; { if(pseg->p[indx].magicpts < (spell_dd[spell] + 1) || rnd(90 + (10 * spell_dd[spell])) > pseg->p[indx].spells[spell]) return -1; improve_s(indx, spell); pseg->p[indx].magicpts -= (spell_dd[spell] + 1); pseg->player_sem++; tell_player(indx); return 0; } spell_x(p_indx) int p_indx; { int max_damage, i, sector; sector = pseg->p[p_indx].loc.sector; for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == sector) dmsg_add(i, "KA-BOOM!!!"); max_damage = 5 * pseg->p[p_indx].magicpts; if(max_damage < 1) max_damage = 5; pseg->p[p_indx].magicpts = 0; for(i = 0; i < n_monster; i++) if(m_table[i].loc.sector == sector) mgethit(i, go2r(max_damage)); for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == sector && i != p_indx && pseg->p[p_indx].partners[i] == 0) pgethit(i, rnd(max_damage)); pseg->player_sem++; mseg->map_sem++; notify(sector); } yank(p_indx, v_indx) int p_indx, v_indx; { int dest_a, rc; char buf[35]; if(v_indx < 0 || v_indx >= MAX_PLAYERS) return; dest_a = pseg->p[p_indx].loc.sector; if(pseg->p[v_indx].loc.sector < 0 || pseg->p[v_indx].playernum < 0 || pseg->p[v_indx].blocked > 0) { sprintf(buf, "%c not found.", (char)('1' + v_indx)); dmsg_add(p_indx, buf); } else if((rc = jump_to(v_indx, dest_a)) == -1) dmsg_add(p_indx, "yank bounced"); else if(rc == -2) dmsg_add(p_indx, "yank fizzled"); else { sprintf(buf, "%c yanked!", (char)('1' + v_indx)); dmsg_add(p_indx, buf); dmsg_add(v_indx, "you've been yanked!"); } } jump_back(indx) int indx; { int dest_a, rc; dest_a = pseg->p[indx].prev_sect; if((rc = jump_to(indx, dest_a)) == -1) dmsg_add(indx, "jump back bounced"); else if(rc == -2) dmsg_add(indx, "jump back fizzled"); else dmsg_add(indx, "returned"); } teleport(indx) int indx; { int dest_a, rc; dest_a = rnd(mseg->max_areas) - 1; if((rc = jump_to(indx, dest_a)) == -1) dmsg_add(indx, "teleport bounced"); else if(rc == -2) dmsg_add(indx, "teleport fizzled"); else dmsg_add(indx, "teleported"); } int jump_to(indx, sector) int indx, sector; { int cnt, rc, symbol, link_dd; int old_s, x, y, dest_x, dest_y; old_s = pseg->p[indx].loc.sector; x = pseg->p[indx].loc.x; y = pseg->p[indx].loc.y; link_dd = mseg->m[old_s].jump_inhibit + mseg->m[sector].jump_inhibit; if(rnd(10) < link_dd) return -2; for(cnt = 0; cnt < TELE_TRYS; cnt++) { mseg->m[old_s].map[y][x] = pseg->p[indx].loc.under; mseg->map_sem++; dest_x = rnd(MAPCOLS) - 1; dest_y = rnd(MAPROWS) - 1; rc = t_move_to(&(pseg->p[indx].loc), sector, dest_x, dest_y, indx); symbol = pseg->p[indx].invis ? indx + 11 : indx + 1; move_sym(&(pseg->p[indx].loc), symbol); mseg->map_sem++; if(rc == 0) { pseg->p[indx].prev_sect = old_s; notify(sector); notify(old_s); return 0; } } return -1; } int send_monster(m_indx, sector) int m_indx, sector; { int rc; lift_a_monster(m_indx); rc = move_to(&(m_table[m_indx].loc), sector, m_table[m_indx].loc.x, m_table[m_indx].loc.y, -1); move_sym(&(m_table[m_indx].loc), m_table[m_indx].m_sym); mseg->map_sem++; if(rc == 0) { notify(sector); return 0; } return -1; } visible(p_indx) int p_indx; { int sector, x, y; pseg->p[p_indx].invis = 0; sector = pseg->p[p_indx].loc.sector; x = pseg->p[p_indx].loc.x; y = pseg->p[p_indx].loc.y; if(sector < 0) return; mseg->m[sector].map[y][x] = 1 + p_indx; mseg->map_sem++; } invisible(p_indx) int p_indx; { int sector, x, y; pseg->p[p_indx].invis += rnd(100); dmsg_add(p_indx, "you disappear!"); sector = pseg->p[p_indx].loc.sector; x = pseg->p[p_indx].loc.x; y = pseg->p[p_indx].loc.y; if(sector < 0) return; mseg->m[sector].map[y][x] = 11 + p_indx; mseg->map_sem++; notify(sector); } heal(p_indx) int p_indx; { pseg->p[p_indx].hitpoints += rnd(10); if(pseg->p[p_indx].hitpoints > pseg->p[p_indx].max_hp) pseg->p[p_indx].hitpoints = pseg->p[p_indx].max_hp; dmsg_add(p_indx, "you feel better"); } glow(p_indx) int p_indx; { pseg->p[p_indx].light += (6 * rnd(100)); mseg->map_sem++; dmsg_add(p_indx, "it's brighter now"); } detect(indx) int indx; { pseg->p[indx].detect += go2r(DETECT_DUR); mseg->map_sem++; dmsg_add(indx, "your vision sharpens"); } ranged_spell(p_indx, dir, spell, range, damage) int p_indx, dir, spell, range, damage; { char buf[35]; if(rspell_start(p_indx, 21, range, damage, dir) == -1) { sprintf(buf, "%s failed", spell_names[spell]); dmsg_add(p_indx, buf); } } int rspell_start(indx, symbol, range, damage, dir) int indx, symbol, range, damage, dir; { return start_ranged(symbol, 5, damage, pseg->p[indx].loc.sector, pseg->p[indx].loc.x, pseg->p[indx].loc.y, dir); } int t_move_to(locptr, dest_a, dest_x, dest_y, p_indx) struct location *locptr; int dest_a, dest_x, dest_y, p_indx; { char at_loc; if(dest_a < 0) return -1; at_loc = mseg->m[dest_a].map[dest_y][dest_x]; switch(at_loc) { case '0' : /* 0-9 are traps */ case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : do_trap(p_indx, at_loc); locptr->sector = dest_a; locptr->x = dest_x; locptr->y = dest_y; locptr->under = at_loc; mseg->map_sem++; return 0; case '.' : case ' ' : case '`' : /* shallow water */ case '+' : /* secret door */ case '<' : /* down */ case '>' : /* up */ locptr->sector = dest_a; locptr->x = dest_x; locptr->y = dest_y; locptr->under = at_loc; mseg->map_sem++; return 0; default : return (int)at_loc; } } clear_n_sectors() { int i; for(i = 0; i < 4; i++) n_sectors[i] = LOC_NONESUCH; } add_n_sector(sector) int sector; { int i; for(i = 0; i < 4; i++) if(n_sectors[i] == LOC_NONESUCH) { n_sectors[i] = sector; return; } } notify_n_sectors() { int i; for(i = 0; i < 4; i++) if(n_sectors[i] != LOC_NONESUCH) notify(n_sectors[i]); } cast_a_spell(loc, a_spell, dir, effect) struct location *loc; int a_spell, dir, effect; { int i, limit; char at_spot; struct location t_loc; switch(dir) { case L_NORTH : case L_SOUTH : case L_EAST : case L_WEST : case L_NEAST : case L_NWEST : case L_SEAST : case L_SWEST : break; default : return; } clear_n_sectors(); limit = 99; for(i = 0; i < 8; i++) { t_loc.sector = loc->sector; t_loc.x = loc->x; t_loc.y = loc->y; loc_a_spell(&t_loc, a_spell, i, dir); if(correct_loc(&t_loc) != -1) { at_spot = mseg->m[t_loc.sector].map[t_loc.y][t_loc.x]; if(a_spell_table[a_spell].advance[i] <= limit && at_spot != '#') { add_n_sector(t_loc.sector); under[i] = at_spot; mseg->m[t_loc.sector].map[t_loc.y][t_loc.x] = '*'; } else if(at_spot == '#' && a_spell_table[a_spell].advance[i] < limit && a_spell_table[a_spell].flag == ASF_LIMITED) { limit = a_spell_table[a_spell].advance[i]; } } } mseg->map_sem++; notify_n_sectors(); busy_wait(600000L); clear_n_sectors(); for(i = 0; i < 8; i++) { t_loc.sector = loc->sector; t_loc.x = loc->x; t_loc.y = loc->y; loc_a_spell(&t_loc, a_spell, i, dir); if(a_spell_table[a_spell].advance[i] <= limit && correct_loc(&t_loc) != -1 && mseg->m[t_loc.sector].map[t_loc.y][t_loc.x] == '*') { add_n_sector(t_loc.sector); mseg->m[t_loc.sector].map[t_loc.y][t_loc.x] = under[i]; } } mseg->map_sem++; notify_n_sectors(); for(i = 0; i < 8; i++) { t_loc.sector = loc->sector; t_loc.x = loc->x; t_loc.y = loc->y; loc_a_spell(&t_loc, a_spell, i, dir); if(correct_loc(&t_loc) != -1 && a_spell_table[a_spell].advance[i] <= limit) zap_spot(t_loc.sector, t_loc.x, t_loc.y, effect); } } zap_spot(sector, x, y, effect) int sector, x, y, effect; { int i; if(is_player(mseg->m[sector].map[y][x])) { for(i = 0; i < MAX_PLAYERS; i++) if(pseg->p[i].loc.sector == sector && pseg->p[i].loc.x == x && pseg->p[i].loc.y == y) pgetzapped(i, effect); } else { for(i = 0; i < n_monster; i++) if(m_table[i].loc.sector == sector && m_table[i].loc.x == x && m_table[i].loc.y == y) mgethit(i, effect); } } loc_a_spell(loc, spell, pos, dir) struct location *loc; int spell, pos, dir; { int off, adv; off = a_spell_table[spell].offset[pos]; adv = a_spell_table[spell].advance[pos]; switch(dir) { case L_NORTH : loc->y -= adv; loc->x += off; break; case L_SOUTH : loc->y += adv; loc->x -= off; break; case L_EAST : loc->x += adv; loc->y += off; break; case L_WEST : loc->x -= adv; loc->y -= off; break; case L_NEAST : loc->y += (-1 * adv) + off - (off > 0); loc->x += off + adv + (off < 0); break; case L_NWEST : loc->y += (-1 * adv) + (-1 * off) - (off < 0); loc->x += off + (-1 * adv) - (off > 0); break; case L_SEAST : loc->y += adv + off + (off < 0); loc->x += (-1 * off) + adv + (off > 0); break; case L_SWEST : loc->y += adv + (-1 * off) + (off > 0); loc->x += (-1 * off) + (-1 * adv) - (off < 0); break; } } int correct_loc(loc) struct location *loc; { if(loc->y < 0 && loc->x >= MAPCOLS) return -1; if(loc->y < 0 && loc->x < 0) return -1; if(loc->y >= MAPROWS && loc->x < 0) return -1; if(loc->y >= MAPROWS && loc->x >= MAPCOLS) return -1; if(loc->x >= MAPCOLS) { loc->x -= MAPCOLS; loc->sector = mseg->m[loc->sector].links[L_EAST]; } if(loc->x < 0) { loc->x += MAPCOLS; loc->sector = mseg->m[loc->sector].links[L_WEST]; } if(loc->y >= MAPROWS) { loc->y -= MAPROWS; loc->sector = mseg->m[loc->sector].links[L_SOUTH]; } if(loc->y < 0) { loc->y += MAPROWS; loc->sector = mseg->m[loc->sector].links[L_NORTH]; } if(loc->sector < 0) return -1; return 0; } busy_wait(delay) long delay; { for(; delay; delay--); } seek_s(p_indx, v_indx) int p_indx, v_indx; { char buf[35]; int rc; if(v_indx < 0 || v_indx >= MAX_PLAYERS) return; if(pseg->p[v_indx].loc.sector < 0 || pseg->p[v_indx].playernum < 0 || pseg->p[v_indx].blocked > 0) { sprintf(buf, "%c not found.", (char)('1' + v_indx)); dmsg_add(p_indx, buf); } else if((rc = jump_to(p_indx, pseg->p[v_indx].loc.sector)) == -1) dmsg_add(p_indx, "seek bounced."); else if(rc == -2) dmsg_add(p_indx, "seek fizzled."); else { sprintf(buf, "%c found!", (char)('1' + v_indx)); dmsg_add(p_indx, buf); } } toggle_obscure(item_indx) int item_indx; { if(item_indx < 0 || item_indx >= pseg->item_count || pseg->itm[item_indx].loc.sector > -1) return; if(pseg->itm[item_indx].type == pseg->itm[item_indx].symbol) pseg->itm[item_indx].symbol = HIDDEN; else pseg->itm[item_indx].symbol = pseg->itm[item_indx].type; pseg->item_sem++; } verify_item(indx, what) int indx, what; { char buf[35]; if(what < 0 || what >= pseg->item_count) return; if(pseg->itm[what].curse == 0) sprintf(buf, "%s is OK", pseg->itm[what].name); else sprintf(buf, "%s is CURSED", pseg->itm[what].name); dmsg_add(indx, buf); } knight(p_indx) int p_indx; { dmsg_add(p_indx, "You feel more confident."); pseg->p[p_indx].knight += rnd(KNIGHT_DUR); } nightmare(p_indx, v_indx) int p_indx, v_indx; { char buf[35]; int choice; if(v_indx < 0 || v_indx >= MAX_PLAYERS) return; if(pseg->p[v_indx].loc.sector < 0 || pseg->p[v_indx].playernum < 0 || pseg->p[v_indx].blocked > 0) { sprintf(buf, "%c not found.", (char)('1' + v_indx)); dmsg_add(p_indx, buf); return; } if((choice = nearestm(p_indx)) == -1) { dmsg_add(p_indx, "No monster."); return; } if(send_monster(choice, pseg->p[v_indx].loc.sector) == -1) { dmsg_add(p_indx, "Can't send monster."); return; } dmsg_add(p_indx, "Monster sent..."); dmsg_add(v_indx, "A Nightmare!!!"); } int nearestm(p_indx) int p_indx; { int result, dist, n_dist, i; int dest_a, m_a, m_x, m_y; result = -1; dist = 100; dest_a = pseg->p[p_indx].loc.sector; for(i = 0; i < n_monster; i++) { m_a = m_table[i].loc.sector; m_x = m_table[i].loc.x; m_y = m_table[i].loc.y; if(m_a == dest_a && (n_dist = distance(p_indx, m_x, m_y)) < dist) { dist = n_dist; result = i; } } return result; } /* end of file. */ SHAR_EOF_magic.c cat > clock.c << SHAR_EOF_clock.c /* MDG Multiuser Dungeon Game -- clock task MDG is Copyright 1990 John C. Gonnerman This program is subject to the general MDG copyright statement (see enclosed file, Copyright). */ static char *sccsx = "@(#) MDG_CLOCK Copyright 1990 John C. Gonnerman"; static char *sccsvers = "@(#) clock.c\t(1.2)\tcreated 1/2/91"; #include <stdio.h> #include <string.h> #include <signal.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include "setup.h" #include "files.h" #include "struct.h" #include "messages.h" extern long dmsgkey, gsemkey, mapkey, playerkey; char *progname; int dqid; extern int errno; extern char *sys_errlist[]; main(argc, argv) int argc; char **argv; { struct dmessage msg_buf; char *strrchr(), *strstr(); int mode; if((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; fputs("clock started.\n", stderr); if(argc != 1) { fprintf(stderr, ARGCOUNT, progname, argc); exit(1); } chdir(GAME_HOME); /* load keys from config file */ loadconfig(); /* set signal handlers */ /* signal(SIGHUP, exit); signal(SIGTERM, exit); */ /* open message queue */ if((dqid = msgget(dmsgkey, 0)) == -1) { fprintf(stderr, CANTERR, progname, "open queue", sys_errlist[errno]); exit(1); } /* actual monster packet driver */ while(1) { sleep(1); msg_buf.msg_type = 1L; msg_buf.cmd = ' '; msg_buf.playernum = -1; msgsnd(dqid, &msg_buf, DMSGSIZ, IPC_NOWAIT); } } /* end of file */ SHAR_EOF_clock.c cat > dmain.c << SHAR_EOF_dmain.c /* MDG Multiuser Dungeon Game -- mdg_daemon MDG is Copyright 1990 John C. Gonnerman This program is subject to the general MDG copyright statement (see enclosed file, Copyright). */ static char *sccsx = "@(#) MDG_DAEMON Copyright 1990 John C. Gonnerman"; static char *sccsvers = "@(#) dmain.c\t(1.5)\tcreated 1/4/91"; #include <stdio.h> #include <fcntl.h> #include <signal.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/sem.h> #include "setup.h" #include "files.h" #include "struct.h" #include "messages.h" char *progname; int dqid, pid; time_t mark_time; long max_mps, msg_count; /* flag for debugging */ int in_msgrcv; FILE *saveopen(); extern long dmsgkey, gsemkey, mapkey, playerkey; extern struct player_seg *pseg; extern struct map_seg *mseg; extern int errno; extern char *sys_errlist[]; main(argc, argv) int argc; char **argv; { int i, rc, xx, dfd, tmp; FILE *gfp; void shutdown(); struct dmessage msg_buf; struct msqid_ds qbuf; progname = argv[0]; /* arrange for file creation to be limited. */ umask(0007); if(argc != 1) { fprintf(stderr, ARGCOUNT, progname, argc); exit(1); } fputs(DTITLE, stderr); fputs(DCOPYRIGHT, stderr); fputs(LOADMSG, stderr); if(chdir(GAME_HOME) == -1) { fprintf(stderr, CANTERR, progname, "chdir()", sys_errlist[errno]); exit(1); } if((tmp = creat(LOCKFILE, 0)) == -1) { fprintf(stderr, "%s: daemon lock found, aborting...\n", progname); exit(99); } close(tmp); if((dfd = open(ERRLOGFILE, O_WRONLY|O_CREAT|O_TRUNC, 0660)) == -1) { fprintf(stderr, CANTERR, progname, "open error log", sys_errlist[errno]); exit(1); } close(2); dup(dfd); close(dfd); setbuf(stderr, NULL); close(0); close(1); fputs(LOADMSG, stderr); if((rc = fork()) == -1) { fprintf(stderr, CANTERR, progname, "fork()", sys_errlist[errno]); exit(1); } if(rc != 0) exit(0); setpgrp(); /* load keys from config file */ loadconfig(); /* load the player segment */ if((gfp = saveopen(ITEMS, "r")) == NULL) { fprintf(stderr, CANTERR, progname, "open item file", sys_errlist[errno]); exit(1); } load_pseg(gfp); fclose(gfp); /* load the monster table */ if((gfp = saveopen(MONSTERS, "r")) == NULL) { fprintf(stderr, CANTERR, progname, "open monster file", sys_errlist[errno]); exit(1); } load_monsters(gfp); fclose(gfp); /* load the notes table */ if((gfp = saveopen(NOTES, "r")) == NULL) { fprintf(stderr, CANTERR, progname, "open note file", sys_errlist[errno]); exit(1); } load_notes(gfp); fclose(gfp); /* load the map segment */ if((gfp = saveopen(MAP, "r")) == NULL) { fprintf(stderr, CANTERR, progname, "open map file", sys_errlist[errno]); exit(1); } load_mseg(gfp); fclose(gfp); /* initialize ranged table */ init_ranged(); /* attach the segments. */ seg_attach(); /* create message queues (if needed) and open them */ if((dqid = msgget(dmsgkey, IPC_CREAT | 0666)) == -1) { fprintf(stderr, CANTERR, progname, "open daemon queue", sys_errlist[errno]); exit(1); } msgctl(dqid, IPC_STAT, &qbuf); qbuf.msg_qbytes = DQSIZ; msgctl(dqid, IPC_SET, &qbuf); if((pseg->sid = semget(gsemkey, MAX_PLAYERS, IPC_CREAT|0777)) == -1) { fprintf(stderr, CANTERR, progname, "open game semset", sys_errlist[errno]); exit(1); } /* ready to run, so set signal traps */ signal(SIGTERM, shutdown); signal(SIGHUP, shutdown); /* lower our priority ... */ nice(NICEVAL); /* ... start the monster packet driver ... */ if((pid = fork()) == 0) { if(execl(CLOCKTASK, CLOCKTASK, (char *)0) == -1) { fprintf(stderr, CANTERR, progname, "execl()", sys_errlist[errno]); exit(1); } } else if(pid == -1) { fprintf(stderr, CANTERR, progname, "fork()", sys_errlist[errno]); exit(1); } /* ... seed the random number generator ... */ random(); /* ... and place the stuff. */ place_items(); place_monsters(); /* we got it, let's do it! */ mark_time = time(NULL); max_mps = 0; msg_count = 0; while(1) { in_msgrcv = 1; if((xx = msgrcv(dqid, &msg_buf, DMSGSIZ, 0L, 0)) == DMSGSIZ) { msg_count++; msg_handler(msg_buf); } in_msgrcv = 0; if(mark_time != time(NULL)) { if(msg_count > max_mps) max_mps = msg_count; msg_count = 0; mark_time = time(NULL); } } } int rename(oldname, newname) char *oldname, *newname; { unlink(newname); if(link(oldname, newname) != -1) return unlink(oldname); else return -1; } FILE *saveopen(file, mode) char *file, *mode; { FILE *fp; char savefile[128], altfile[128]; strcpy(savefile, file); strcat(savefile, SAVEEXT); strcpy(altfile, file); if(mode[0] == 'r') { strcat(altfile, STARTEXT); if((fp = fopen(savefile, "r")) == NULL) return fopen(altfile, "r"); else return fp; } else if(mode[0] == 'w') { strcat(altfile, OLDEXT); rename(savefile, altfile); return fopen(savefile, "w"); } } /* end of file */ SHAR_EOF_dmain.c -- Michael michael@stb.info.com denwa!stb!michael anes.ucla.edu!stb!michael "Space is an illusion; disk space doubly so"